Merge "Fix potential overflow in WAV extractor" into oc-dev am: e2b1c22fe8 am: 7bca01a473
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/av/+/12972922
Change-Id: Ic37d52a4ca812a5b4248ea18830177dd03156428
diff --git a/Android.bp b/Android.bp
index b207a96..a3679b1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2,6 +2,5 @@
"camera",
"drm/*",
"media/*",
- "radio",
"soundtrigger",
]
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 5e4d81d..793cbf4 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -78,6 +78,9 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/soundfx/libbundlewrapper.so)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/soundfx/libaudiopreprocessing.so)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libmediacodecservice.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libstagefright_xmlparser@1.0.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libstagefright_soft_*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk/libstagefright_soft_*)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..8f405e9
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,4 @@
+elaurent@google.com
+etalvala@google.com
+lajos@google.com
+marcone@google.com
diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
index 7e6297c..8620f36 100644
--- a/camera/ICameraClient.cpp
+++ b/camera/ICameraClient.cpp
@@ -192,12 +192,14 @@
timestamps.reserve(n);
handles.reserve(n);
for (uint32_t i = 0; i < n; i++) {
- res = data.readInt64(×tamps[i]);
+ nsecs_t t;
+ res = data.readInt64(&t);
if (res != OK) {
ALOGE("%s: Failed to read timestamp[%d]: %s (%d)",
__FUNCTION__, i, strerror(-res), res);
return BAD_VALUE;
}
+ timestamps.push_back(t);
}
for (uint32_t i = 0; i < n; i++) {
native_handle_t* handle = data.readNativeHandle();
diff --git a/camera/ICameraRecordingProxyListener.cpp b/camera/ICameraRecordingProxyListener.cpp
index c954241..66faf8f 100644
--- a/camera/ICameraRecordingProxyListener.cpp
+++ b/camera/ICameraRecordingProxyListener.cpp
@@ -146,12 +146,14 @@
timestamps.reserve(n);
handles.reserve(n);
for (uint32_t i = 0; i < n; i++) {
- res = data.readInt64(×tamps[i]);
+ nsecs_t t;
+ res = data.readInt64(&t);
if (res != OK) {
ALOGE("%s: Failed to read timestamp[%d]: %s (%d)",
__FUNCTION__, i, strerror(-res), res);
return BAD_VALUE;
}
+ timestamps.push_back(t);
}
for (uint32_t i = 0; i < n; i++) {
native_handle_t* handle = data.readNativeHandle();
diff --git a/camera/OWNERS b/camera/OWNERS
new file mode 100644
index 0000000..18acfee
--- /dev/null
+++ b/camera/OWNERS
@@ -0,0 +1,6 @@
+cychen@google.com
+epeev@google.com
+etalvala@google.com
+shuzhenwang@google.com
+yinchiayeh@google.com
+zhijunhe@google.com
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index 8308095..28252c0 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -42,7 +42,9 @@
* Repeating request encountered an error and was stopped.
*
* @param lastFrameNumber Frame number of the last frame of the streaming request.
+ * @param repeatingRequestId the ID of the repeating request being stopped
*/
- oneway void onRepeatingRequestError(in long lastFrameNumber);
+ oneway void onRepeatingRequestError(in long lastFrameNumber,
+ in int repeatingRequestId);
oneway void onRequestQueueEmpty();
}
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 229b159..af977b8 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -941,7 +941,6 @@
ACaptureRequest* request = allocateACaptureRequest(requestSp);
(*onFail)(context, session.get(), request, failure);
freeACaptureRequest(request);
- delete failure;
break;
}
case kWhatCaptureSeqEnd:
@@ -1353,7 +1352,8 @@
}
binder::Status
-CameraDevice::ServiceCallback::onRepeatingRequestError(int64_t lastFrameNumber) {
+CameraDevice::ServiceCallback::onRepeatingRequestError(
+ int64_t lastFrameNumber, int32_t stoppedSequenceId) {
binder::Status ret = binder::Status::ok();
sp<CameraDevice> dev = mDevice.promote();
@@ -1364,7 +1364,9 @@
Mutex::Autolock _l(dev->mDeviceLock);
int repeatingSequenceId = dev->mRepeatingSequenceId;
- dev->mRepeatingSequenceId = REQUEST_ID_NONE;
+ if (stoppedSequenceId == repeatingSequenceId) {
+ dev->mRepeatingSequenceId = REQUEST_ID_NONE;
+ }
dev->checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index c566cd2..855efe1 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -75,7 +75,8 @@
const CaptureResultExtras& resultExtras) override;
binder::Status onPrepared(int streamId) override;
binder::Status onRequestQueueEmpty() override;
- binder::Status onRepeatingRequestError(int64_t lastFrameNumber) override;
+ binder::Status onRepeatingRequestError(int64_t lastFrameNumber,
+ int32_t stoppedSequenceId) override;
private:
const wp<CameraDevice> mDevice;
};
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 946e3b8..51d9214 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -217,8 +217,10 @@
return binder::Status::ok();
}
- virtual binder::Status onRepeatingRequestError(int64_t lastFrameNumber) {
+ virtual binder::Status onRepeatingRequestError(
+ int64_t lastFrameNumber, int32_t stoppedSequenceId) {
(void) lastFrameNumber;
+ (void) stoppedSequenceId;
Mutex::Autolock l(mLock);
mLastStatus = REPEATING_REQUEST_ERROR;
mStatusesHit.push_back(mLastStatus);
diff --git a/cmds/OWNERS b/cmds/OWNERS
new file mode 100644
index 0000000..0d32aac
--- /dev/null
+++ b/cmds/OWNERS
@@ -0,0 +1,3 @@
+elaurent@google.com
+lajos@google.com
+marcone@google.com
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index de0167a..bc32bbe 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -78,7 +78,7 @@
static bool gWantFrameTime = false; // do we want times on each frame?
static uint32_t gVideoWidth = 0; // default width+height
static uint32_t gVideoHeight = 0;
-static uint32_t gBitRate = 4000000; // 4Mbps
+static uint32_t gBitRate = 20000000; // 20Mbps
static uint32_t gTimeLimitSec = kMaxTimeLimitSec;
// Set by signal handler to stop recording.
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index d7c2e87..d70282b 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -870,7 +870,9 @@
sp<IMemory> mem =
retriever->getFrameAtTime(-1,
- MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+ MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
+ HAL_PIXEL_FORMAT_RGB_565,
+ false /*metaOnly*/);
if (mem != NULL) {
failed = false;
diff --git a/drm/OWNERS b/drm/OWNERS
new file mode 100644
index 0000000..e788754
--- /dev/null
+++ b/drm/OWNERS
@@ -0,0 +1 @@
+jtinker@google.com
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 66f5fc2..f906564 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -5,36 +5,31 @@
cc_library_shared {
name: "libmediadrm",
- aidl: {
- local_include_dirs: ["aidl"],
- export_aidl_headers: true,
- },
srcs: [
- "aidl/android/media/ICas.aidl",
- "aidl/android/media/ICasListener.aidl",
- "aidl/android/media/IDescrambler.aidl",
- "aidl/android/media/IMediaCasService.aidl",
-
- "CasImpl.cpp",
- "DescramblerImpl.cpp",
"DrmPluginPath.cpp",
"DrmSessionManager.cpp",
"ICrypto.cpp",
"IDrm.cpp",
"IDrmClient.cpp",
"IMediaDrmService.cpp",
- "MediaCasDefs.cpp",
+ "PluginMetricsReporting.cpp",
"SharedLibrary.cpp",
"DrmHal.cpp",
"CryptoHal.cpp",
+ "protos/plugin_metrics.proto",
],
+ proto: {
+ type: "lite",
+ },
+
shared_libs: [
"libbinder",
"libcutils",
"libdl",
"liblog",
+ "libmediametrics",
"libmediautils",
"libstagefright_foundation",
"libutils",
diff --git a/drm/libmediadrm/CasImpl.cpp b/drm/libmediadrm/CasImpl.cpp
deleted file mode 100644
index 1a33bb0..0000000
--- a/drm/libmediadrm/CasImpl.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-
-/*
- * Copyright (C) 2017 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 "CasImpl"
-
-#include <android/media/ICasListener.h>
-#include <media/cas/CasAPI.h>
-#include <media/CasImpl.h>
-#include <media/SharedLibrary.h>
-#include <utils/Log.h>
-
-namespace android {
-
-static Status getBinderStatus(status_t err) {
- if (err == OK) {
- return Status::ok();
- }
- if (err == BAD_VALUE) {
- return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
- }
- if (err == INVALID_OPERATION) {
- return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
- }
- return Status::fromServiceSpecificError(err);
-}
-
-static String8 sessionIdToString(const CasSessionId &sessionId) {
- String8 result;
- for (size_t i = 0; i < sessionId.size(); i++) {
- result.appendFormat("%02x ", sessionId[i]);
- }
- if (result.isEmpty()) {
- result.append("(null)");
- }
- return result;
-}
-
-struct CasImpl::PluginHolder : public RefBase {
-public:
- explicit PluginHolder(CasPlugin *plugin) : mPlugin(plugin) {}
- ~PluginHolder() { if (mPlugin != NULL) delete mPlugin; }
- CasPlugin* get() { return mPlugin; }
-
-private:
- CasPlugin *mPlugin;
- DISALLOW_EVIL_CONSTRUCTORS(PluginHolder);
-};
-
-CasImpl::CasImpl(const sp<ICasListener> &listener)
- : mPluginHolder(NULL), mListener(listener) {
- ALOGV("CTOR");
-}
-
-CasImpl::~CasImpl() {
- ALOGV("DTOR");
- release();
-}
-
-//static
-void CasImpl::OnEvent(
- void *appData,
- int32_t event,
- int32_t arg,
- uint8_t *data,
- size_t size) {
- if (appData == NULL) {
- ALOGE("Invalid appData!");
- return;
- }
- CasImpl *casImpl = static_cast<CasImpl *>(appData);
- casImpl->onEvent(event, arg, data, size);
-}
-
-void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin *plugin) {
- mLibrary = library;
- mPluginHolder = new PluginHolder(plugin);
-}
-
-void CasImpl::onEvent(
- int32_t event, int32_t arg, uint8_t *data, size_t size) {
- if (mListener == NULL) {
- return;
- }
-
- std::unique_ptr<CasData> eventData;
- if (data != NULL && size > 0) {
- eventData.reset(new CasData(data, data + size));
- }
-
- mListener->onEvent(event, arg, eventData);
-}
-
-Status CasImpl::setPrivateData(const CasData& pvtData) {
- ALOGV("setPrivateData");
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
- return getBinderStatus(INVALID_OPERATION);
- }
- return getBinderStatus(holder->get()->setPrivateData(pvtData));
-}
-
-Status CasImpl::openSession(CasSessionId* sessionId) {
- ALOGV("openSession");
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
- return getBinderStatus(INVALID_OPERATION);
- }
- status_t err = holder->get()->openSession(sessionId);
-
- ALOGV("openSession: session opened, sessionId=%s",
- sessionIdToString(*sessionId).string());
-
- return getBinderStatus(err);
-}
-
-Status CasImpl::setSessionPrivateData(
- const CasSessionId &sessionId, const CasData& pvtData) {
- ALOGV("setSessionPrivateData: sessionId=%s",
- sessionIdToString(sessionId).string());
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
- return getBinderStatus(INVALID_OPERATION);
- }
- return getBinderStatus(holder->get()->setSessionPrivateData(sessionId, pvtData));
-}
-
-Status CasImpl::closeSession(const CasSessionId &sessionId) {
- ALOGV("closeSession: sessionId=%s",
- sessionIdToString(sessionId).string());
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
- return getBinderStatus(INVALID_OPERATION);
- }
- return getBinderStatus(holder->get()->closeSession(sessionId));
-}
-
-Status CasImpl::processEcm(const CasSessionId &sessionId, const ParcelableCasData& ecm) {
- ALOGV("processEcm: sessionId=%s",
- sessionIdToString(sessionId).string());
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
- return getBinderStatus(INVALID_OPERATION);
- }
-
- return getBinderStatus(holder->get()->processEcm(sessionId, ecm));
-}
-
-Status CasImpl::processEmm(const ParcelableCasData& emm) {
- ALOGV("processEmm");
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
- return getBinderStatus(INVALID_OPERATION);
- }
-
- return getBinderStatus(holder->get()->processEmm(emm));
-}
-
-Status CasImpl::sendEvent(
- int32_t event, int32_t arg, const ::std::unique_ptr<CasData> &eventData) {
- ALOGV("sendEvent");
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
- return getBinderStatus(INVALID_OPERATION);
- }
-
- status_t err;
- if (eventData == nullptr) {
- err = holder->get()->sendEvent(event, arg, CasData());
- } else {
- err = holder->get()->sendEvent(event, arg, *eventData);
- }
- return getBinderStatus(err);
-}
-
-Status CasImpl::provision(const String16& provisionString) {
- ALOGV("provision: provisionString=%s", String8(provisionString).string());
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
- return getBinderStatus(INVALID_OPERATION);
- }
-
- return getBinderStatus(holder->get()->provision(String8(provisionString)));
-}
-
-Status CasImpl::refreshEntitlements(
- int32_t refreshType, const ::std::unique_ptr<CasData> &refreshData) {
- ALOGV("refreshEntitlements");
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
- return getBinderStatus(INVALID_OPERATION);
- }
-
- status_t err;
- if (refreshData == nullptr) {
- err = holder->get()->refreshEntitlements(refreshType, CasData());
- } else {
- err = holder->get()->refreshEntitlements(refreshType, *refreshData);
- }
- return getBinderStatus(err);
-}
-
-Status CasImpl::release() {
- ALOGV("release: plugin=%p",
- mPluginHolder == NULL ? mPluginHolder->get() : NULL);
- mPluginHolder.clear();
- return Status::ok();
-}
-
-} // namespace android
-
diff --git a/drm/libmediadrm/DescramblerImpl.cpp b/drm/libmediadrm/DescramblerImpl.cpp
deleted file mode 100644
index 5764669..0000000
--- a/drm/libmediadrm/DescramblerImpl.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-
-/*
- * Copyright (C) 2017 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 "DescramblerImpl"
-
-#include <media/cas/DescramblerAPI.h>
-#include <media/DescramblerImpl.h>
-#include <media/SharedLibrary.h>
-#include <media/stagefright/foundation/AUtils.h>
-#include <binder/IMemory.h>
-#include <utils/Log.h>
-
-namespace android {
-
-static Status getBinderStatus(status_t err) {
- if (err == OK) {
- return Status::ok();
- }
- if (err == BAD_VALUE) {
- return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
- }
- if (err == INVALID_OPERATION) {
- return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
- }
- return Status::fromServiceSpecificError(err);
-}
-
-static String8 sessionIdToString(const CasSessionId &sessionId) {
- String8 result;
- for (size_t i = 0; i < sessionId.size(); i++) {
- result.appendFormat("%02x ", sessionId[i]);
- }
- if (result.isEmpty()) {
- result.append("(null)");
- }
- return result;
-}
-
-DescramblerImpl::DescramblerImpl(
- const sp<SharedLibrary>& library, DescramblerPlugin *plugin) :
- mLibrary(library), mPlugin(plugin) {
- ALOGV("CTOR: mPlugin=%p", mPlugin);
-}
-
-DescramblerImpl::~DescramblerImpl() {
- ALOGV("DTOR: mPlugin=%p", mPlugin);
- release();
-}
-
-Status DescramblerImpl::setMediaCasSession(const CasSessionId& sessionId) {
- ALOGV("setMediaCasSession: sessionId=%s",
- sessionIdToString(sessionId).string());
-
- return getBinderStatus(mPlugin->setMediaCasSession(sessionId));
-}
-
-Status DescramblerImpl::requiresSecureDecoderComponent(
- const String16& mime, bool *result) {
- *result = mPlugin->requiresSecureDecoderComponent(String8(mime));
-
- return getBinderStatus(OK);
-}
-
-static inline bool validateRangeForSize(
- uint64_t offset, uint64_t length, uint64_t size) {
- return isInRange<uint64_t, uint64_t>(0, size, offset, length);
-}
-
-Status DescramblerImpl::descramble(
- const DescrambleInfo& info, int32_t *result) {
- ALOGV("descramble");
-
- if (info.srcMem == NULL || info.srcMem->pointer() == NULL) {
- ALOGE("srcMem is invalid");
- return getBinderStatus(BAD_VALUE);
- }
-
- // use 64-bit here to catch bad subsample size that might be overflowing.
- uint64_t totalBytesInSubSamples = 0;
- for (size_t i = 0; i < info.numSubSamples; i++) {
- totalBytesInSubSamples += (uint64_t)info.subSamples[i].mNumBytesOfClearData +
- info.subSamples[i].mNumBytesOfEncryptedData;
- }
- // validate if the specified srcOffset and requested total subsample size
- // is consistent with the source shared buffer size.
- if (!validateRangeForSize(info.srcOffset, totalBytesInSubSamples, info.srcMem->size())) {
- ALOGE("Invalid srcOffset and subsample size: "
- "srcOffset %llu, totalBytesInSubSamples %llu, srcMem size %llu",
- (unsigned long long) info.srcOffset,
- (unsigned long long) totalBytesInSubSamples,
- (unsigned long long) info.srcMem->size());
- android_errorWriteLog(0x534e4554, "67962232");
- return getBinderStatus(BAD_VALUE);
- }
- void *dstPtr = NULL;
- if (info.dstType == DescrambleInfo::kDestinationTypeVmPointer) {
- // When using shared memory, src buffer is also used as dst
- dstPtr = info.srcMem->pointer();
-
- // In this case the dst and src would be the same buffer, need to validate
- // dstOffset against the buffer size too.
- if (!validateRangeForSize(info.dstOffset, totalBytesInSubSamples, info.srcMem->size())) {
- ALOGE("Invalid dstOffset and subsample size: "
- "dstOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu",
- (unsigned long long) info.dstOffset,
- (unsigned long long) totalBytesInSubSamples,
- (unsigned long long) info.srcMem->size());
- android_errorWriteLog(0x534e4554, "67962232");
- return getBinderStatus(BAD_VALUE);
- }
- } else {
- dstPtr = info.dstPtr;
- }
-
- *result = mPlugin->descramble(
- info.dstType != DescrambleInfo::kDestinationTypeVmPointer,
- info.scramblingControl,
- info.numSubSamples,
- info.subSamples,
- info.srcMem->pointer(),
- info.srcOffset,
- dstPtr,
- info.dstOffset,
- NULL);
-
- return getBinderStatus(*result >= 0 ? OK : *result);
-}
-
-Status DescramblerImpl::release() {
- ALOGV("release: mPlugin=%p", mPlugin);
-
- if (mPlugin != NULL) {
- delete mPlugin;
- mPlugin = NULL;
- }
- return Status::ok();
-}
-
-} // namespace android
-
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 074489a..bc37557 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -30,6 +30,7 @@
#include <media/DrmHal.h>
#include <media/DrmSessionClientInterface.h>
#include <media/DrmSessionManager.h>
+#include <media/PluginMetricsReporting.h>
#include <media/drm/DrmAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
@@ -194,7 +195,18 @@
mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {
}
+void DrmHal::closeOpenSessions() {
+ if (mPlugin != NULL) {
+ for (size_t i = 0; i < mOpenSessions.size(); i++) {
+ mPlugin->closeSession(toHidlVec(mOpenSessions[i]));
+ DrmSessionManager::Instance()->removeSession(mOpenSessions[i]);
+ }
+ }
+ mOpenSessions.clear();
+}
+
DrmHal::~DrmHal() {
+ closeOpenSessions();
DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
}
@@ -413,11 +425,12 @@
status_t DrmHal::destroyPlugin() {
Mutex::Autolock autoLock(mLock);
-
if (mInitCheck != OK) {
return mInitCheck;
}
+ closeOpenSessions();
+ reportMetrics();
setListener(NULL);
mInitCheck = NO_INIT;
@@ -471,6 +484,7 @@
if (err == OK) {
DrmSessionManager::Instance()->addSession(getCallingPid(),
mDrmSessionClient, sessionId);
+ mOpenSessions.push(sessionId);
}
return err;
}
@@ -486,7 +500,14 @@
if (status.isOk()) {
if (status == Status::OK) {
DrmSessionManager::Instance()->removeSession(sessionId);
+ for (size_t i = 0; i < mOpenSessions.size(); i++) {
+ if (mOpenSessions[i] == sessionId) {
+ mOpenSessions.removeAt(i);
+ break;
+ }
+ }
}
+ reportMetrics();
return toStatusT(status);
}
return DEAD_OBJECT;
@@ -740,6 +761,12 @@
status_t DrmHal::getPropertyString(String8 const &name, String8 &value ) const {
Mutex::Autolock autoLock(mLock);
+ return getPropertyStringInternal(name, value);
+}
+
+status_t DrmHal::getPropertyStringInternal(String8 const &name, String8 &value) const {
+ // This function is internal to the class and should only be called while
+ // mLock is already held.
if (mInitCheck != OK) {
return mInitCheck;
@@ -761,6 +788,12 @@
status_t DrmHal::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
Mutex::Autolock autoLock(mLock);
+ return getPropertyByteArrayInternal(name, value);
+}
+
+status_t DrmHal::getPropertyByteArrayInternal(String8 const &name, Vector<uint8_t> &value ) const {
+ // This function is internal to the class and should only be called while
+ // mLock is already held.
if (mInitCheck != OK) {
return mInitCheck;
@@ -975,7 +1008,7 @@
void DrmHal::binderDied(const wp<IBinder> &the_late_who __unused)
{
Mutex::Autolock autoLock(mLock);
-
+ closeOpenSessions();
setListener(NULL);
mInitCheck = NO_INIT;
@@ -997,4 +1030,20 @@
}
}
+void DrmHal::reportMetrics() const
+{
+ Vector<uint8_t> metrics;
+ String8 vendor;
+ String8 description;
+ if (getPropertyStringInternal(String8("vendor"), vendor) == OK &&
+ getPropertyStringInternal(String8("description"), description) == OK &&
+ getPropertyByteArrayInternal(String8("metrics"), metrics) == OK) {
+ status_t res = android::reportDrmPluginMetrics(
+ metrics, vendor, description);
+ if (res != OK) {
+ ALOGE("Metrics were retrieved but could not be reported: %i", res);
+ }
+ }
+}
+
} // namespace android
diff --git a/drm/libmediadrm/MediaCasDefs.cpp b/drm/libmediadrm/MediaCasDefs.cpp
deleted file mode 100644
index 9c2ba38..0000000
--- a/drm/libmediadrm/MediaCasDefs.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2017 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 "MediaCas"
-
-#include <media/MediaCasDefs.h>
-#include <utils/Log.h>
-#include <binder/IMemory.h>
-
-namespace android {
-namespace media {
-
-///////////////////////////////////////////////////////////////////////////////
-namespace MediaCas {
-
-status_t ParcelableCasData::readFromParcel(const Parcel* parcel) {
- return parcel->readByteVector(this);
-}
-
-status_t ParcelableCasData::writeToParcel(Parcel* parcel) const {
- return parcel->writeByteVector(*this);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-status_t ParcelableCasPluginDescriptor::readFromParcel(const Parcel* /*parcel*/) {
- ALOGE("CAPluginDescriptor::readFromParcel() shouldn't be called");
- return INVALID_OPERATION;
-}
-
-status_t ParcelableCasPluginDescriptor::writeToParcel(Parcel* parcel) const {
- status_t err = parcel->writeInt32(mCASystemId);
- if (err != NO_ERROR) {
- return err;
- }
- return parcel->writeString16(mName);
-}
-
-} // namespace MediaCas
-///////////////////////////////////////////////////////////////////////////////
-
-namespace MediaDescrambler {
-
-DescrambleInfo::DescrambleInfo() {}
-
-DescrambleInfo::~DescrambleInfo() {}
-
-status_t DescrambleInfo::readFromParcel(const Parcel* parcel) {
- status_t err = parcel->readInt32((int32_t*)&dstType);
- if (err != OK) {
- return err;
- }
- if (dstType != kDestinationTypeNativeHandle
- && dstType != kDestinationTypeVmPointer) {
- return BAD_VALUE;
- }
-
- err = parcel->readInt32((int32_t*)&scramblingControl);
- if (err != OK) {
- return err;
- }
-
- err = parcel->readUint32((uint32_t*)&numSubSamples);
- if (err != OK) {
- return err;
- }
- if (numSubSamples > 0xffff) {
- return BAD_VALUE;
- }
-
- subSamples = new DescramblerPlugin::SubSample[numSubSamples];
- if (subSamples == NULL) {
- return NO_MEMORY;
- }
-
- for (size_t i = 0; i < numSubSamples; i++) {
- err = parcel->readUint32(&subSamples[i].mNumBytesOfClearData);
- if (err != OK) {
- return err;
- }
- err = parcel->readUint32(&subSamples[i].mNumBytesOfEncryptedData);
- if (err != OK) {
- return err;
- }
- }
-
- srcMem = interface_cast<IMemory>(parcel->readStrongBinder());
- if (srcMem == NULL) {
- return BAD_VALUE;
- }
-
- err = parcel->readInt32(&srcOffset);
- if (err != OK) {
- return err;
- }
-
- native_handle_t *nativeHandle = NULL;
- if (dstType == kDestinationTypeNativeHandle) {
- nativeHandle = parcel->readNativeHandle();
- dstPtr = static_cast<void *>(nativeHandle);
- } else {
- dstPtr = NULL;
- }
-
- err = parcel->readInt32(&dstOffset);
- if (err != OK) {
- return err;
- }
-
- return OK;
-}
-
-status_t DescrambleInfo::writeToParcel(Parcel* parcel) const {
- if (dstType != kDestinationTypeNativeHandle
- && dstType != kDestinationTypeVmPointer) {
- return BAD_VALUE;
- }
-
- status_t err = parcel->writeInt32((int32_t)dstType);
- if (err != OK) {
- return err;
- }
-
- err = parcel->writeInt32(scramblingControl);
- if (err != OK) {
- return err;
- }
-
- err = parcel->writeUint32(numSubSamples);
- if (err != OK) {
- return err;
- }
-
- for (size_t i = 0; i < numSubSamples; i++) {
- err = parcel->writeUint32(subSamples[i].mNumBytesOfClearData);
- if (err != OK) {
- return err;
- }
- err = parcel->writeUint32(subSamples[i].mNumBytesOfEncryptedData);
- if (err != OK) {
- return err;
- }
- }
-
- err = parcel->writeStrongBinder(IInterface::asBinder(srcMem));
- if (err != OK) {
- return err;
- }
-
- err = parcel->writeInt32(srcOffset);
- if (err != OK) {
- return err;
- }
-
- if (dstType == kDestinationTypeNativeHandle) {
- parcel->writeNativeHandle(static_cast<native_handle_t *>(dstPtr));
- }
-
- err = parcel->writeInt32(dstOffset);
- if (err != OK) {
- return err;
- }
-
- return OK;
-}
-
-} // namespace MediaDescrambler
-
-} // namespace media
-} // namespace android
-
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
new file mode 100644
index 0000000..57ff5b8
--- /dev/null
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 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 "PluginMetricsReporting"
+#include <utils/Log.h>
+
+#include <media/PluginMetricsReporting.h>
+
+#include <media/MediaAnalyticsItem.h>
+
+#include "protos/plugin_metrics.pb.h"
+
+namespace android {
+
+namespace {
+
+using android::drm_metrics::MetricsGroup;
+using android::drm_metrics::MetricsGroup_Metric;
+using android::drm_metrics::MetricsGroup_Metric_MetricValue;
+
+const char* const kParentAttribute = "/parent/external";
+
+status_t reportMetricsGroup(const MetricsGroup& metricsGroup,
+ const String8& batchName,
+ const int64_t* parentId) {
+ MediaAnalyticsItem analyticsItem(batchName.c_str());
+ analyticsItem.generateSessionID();
+ int64_t sessionId = analyticsItem.getSessionID();
+ if (parentId != NULL) {
+ analyticsItem.setInt64(kParentAttribute, *parentId);
+ }
+
+ // Report the package name.
+ if (metricsGroup.has_app_package_name()) {
+ AString app_package_name(metricsGroup.app_package_name().c_str(),
+ metricsGroup.app_package_name().size());
+ analyticsItem.setPkgName(app_package_name);
+ }
+
+ for (int i = 0; i < metricsGroup.metric_size(); ++i) {
+ const MetricsGroup_Metric& metric = metricsGroup.metric(i);
+ if (!metric.has_name()) {
+ ALOGE("Metric with no name.");
+ return BAD_VALUE;
+ }
+
+ if (!metric.has_value()) {
+ ALOGE("Metric with no value.");
+ return BAD_VALUE;
+ }
+
+ const MetricsGroup_Metric_MetricValue& value = metric.value();
+ if (value.has_int_value()) {
+ analyticsItem.setInt64(metric.name().c_str(),
+ value.int_value());
+ } else if (value.has_double_value()) {
+ analyticsItem.setDouble(metric.name().c_str(),
+ value.double_value());
+ } else if (value.has_string_value()) {
+ analyticsItem.setCString(metric.name().c_str(),
+ value.string_value().c_str());
+ } else {
+ ALOGE("Metric Value with no actual value.");
+ return BAD_VALUE;
+ }
+ }
+
+ analyticsItem.setFinalized(true);
+ if (!analyticsItem.selfrecord()) {
+ // Note the cast to int is because we build on 32 and 64 bit.
+ // The cast prevents a peculiar printf problem where one format cannot
+ // satisfy both.
+ ALOGE("selfrecord() returned false. sessioId %d", (int) sessionId);
+ }
+
+ for (int i = 0; i < metricsGroup.metric_sub_group_size(); ++i) {
+ const MetricsGroup& subGroup = metricsGroup.metric_sub_group(i);
+ status_t res = reportMetricsGroup(subGroup, batchName, &sessionId);
+ if (res != OK) {
+ return res;
+ }
+ }
+
+ return OK;
+}
+
+String8 sanitize(const String8& input) {
+ // Filters the input string down to just alphanumeric characters.
+ String8 output;
+ for (size_t i = 0; i < input.size(); ++i) {
+ char candidate = input[i];
+ if ((candidate >= 'a' && candidate <= 'z') ||
+ (candidate >= 'A' && candidate <= 'Z') ||
+ (candidate >= '0' && candidate <= '9')) {
+ output.append(&candidate, 1);
+ }
+ }
+ return output;
+}
+
+} // namespace
+
+status_t reportDrmPluginMetrics(const Vector<uint8_t>& serializedMetrics,
+ const String8& vendor,
+ const String8& description) {
+ MetricsGroup root_metrics_group;
+ if (!root_metrics_group.ParseFromArray(serializedMetrics.array(),
+ serializedMetrics.size())) {
+ ALOGE("Failure to parse.");
+ return BAD_VALUE;
+ }
+
+ String8 name = String8::format("drm.vendor.%s.%s",
+ sanitize(vendor).c_str(),
+ sanitize(description).c_str());
+
+ return reportMetricsGroup(root_metrics_group, name, NULL);
+}
+
+} // namespace android
diff --git a/drm/libmediadrm/aidl/android/media/ICas.aidl b/drm/libmediadrm/aidl/android/media/ICas.aidl
deleted file mode 100644
index 9746593..0000000
--- a/drm/libmediadrm/aidl/android/media/ICas.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-import android.media.MediaCas;
-
-/** @hide */
-interface ICas {
- void setPrivateData(in byte[] pvtData);
- byte[] openSession();
- void closeSession(in byte[] sessionId);
- void setSessionPrivateData(in byte[] sessionId, in byte[] pvtData);
- void processEcm(in byte[] sessionId, in MediaCas.ParcelableCasData ecm);
- void processEmm(in MediaCas.ParcelableCasData emm);
- void sendEvent(int event, int arg, in @nullable byte[] eventData);
- void provision(String provisionString);
- void refreshEntitlements(int refreshType, in @nullable byte[] refreshData);
- void release();
-}
\ No newline at end of file
diff --git a/drm/libmediadrm/aidl/android/media/ICasListener.aidl b/drm/libmediadrm/aidl/android/media/ICasListener.aidl
deleted file mode 100644
index 01a5abc..0000000
--- a/drm/libmediadrm/aidl/android/media/ICasListener.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-/** @hide */
-interface ICasListener {
- void onEvent(int event, int arg, in @nullable byte[] data);
-}
\ No newline at end of file
diff --git a/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl b/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl
deleted file mode 100644
index 44f6825..0000000
--- a/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-import android.media.IDescrambler;
-import android.media.ICas;
-import android.media.ICasListener;
-import android.media.MediaCas;
-
-/** @hide */
-interface IMediaCasService {
- MediaCas.ParcelableCasPluginDescriptor[] enumeratePlugins();
- boolean isSystemIdSupported(int CA_system_id);
- ICas createPlugin(int CA_system_id, ICasListener listener);
- boolean isDescramblerSupported(int CA_system_id);
- IDescrambler createDescrambler(int CA_system_id);
-}
-
diff --git a/drm/libmediadrm/aidl/android/media/MediaCas.aidl b/drm/libmediadrm/aidl/android/media/MediaCas.aidl
deleted file mode 100644
index cb8d0c6..0000000
--- a/drm/libmediadrm/aidl/android/media/MediaCas.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-/** @hide */
-parcelable MediaCas.ParcelableCasPluginDescriptor cpp_header "media/MediaCasDefs.h";
-
-/** @hide */
-parcelable MediaCas.ParcelableCasData cpp_header "media/MediaCasDefs.h";
\ No newline at end of file
diff --git a/drm/libmediadrm/protos/plugin_metrics.proto b/drm/libmediadrm/protos/plugin_metrics.proto
new file mode 100644
index 0000000..7e3bcf5
--- /dev/null
+++ b/drm/libmediadrm/protos/plugin_metrics.proto
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto2";
+
+package android.drm_metrics;
+
+// need this if we are using libprotobuf-cpp-2.3.0-lite
+option optimize_for = LITE_RUNTIME;
+
+// The MetricsGroup is a collection of metric name/value pair instances
+// that can be serialized and provided to a caller.
+message MetricsGroup {
+ message Metric {
+ message MetricValue {
+ // Exactly one of the following values must be set.
+ optional int64 int_value = 1;
+ optional double double_value = 2;
+ optional string string_value = 3;
+ }
+
+ // The name of the metric. Must be valid UTF-8. Required.
+ optional string name = 1;
+
+ // The value of the metric. Required.
+ optional MetricValue value = 2;
+ }
+
+ // The list of name/value pairs of metrics.
+ repeated Metric metric = 1;
+
+ // Allow multiple sub groups of metrics.
+ repeated MetricsGroup metric_sub_group = 2;
+
+ // Name of the application package associated with the metrics.
+ optional string app_package_name = 3;
+}
diff --git a/drm/mediacas/plugins/clearkey/Android.mk b/drm/mediacas/plugins/clearkey/Android.mk
index 8fd866c..4b139a8 100644
--- a/drm/mediacas/plugins/clearkey/Android.mk
+++ b/drm/mediacas/plugins/clearkey/Android.mk
@@ -28,8 +28,7 @@
LOCAL_MODULE := libclearkeycasplugin
-#TODO: move this back to /vendor/lib after conversion to treble
-#LOCAL_PROPRIETARY_MODULE := true
+LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := mediacas
LOCAL_SHARED_LIBRARIES := \
@@ -39,6 +38,9 @@
libstagefright_foundation \
libprotobuf-cpp-lite \
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers
+
LOCAL_STATIC_LIBRARIES := \
libjsmn \
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
index 7572194..50acc1d 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
@@ -121,7 +121,7 @@
std::shared_ptr<ClearKeyCasSession> session =
ClearKeySessionLibrary::get()->findSession(sessionId);
if (session.get() == nullptr) {
- return ERROR_DRM_SESSION_NOT_OPENED;
+ return ERROR_CAS_SESSION_NOT_OPENED;
}
ClearKeySessionLibrary::get()->destroySession(sessionId);
@@ -135,7 +135,7 @@
std::shared_ptr<ClearKeyCasSession> session =
ClearKeySessionLibrary::get()->findSession(sessionId);
if (session.get() == nullptr) {
- return ERROR_DRM_SESSION_NOT_OPENED;
+ return ERROR_CAS_SESSION_NOT_OPENED;
}
return OK;
}
@@ -146,7 +146,7 @@
std::shared_ptr<ClearKeyCasSession> session =
ClearKeySessionLibrary::get()->findSession(sessionId);
if (session.get() == nullptr) {
- return ERROR_DRM_SESSION_NOT_OPENED;
+ return ERROR_CAS_SESSION_NOT_OPENED;
}
Mutex::Autolock lock(mKeyFetcherLock);
@@ -293,7 +293,7 @@
status_t ClearKeyCasSession::updateECM(
KeyFetcher *keyFetcher, void *ecm, size_t size) {
if (keyFetcher == nullptr) {
- return ERROR_DRM_NOT_PROVISIONED;
+ return ERROR_CAS_NOT_PROVISIONED;
}
if (size < kEcmHeaderLength) {
@@ -344,7 +344,7 @@
size_t numSubSamples, const DescramblerPlugin::SubSample *subSamples,
const void *srcPtr, void *dstPtr, AString * /* errorDetailMsg */) {
if (secure) {
- return ERROR_DRM_CANNOT_HANDLE;
+ return ERROR_CAS_CANNOT_HANDLE;
}
AES_KEY contentKey;
@@ -356,7 +356,7 @@
int32_t keyIndex = (scramblingControl & 1);
if (!mKeyInfo[keyIndex].valid) {
ALOGE("decrypt: key %d is invalid", keyIndex);
- return ERROR_DRM_DECRYPT;
+ return ERROR_CAS_DECRYPT;
}
contentKey = mKeyInfo[keyIndex].contentKey;
}
@@ -420,7 +420,7 @@
if (session.get() == nullptr) {
ALOGE("ClearKeyDescramblerPlugin: session not found");
- return ERROR_DRM_SESSION_NOT_OPENED;
+ return ERROR_CAS_SESSION_NOT_OPENED;
}
std::atomic_store(&mCASSession, session);
@@ -448,7 +448,7 @@
if (session.get() == nullptr) {
ALOGE("Uninitialized CAS session!");
- return ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED;
+ return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
}
return session->decrypt(
diff --git a/drm/mediacas/plugins/clearkey/JsonAssetLoader.cpp b/drm/mediacas/plugins/clearkey/JsonAssetLoader.cpp
index 9cd77e9..6e1004c 100644
--- a/drm/mediacas/plugins/clearkey/JsonAssetLoader.cpp
+++ b/drm/mediacas/plugins/clearkey/JsonAssetLoader.cpp
@@ -48,24 +48,24 @@
* Extract a clear key asset from a JSON string.
*
* Returns OK if a clear key asset is extracted successfully,
- * or ERROR_DRM_NO_LICENSE if the string doesn't contain a valid
+ * or ERROR_CAS_NO_LICENSE if the string doesn't contain a valid
* clear key asset.
*/
status_t JsonAssetLoader::extractAssetFromString(
const String8& jsonAssetString, Asset *asset) {
if (!parseJsonAssetString(jsonAssetString, &mJsonObjects)) {
- return ERROR_DRM_NO_LICENSE;
+ return ERROR_CAS_NO_LICENSE;
}
if (mJsonObjects.size() < 1) {
- return ERROR_DRM_NO_LICENSE;
+ return ERROR_CAS_NO_LICENSE;
}
if (!parseJsonObject(mJsonObjects[0], &mTokens))
- return ERROR_DRM_NO_LICENSE;
+ return ERROR_CAS_NO_LICENSE;
if (!findKey(mJsonObjects[0], asset)) {
- return ERROR_DRM_NO_LICENSE;
+ return ERROR_CAS_NO_LICENSE;
}
return OK;
}
diff --git a/drm/mediacas/plugins/clearkey/ecm_generator.h b/drm/mediacas/plugins/clearkey/ecm_generator.h
index 2ef06c4..5fbdea5 100644
--- a/drm/mediacas/plugins/clearkey/ecm_generator.h
+++ b/drm/mediacas/plugins/clearkey/ecm_generator.h
@@ -29,7 +29,7 @@
namespace android {
namespace clearkeycas {
enum {
- CLEARKEY_STATUS_BASE = ERROR_DRM_VENDOR_MAX,
+ CLEARKEY_STATUS_BASE = ERROR_CAS_VENDOR_MAX,
CLEARKEY_STATUS_INVALIDASSETID = CLEARKEY_STATUS_BASE - 1,
CLEARKEY_STATUS_INVALIDSYSTEMID = CLEARKEY_STATUS_BASE - 2,
CLEARKEY_STATUS_INVALID_PARAMETER = CLEARKEY_STATUS_BASE - 3,
diff --git a/drm/mediacas/plugins/clearkey/tests/Android.mk b/drm/mediacas/plugins/clearkey/tests/Android.mk
index cbf7be7..e1545af 100644
--- a/drm/mediacas/plugins/clearkey/tests/Android.mk
+++ b/drm/mediacas/plugins/clearkey/tests/Android.mk
@@ -21,12 +21,13 @@
ClearKeyFetcherTest.cpp
LOCAL_MODULE := ClearKeyFetcherTest
+LOCAL_VENDOR_MODULE := true
# LOCAL_LDFLAGS is needed here for the test to use the plugin, because
# the plugin is not in standard library search path. Without this .so
# loading fails at run-time (linking is okay).
LOCAL_LDFLAGS := \
- -Wl,--rpath,\$${ORIGIN}/../../../system/lib/mediacas -Wl,--enable-new-dtags
+ -Wl,--rpath,\$${ORIGIN}/../../../system/vendor/lib/mediacas -Wl,--enable-new-dtags
LOCAL_SHARED_LIBRARIES := \
libutils libclearkeycasplugin libstagefright_foundation libprotobuf-cpp-lite liblog
diff --git a/drm/mediacas/plugins/mock/Android.mk b/drm/mediacas/plugins/mock/Android.mk
index a97fac6..a1d61da 100644
--- a/drm/mediacas/plugins/mock/Android.mk
+++ b/drm/mediacas/plugins/mock/Android.mk
@@ -28,6 +28,8 @@
LOCAL_SHARED_LIBRARIES := \
libutils liblog
+LOCAL_HEADER_LIBRARIES := media_plugin_headers
+
LOCAL_C_INCLUDES += \
$(TOP)/frameworks/av/include \
$(TOP)/frameworks/native/include/media \
diff --git a/drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp b/drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp
index ed050f7..0259a42 100644
--- a/drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp
+++ b/drm/mediadrm/plugins/clearkey/ClearKeyUUID.cpp
@@ -21,12 +21,19 @@
namespace clearkeydrm {
bool isClearKeyUUID(const uint8_t uuid[16]) {
- static const uint8_t kClearKeyUUID[16] = {
+ static const uint8_t kCommonPsshBoxUUID[16] = {
0x10,0x77,0xEF,0xEC,0xC0,0xB2,0x4D,0x02,
0xAC,0xE3,0x3C,0x1E,0x52,0xE2,0xFB,0x4B
};
- return !memcmp(uuid, kClearKeyUUID, sizeof(kClearKeyUUID));
+ // To be used in mpd to specify drm scheme for players
+ static const uint8_t kClearKeyUUID[16] = {
+ 0xE2,0x71,0x9D,0x58,0xA9,0x85,0xB3,0xC9,
+ 0x78,0x1A,0xB0,0x30,0xAF,0x78,0xD3,0x0E
+ };
+
+ return !memcmp(uuid, kCommonPsshBoxUUID, sizeof(kCommonPsshBoxUUID)) ||
+ !memcmp(uuid, kClearKeyUUID, sizeof(kClearKeyUUID));
}
} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
index 5fdac5c..ec07d87 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
@@ -25,10 +25,28 @@
#include "Session.h"
+namespace {
+const android::String8 kStreaming("Streaming");
+const android::String8 kOffline("Offline");
+const android::String8 kTrue("True");
+
+const android::String8 kQueryKeyLicenseType("LicenseType");
+ // Value: "Streaming" or "Offline"
+const android::String8 kQueryKeyPlayAllowed("PlayAllowed");
+ // Value: "True" or "False"
+const android::String8 kQueryKeyRenewAllowed("RenewAllowed");
+ // Value: "True" or "False"
+};
+
namespace clearkeydrm {
using android::sp;
+DrmPlugin::DrmPlugin(SessionLibrary* sessionLibrary)
+ : mSessionLibrary(sessionLibrary) {
+ mPlayPolicy.clear();
+}
+
status_t DrmPlugin::openSession(Vector<uint8_t>& sessionId) {
sp<Session> session = mSessionLibrary->createSession();
sessionId = session->sessionId();
@@ -60,18 +78,28 @@
if (scope.size() == 0) {
return android::BAD_VALUE;
}
+
if (keyType != kKeyType_Streaming) {
return android::ERROR_DRM_CANNOT_HANDLE;
}
+
*keyRequestType = DrmPlugin::kKeyRequestType_Initial;
defaultUrl.clear();
sp<Session> session = mSessionLibrary->findSession(scope);
if (!session.get()) {
return android::ERROR_DRM_SESSION_NOT_OPENED;
}
+
return session->getKeyRequest(initData, mimeType, &request);
}
+void DrmPlugin::setPlayPolicy() {
+ mPlayPolicy.clear();
+ mPlayPolicy.add(kQueryKeyLicenseType, kStreaming);
+ mPlayPolicy.add(kQueryKeyPlayAllowed, kTrue);
+ mPlayPolicy.add(kQueryKeyRenewAllowed, kTrue);
+}
+
status_t DrmPlugin::provideKeyResponse(
const Vector<uint8_t>& scope,
const Vector<uint8_t>& response,
@@ -83,6 +111,8 @@
if (!session.get()) {
return android::ERROR_DRM_SESSION_NOT_OPENED;
}
+
+ setPlayPolicy();
status_t res = session->provideKeyResponse(response);
if (res == android::OK) {
// This is for testing AMediaDrm_setOnEventListener only.
@@ -111,4 +141,18 @@
return android::OK;
}
+status_t DrmPlugin::queryKeyStatus(
+ const Vector<uint8_t>& sessionId,
+ KeyedVector<String8, String8>& infoMap) const {
+
+ if (sessionId.size() == 0) {
+ return android::BAD_VALUE;
+ }
+
+ infoMap.clear();
+ for (size_t i = 0; i < mPlayPolicy.size(); ++i) {
+ infoMap.add(mPlayPolicy.keyAt(i), mPlayPolicy.valueAt(i));
+ }
+ return android::OK;
+}
} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index 58421b9..f37a706 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -39,8 +39,8 @@
class DrmPlugin : public android::DrmPlugin {
public:
- explicit DrmPlugin(SessionLibrary* sessionLibrary)
- : mSessionLibrary(sessionLibrary) {}
+ explicit DrmPlugin(SessionLibrary* sessionLibrary);
+
virtual ~DrmPlugin() {}
virtual status_t openSession(Vector<uint8_t>& sessionId);
@@ -81,13 +81,7 @@
virtual status_t queryKeyStatus(
const Vector<uint8_t>& sessionId,
- KeyedVector<String8, String8>& infoMap) const {
- if (sessionId.size() == 0) {
- return android::BAD_VALUE;
- }
- UNUSED(infoMap);
- return android::ERROR_DRM_CANNOT_HANDLE;
- }
+ KeyedVector<String8, String8>& infoMap) const;
virtual status_t getProvisionRequest(
const String8& cert_type,
@@ -248,9 +242,12 @@
}
private:
- DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin);
+ void setPlayPolicy();
+ android::KeyedVector<android::String8, android::String8> mPlayPolicy;
SessionLibrary* mSessionLibrary;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin);
};
} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
index 6a4f8d5..caff393 100644
--- a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
@@ -136,7 +136,7 @@
AString encodedId;
for (size_t i = 0; i < keyIds.size(); ++i) {
encodedId.clear();
- android::encodeBase64(keyIds[i], kKeyIdSize, &encodedId);
+ android::encodeBase64Url(keyIds[i], kKeyIdSize, &encodedId);
if (i != 0) {
request.append(",");
}
diff --git a/drm/mediadrm/plugins/clearkey/tests/Android.bp b/drm/mediadrm/plugins/clearkey/tests/Android.bp
index ac57d65..0fcfc64 100644
--- a/drm/mediadrm/plugins/clearkey/tests/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/tests/Android.bp
@@ -34,4 +34,5 @@
"libstagefright_foundation",
"libutils",
],
+ header_libs: ["media_plugin_headers"],
}
diff --git a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
index 84ed242..8c49656 100644
--- a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
@@ -59,7 +59,7 @@
(size_t)requestString.find(kRequestSuffix));
for (size_t i = 0; i < expectedKeys.size(); ++i) {
AString encodedIdAString;
- android::encodeBase64(expectedKeys[i], kKeyIdSize,
+ android::encodeBase64Url(expectedKeys[i], kKeyIdSize,
&encodedIdAString);
String8 encodedId(encodedIdAString.c_str());
encodedId.removeAll(kBase64Padding);
@@ -231,5 +231,4 @@
attemptParseExpectingFailure(initData, kCencMimeType);
}
-
} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp
index c3b0d84..d9f3ea6 100644
--- a/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp
@@ -284,14 +284,14 @@
"\"keys\":"
"[{"
"\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\""
- "\"k\":\"SGVsbG8gRnJpZW5kISE\""
+ "\"k\":\"SGVsbG8gRnJpZW5kICE-Pw\""
"\"kty\":\"oct\""
"\"alg\":\"A128KW1\""
"}"
"{"
"\"kty\":\"oct\""
"\"alg\":\"A128KW2\""
- "\"k\":\"SGVsbG8gRnJpZW5kIQ\""
+ "\"k\":\"SGVsbG8gRnJpZW5kICE_\""
"\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\""
"}"
"{"
@@ -303,7 +303,7 @@
"{"
"\"alg\":\"A128KW3\""
"\"kid\":\"Y2xlYXJrZXlrZXlpZDAz\""
- "\"k\":\"R29vZCBkYXkh\""
+ "\"k\":\"SGVsbG8gPz4-IEZyaWVuZCA_Pg\""
"\"kty\":\"oct\""
"}]"
"}");
@@ -313,8 +313,8 @@
EXPECT_TRUE(keys.size() == 3);
const String8 clearKeys[] =
- { String8("Hello Friend!!"), String8("Hello Friend!"),
- String8("Good day!") };
+ { String8("Hello Friend !>?"), String8("Hello Friend !?"),
+ String8("Hello ?>> Friend ?>") };
verifyKeys(keys, clearKeys);
}
diff --git a/drm/mediadrm/plugins/mock/Android.bp b/drm/mediadrm/plugins/mock/Android.bp
index 7f44819..abd1884 100644
--- a/drm/mediadrm/plugins/mock/Android.bp
+++ b/drm/mediadrm/plugins/mock/Android.bp
@@ -22,6 +22,8 @@
vendor: true,
relative_install_path: "mediadrm",
+ header_libs: ["media_plugin_headers"],
+
shared_libs: [
"libutils",
"liblog",
diff --git a/include/OWNERS b/include/OWNERS
new file mode 100644
index 0000000..3cb6d9c
--- /dev/null
+++ b/include/OWNERS
@@ -0,0 +1,6 @@
+elaurent@google.com
+gkasten@android.com
+hunga@google.com
+jtinker@google.com
+lajos@google.com
+marcone@google.com
diff --git a/include/media/AudioClient.h b/include/media/AudioClient.h
deleted file mode 120000
index a0530e4..0000000
--- a/include/media/AudioClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioClient.h
\ No newline at end of file
diff --git a/drm/libmediadrm/aidl/android/media/IDescrambler.aidl b/include/media/AudioClient.h
similarity index 61%
copy from drm/libmediadrm/aidl/android/media/IDescrambler.aidl
copy to include/media/AudioClient.h
index fdf99eb..9efd76d 100644
--- a/drm/libmediadrm/aidl/android/media/IDescrambler.aidl
+++ b/include/media/AudioClient.h
@@ -14,14 +14,25 @@
* limitations under the License.
*/
-package android.media;
-import android.media.MediaDescrambler;
+#ifndef ANDROID_AUDIO_CLIENT_H
+#define ANDROID_AUDIO_CLIENT_H
-/** @hide */
-interface IDescrambler {
- void setMediaCasSession(in byte[] sessionId);
- boolean requiresSecureDecoderComponent(String mime);
- int descramble(in MediaDescrambler.DescrambleInfo descrambleInfo);
- void release();
-}
\ No newline at end of file
+#include <system/audio.h>
+#include <utils/String16.h>
+
+namespace android {
+
+class AudioClient {
+ public:
+ AudioClient() :
+ clientUid(-1), clientPid(-1), packageName("") {}
+
+ uid_t clientUid;
+ pid_t clientPid;
+ String16 packageName;
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_CLIENT_H
diff --git a/include/media/AudioResampler.h b/include/media/AudioResampler.h
index 50e12f4..771f1b8 120000
--- a/include/media/AudioResampler.h
+++ b/include/media/AudioResampler.h
@@ -1 +1 @@
-../../media/libaudioprocessing/include/AudioResampler.h
\ No newline at end of file
+../../media/libaudioprocessing/include/media/AudioResampler.h
\ No newline at end of file
diff --git a/include/media/AudioResamplerPublic.h b/include/media/AudioResamplerPublic.h
index 309c23d..ce30a78 120000
--- a/include/media/AudioResamplerPublic.h
+++ b/include/media/AudioResamplerPublic.h
@@ -1 +1 @@
-../../media/libaudioprocessing/include/AudioResamplerPublic.h
\ No newline at end of file
+../../media/libaudioprocessing/include/media/AudioResamplerPublic.h
\ No newline at end of file
diff --git a/include/media/CasImpl.h b/include/media/CasImpl.h
deleted file mode 100644
index 726f1ce..0000000
--- a/include/media/CasImpl.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2017 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 CAS_IMPL_H_
-#define CAS_IMPL_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <android/media/BnCas.h>
-
-namespace android {
-namespace media {
-class ICasListener;
-}
-using namespace media;
-using namespace MediaCas;
-using binder::Status;
-struct CasPlugin;
-class SharedLibrary;
-
-class CasImpl : public BnCas {
-public:
- CasImpl(const sp<ICasListener> &listener);
- virtual ~CasImpl();
-
- static void OnEvent(
- void *appData,
- int32_t event,
- int32_t arg,
- uint8_t *data,
- size_t size);
-
- void init(const sp<SharedLibrary>& library, CasPlugin *plugin);
- void onEvent(
- int32_t event,
- int32_t arg,
- uint8_t *data,
- size_t size);
-
- // ICas inherits
-
- virtual Status setPrivateData(
- const CasData& pvtData) override;
-
- virtual Status openSession(CasSessionId* _aidl_return) override;
-
- virtual Status closeSession(const CasSessionId& sessionId) override;
-
- virtual Status setSessionPrivateData(
- const CasSessionId& sessionId,
- const CasData& pvtData) override;
-
- virtual Status processEcm(
- const CasSessionId& sessionId, const ParcelableCasData& ecm) override;
-
- virtual Status processEmm(const ParcelableCasData& emm) override;
-
- virtual Status sendEvent(
- int32_t event, int32_t arg, const ::std::unique_ptr<CasData> &eventData) override;
-
- virtual Status provision(const String16& provisionString) override;
-
- virtual Status refreshEntitlements(
- int32_t refreshType, const ::std::unique_ptr<CasData> &refreshData) override;
-
- virtual Status release() override;
-
-private:
- struct PluginHolder;
- sp<SharedLibrary> mLibrary;
- sp<PluginHolder> mPluginHolder;
- sp<ICasListener> mListener;
-
- DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
-};
-
-} // namespace android
-
-#endif // CAS_IMPL_H_
diff --git a/include/media/DescramblerImpl.h b/include/media/DescramblerImpl.h
deleted file mode 100644
index 9f212ac..0000000
--- a/include/media/DescramblerImpl.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2017 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 DESCRAMBLER_IMPL_H_
-#define DESCRAMBLER_IMPL_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <android/media/BnDescrambler.h>
-
-namespace android {
-using namespace media;
-using namespace MediaDescrambler;
-using binder::Status;
-struct DescramblerPlugin;
-class SharedLibrary;
-
-class DescramblerImpl : public BnDescrambler {
-public:
- DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin *plugin);
- virtual ~DescramblerImpl();
-
- virtual Status setMediaCasSession(
- const CasSessionId& sessionId) override;
-
- virtual Status requiresSecureDecoderComponent(
- const String16& mime, bool *result) override;
-
- virtual Status descramble(
- const DescrambleInfo& descrambleInfo, int32_t *result) override;
-
- virtual Status release() override;
-
-private:
- sp<SharedLibrary> mLibrary;
- DescramblerPlugin *mPlugin;
-
- DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
-};
-
-} // namespace android
-
-#endif // DESCRAMBLER_IMPL_H_
diff --git a/include/media/MediaCasDefs.h b/include/media/MediaCasDefs.h
deleted file mode 100644
index 8c5a967..0000000
--- a/include/media/MediaCasDefs.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2017 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 MEDIA_CAS_DEFS_H_
-#define MEDIA_CAS_DEFS_H_
-
-#include <binder/Parcel.h>
-#include <media/cas/CasAPI.h>
-#include <media/cas/DescramblerAPI.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-class IMemory;
-namespace media {
-
-namespace MediaCas {
-class ParcelableCasData : public CasData,
- public Parcelable {
-public:
- ParcelableCasData() {}
- ParcelableCasData(const uint8_t *data, size_t size) :
- CasData(data, data + size) {}
- virtual ~ParcelableCasData() {}
- status_t readFromParcel(const Parcel* parcel) override;
- status_t writeToParcel(Parcel* parcel) const override;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(ParcelableCasData);
-};
-
-class ParcelableCasPluginDescriptor : public Parcelable {
-public:
- ParcelableCasPluginDescriptor(int32_t CA_system_id, const char *name)
- : mCASystemId(CA_system_id), mName(name) {}
-
- ParcelableCasPluginDescriptor() : mCASystemId(0) {}
-
- ParcelableCasPluginDescriptor(ParcelableCasPluginDescriptor&& desc) = default;
-
- virtual ~ParcelableCasPluginDescriptor() {}
-
- status_t readFromParcel(const Parcel* parcel) override;
- status_t writeToParcel(Parcel* parcel) const override;
-
-private:
- int32_t mCASystemId;
- String16 mName;
- DISALLOW_EVIL_CONSTRUCTORS(ParcelableCasPluginDescriptor);
-};
-}
-
-namespace MediaDescrambler {
-class DescrambleInfo : public Parcelable {
-public:
- enum DestinationType {
- kDestinationTypeVmPointer, // non-secure
- kDestinationTypeNativeHandle // secure
- };
-
- DestinationType dstType;
- DescramblerPlugin::ScramblingControl scramblingControl;
- size_t numSubSamples;
- DescramblerPlugin::SubSample *subSamples;
- sp<IMemory> srcMem;
- int32_t srcOffset;
- void *dstPtr;
- int32_t dstOffset;
-
- DescrambleInfo();
- virtual ~DescrambleInfo();
- status_t readFromParcel(const Parcel* parcel) override;
- status_t writeToParcel(Parcel* parcel) const override;
-
-private:
-
- DISALLOW_EVIL_CONSTRUCTORS(DescrambleInfo);
-};
-}
-
-} // namespace media
-} // namespace android
-
-
-#endif // MEDIA_CAS_DEFS_H_
diff --git a/include/media/PluginMetricsReporting.h b/include/media/PluginMetricsReporting.h
new file mode 120000
index 0000000..7d9a7a0
--- /dev/null
+++ b/include/media/PluginMetricsReporting.h
@@ -0,0 +1 @@
+../../media/libmedia/include/media/PluginMetricsReporting.h
\ No newline at end of file
diff --git a/include/media/audiohal b/include/media/audiohal
index 37e2c39..f400582 120000
--- a/include/media/audiohal
+++ b/include/media/audiohal
@@ -1 +1 @@
-../../media/libaudiohal/include
\ No newline at end of file
+../../media/libaudiohal/include/media/audiohal/
\ No newline at end of file
diff --git a/include/media/nbaio b/include/media/nbaio
deleted file mode 120000
index 67d0ba6..0000000
--- a/include/media/nbaio
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libnbaio/include
\ No newline at end of file
diff --git a/include/media/nbaio/AudioBufferProviderSource.h b/include/media/nbaio/AudioBufferProviderSource.h
new file mode 120000
index 0000000..55841e7
--- /dev/null
+++ b/include/media/nbaio/AudioBufferProviderSource.h
@@ -0,0 +1 @@
+../../../media/libnbaio/include/media/nbaio/AudioBufferProviderSource.h
\ No newline at end of file
diff --git a/include/media/nbaio/AudioStreamInSource.h b/include/media/nbaio/AudioStreamInSource.h
new file mode 120000
index 0000000..f5bcc76
--- /dev/null
+++ b/include/media/nbaio/AudioStreamInSource.h
@@ -0,0 +1 @@
+../../../media/libnbaio/include/media/nbaio/AudioStreamInSource.h
\ No newline at end of file
diff --git a/include/media/nbaio/AudioStreamOutSink.h b/include/media/nbaio/AudioStreamOutSink.h
new file mode 120000
index 0000000..43bfac5
--- /dev/null
+++ b/include/media/nbaio/AudioStreamOutSink.h
@@ -0,0 +1 @@
+../../../media/libnbaio/include/media/nbaio/AudioStreamOutSink.h
\ No newline at end of file
diff --git a/include/media/nbaio/LibsndfileSink.h b/include/media/nbaio/LibsndfileSink.h
new file mode 120000
index 0000000..8a13b6c
--- /dev/null
+++ b/include/media/nbaio/LibsndfileSink.h
@@ -0,0 +1 @@
+../../../media/libnbaio/include/media/nbaio/LibsndfileSink.h
\ No newline at end of file
diff --git a/include/media/nbaio/LibsndfileSource.h b/include/media/nbaio/LibsndfileSource.h
new file mode 120000
index 0000000..2750fde
--- /dev/null
+++ b/include/media/nbaio/LibsndfileSource.h
@@ -0,0 +1 @@
+../../../media/libnbaio/include/media/nbaio/LibsndfileSource.h
\ No newline at end of file
diff --git a/include/media/nbaio/MonoPipe.h b/include/media/nbaio/MonoPipe.h
new file mode 120000
index 0000000..4ea43be
--- /dev/null
+++ b/include/media/nbaio/MonoPipe.h
@@ -0,0 +1 @@
+../../../media/libnbaio/include_mono/media/nbaio/MonoPipe.h
\ No newline at end of file
diff --git a/include/media/nbaio/MonoPipeReader.h b/include/media/nbaio/MonoPipeReader.h
new file mode 120000
index 0000000..30f426c
--- /dev/null
+++ b/include/media/nbaio/MonoPipeReader.h
@@ -0,0 +1 @@
+../../../media/libnbaio/include_mono/media/nbaio/MonoPipeReader.h
\ No newline at end of file
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
new file mode 120000
index 0000000..ff6a151
--- /dev/null
+++ b/include/media/nbaio/NBAIO.h
@@ -0,0 +1 @@
+../../../media/libnbaio/include_mono/media/nbaio/NBAIO.h
\ No newline at end of file
diff --git a/include/media/nbaio/NBLog.h b/include/media/nbaio/NBLog.h
new file mode 120000
index 0000000..c35401e
--- /dev/null
+++ b/include/media/nbaio/NBLog.h
@@ -0,0 +1 @@
+../../../media/libnbaio/include/media/nbaio/NBLog.h
\ No newline at end of file
diff --git a/include/media/nbaio/PerformanceAnalysis.h b/include/media/nbaio/PerformanceAnalysis.h
new file mode 120000
index 0000000..7acfc90
--- /dev/null
+++ b/include/media/nbaio/PerformanceAnalysis.h
@@ -0,0 +1 @@
+../../../media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
\ No newline at end of file
diff --git a/include/media/nbaio/Pipe.h b/include/media/nbaio/Pipe.h
new file mode 120000
index 0000000..a4bbbc9
--- /dev/null
+++ b/include/media/nbaio/Pipe.h
@@ -0,0 +1 @@
+../../../media/libnbaio/include/media/nbaio/Pipe.h
\ No newline at end of file
diff --git a/include/media/nbaio/PipeReader.h b/include/media/nbaio/PipeReader.h
new file mode 120000
index 0000000..64b21cf
--- /dev/null
+++ b/include/media/nbaio/PipeReader.h
@@ -0,0 +1 @@
+../../../media/libnbaio/include/media/nbaio/PipeReader.h
\ No newline at end of file
diff --git a/include/media/nbaio/SourceAudioBufferProvider.h b/include/media/nbaio/SourceAudioBufferProvider.h
new file mode 120000
index 0000000..74a3b06
--- /dev/null
+++ b/include/media/nbaio/SourceAudioBufferProvider.h
@@ -0,0 +1 @@
+../../../media/libnbaio/include/media/nbaio/SourceAudioBufferProvider.h
\ No newline at end of file
diff --git a/include/media/vndk/xmlparser/1.0/MediaCodecsXmlParser.h b/include/media/vndk/xmlparser/1.0/MediaCodecsXmlParser.h
deleted file mode 100644
index b324cd8..0000000
--- a/include/media/vndk/xmlparser/1.0/MediaCodecsXmlParser.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2017, 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 MEDIA_CODECS_XML_PARSER_H_
-
-#define MEDIA_CODECS_XML_PARSER_H_
-
-#include <map>
-#include <vector>
-
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AString.h>
-
-#include <sys/types.h>
-#include <utils/Errors.h>
-#include <utils/Vector.h>
-#include <utils/StrongPointer.h>
-
-namespace android {
-
-struct AMessage;
-
-// Quirk still supported, even though deprecated
-enum Quirks {
- kRequiresAllocateBufferOnInputPorts = 1,
- kRequiresAllocateBufferOnOutputPorts = 2,
-
- kQuirksMask = kRequiresAllocateBufferOnInputPorts
- | kRequiresAllocateBufferOnOutputPorts,
-};
-
-// Lightweight struct for querying components.
-struct TypeInfo {
- AString mName;
- std::map<AString, AString> mStringFeatures;
- std::map<AString, bool> mBoolFeatures;
- std::map<AString, AString> mDetails;
-};
-
-struct ProfileLevel {
- uint32_t mProfile;
- uint32_t mLevel;
-};
-
-struct CodecInfo {
- std::vector<TypeInfo> mTypes;
- std::vector<ProfileLevel> mProfileLevels;
- std::vector<uint32_t> mColorFormats;
- uint32_t mFlags;
- bool mIsEncoder;
-};
-
-class MediaCodecsXmlParser {
-public:
- MediaCodecsXmlParser();
- ~MediaCodecsXmlParser();
-
- void getGlobalSettings(std::map<AString, AString> *settings) const;
-
- status_t getCodecInfo(const char *name, CodecInfo *info) const;
-
- status_t getQuirks(const char *name, std::vector<AString> *quirks) const;
-
-private:
- enum Section {
- SECTION_TOPLEVEL,
- SECTION_SETTINGS,
- SECTION_DECODERS,
- SECTION_DECODER,
- SECTION_DECODER_TYPE,
- SECTION_ENCODERS,
- SECTION_ENCODER,
- SECTION_ENCODER_TYPE,
- SECTION_INCLUDE,
- };
-
- status_t mInitCheck;
- Section mCurrentSection;
- bool mUpdate;
- Vector<Section> mPastSections;
- int32_t mDepth;
- AString mHrefBase;
-
- std::map<AString, AString> mGlobalSettings;
-
- // name -> CodecInfo
- std::map<AString, CodecInfo> mCodecInfos;
- std::map<AString, std::vector<AString>> mQuirks;
- AString mCurrentName;
- std::vector<TypeInfo>::iterator mCurrentType;
-
- status_t initCheck() const;
- void parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
-
- void parseXMLFile(const char *path);
-
- static void StartElementHandlerWrapper(
- void *me, const char *name, const char **attrs);
-
- static void EndElementHandlerWrapper(void *me, const char *name);
-
- void startElementHandler(const char *name, const char **attrs);
- void endElementHandler(const char *name);
-
- status_t includeXMLFile(const char **attrs);
- status_t addSettingFromAttributes(const char **attrs);
- status_t addMediaCodecFromAttributes(bool encoder, const char **attrs);
- void addMediaCodec(bool encoder, const char *name, const char *type = NULL);
-
- status_t addQuirk(const char **attrs);
- status_t addTypeFromAttributes(const char **attrs, bool encoder);
- status_t addLimit(const char **attrs);
- status_t addFeature(const char **attrs);
- void addType(const char *name);
-
- DISALLOW_EVIL_CONSTRUCTORS(MediaCodecsXmlParser);
-};
-
-} // namespace android
-
-#endif // MEDIA_CODECS_XML_PARSER_H_
-
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 9da5ef3..ff440bc 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -568,6 +568,9 @@
// which may include non-contiguous frames
virtual size_t framesReady();
+ // Safe frames ready query used by dump() - this has no side effects.
+ virtual size_t framesReadySafe() const;
+
// Currently AudioFlinger will call framesReady() for a fast track from two threads:
// FastMixer thread, and normal mixer thread. This is dangerous, as the proxy is intended
// to be called from at most one thread of server, and one thread of client.
@@ -620,6 +623,7 @@
public:
virtual size_t framesReady();
+ virtual size_t framesReadySafe() const override;
virtual void framesReadyIsCalledByMultipleThreads();
virtual status_t obtainBuffer(Buffer* buffer, bool ackFlush);
virtual void releaseBuffer(Buffer* buffer);
diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h
index 51050cd..a9d4dd1 100644
--- a/include/private/media/VideoFrame.h
+++ b/include/private/media/VideoFrame.h
@@ -30,14 +30,41 @@
class VideoFrame
{
public:
- VideoFrame(): mWidth(0), mHeight(0), mDisplayWidth(0), mDisplayHeight(0), mSize(0),
- mRotationAngle(0), mData(0) {}
+ // Construct a VideoFrame object with the specified parameters,
+ // will allocate frame buffer if |allocate| is set to true, will
+ // allocate buffer to hold ICC data if |iccData| and |iccSize|
+ // indicate its presence.
+ VideoFrame(uint32_t width, uint32_t height,
+ uint32_t displayWidth, uint32_t displayHeight,
+ uint32_t angle, uint32_t bpp, bool allocate,
+ const void *iccData, size_t iccSize):
+ mWidth(width), mHeight(height),
+ mDisplayWidth(displayWidth), mDisplayHeight(displayHeight),
+ mRotationAngle(angle), mBytesPerPixel(bpp), mRowBytes(bpp * width),
+ mSize(0), mIccSize(0), mReserved(0), mData(0), mIccData(0) {
+ if (allocate) {
+ mSize = mRowBytes * mHeight;
+ mData = new uint8_t[mSize];
+ if (mData == NULL) {
+ mSize = 0;
+ }
+ }
+ if (iccData != NULL && iccSize > 0) {
+ mIccSize = iccSize;
+ mIccData = new uint8_t[iccSize];
+ if (mIccData != NULL) {
+ memcpy(mIccData, iccData, iccSize);
+ } else {
+ mIccSize = 0;
+ }
+ }
+ }
+
+ // Deep copy of both the information fields and the frame data
VideoFrame(const VideoFrame& copy) {
- mWidth = copy.mWidth;
- mHeight = copy.mHeight;
- mDisplayWidth = copy.mDisplayWidth;
- mDisplayHeight = copy.mDisplayHeight;
+ copyInfoOnly(copy);
+
mSize = copy.mSize;
mData = NULL; // initialize it first
if (mSize > 0 && copy.mData != NULL) {
@@ -48,26 +75,99 @@
mSize = 0;
}
}
- mRotationAngle = copy.mRotationAngle;
+
+ mIccSize = copy.mIccSize;
+ mIccData = NULL; // initialize it first
+ if (mIccSize > 0 && copy.mIccData != NULL) {
+ mIccData = new uint8_t[mIccSize];
+ if (mIccData != NULL) {
+ memcpy(mIccData, copy.mIccData, mIccSize);
+ } else {
+ mIccSize = 0;
+ }
+ }
}
~VideoFrame() {
if (mData != 0) {
delete[] mData;
}
+ if (mIccData != 0) {
+ delete[] mIccData;
+ }
+ }
+
+ // Copy |copy| to a flattened VideoFrame in IMemory, 'this' must point to
+ // a chunk of memory back by IMemory of size at least getFlattenedSize()
+ // of |copy|.
+ void copyFlattened(const VideoFrame& copy) {
+ copyInfoOnly(copy);
+
+ mSize = copy.mSize;
+ mData = NULL; // initialize it first
+ if (copy.mSize > 0 && copy.mData != NULL) {
+ memcpy(getFlattenedData(), copy.mData, copy.mSize);
+ }
+
+ mIccSize = copy.mIccSize;
+ mIccData = NULL; // initialize it first
+ if (copy.mIccSize > 0 && copy.mIccData != NULL) {
+ memcpy(getFlattenedIccData(), copy.mIccData, copy.mIccSize);
+ }
+ }
+
+ // Calculate the flattened size to put it in IMemory
+ size_t getFlattenedSize() const {
+ return sizeof(VideoFrame) + mSize + mIccSize;
+ }
+
+ // Get the pointer to the frame data in a flattened VideoFrame in IMemory
+ uint8_t* getFlattenedData() const {
+ return (uint8_t*)this + sizeof(VideoFrame);
+ }
+
+ // Get the pointer to the ICC data in a flattened VideoFrame in IMemory
+ uint8_t* getFlattenedIccData() const {
+ return (uint8_t*)this + sizeof(VideoFrame) + mSize;
}
// Intentional public access modifier:
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mDisplayWidth;
- uint32_t mDisplayHeight;
+ uint32_t mWidth; // Decoded image width before rotation
+ uint32_t mHeight; // Decoded image height before rotation
+ uint32_t mDisplayWidth; // Display width before rotation
+ uint32_t mDisplayHeight; // Display height before rotation
+ int32_t mRotationAngle; // Rotation angle, clockwise, should be multiple of 90
+ uint32_t mBytesPerPixel; // Number of bytes per pixel
+ uint32_t mRowBytes; // Number of bytes per row before rotation
uint32_t mSize; // Number of bytes in mData
- int32_t mRotationAngle; // rotation angle, clockwise, should be multiple of 90
- // mData should be 64 bit aligned to prevent additional padding
+ uint32_t mIccSize; // Number of bytes in mIccData
+ uint32_t mReserved; // (padding to make mData 64-bit aligned)
+
+ // mData should be 64-bit aligned to prevent additional padding
uint8_t* mData; // Actual binary data
- // pad structure so it's the same size on 64 bit and 32 bit
+ // pad structure so it's the same size on 64-bit and 32-bit
char mPadding[8 - sizeof(mData)];
+
+ // mIccData should be 64-bit aligned to prevent additional padding
+ uint8_t* mIccData; // Actual binary data
+ // pad structure so it's the same size on 64-bit and 32-bit
+ char mIccPadding[8 - sizeof(mIccData)];
+
+private:
+ //
+ // Utility methods used only within VideoFrame struct
+ //
+
+ // Copy the information fields only
+ void copyInfoOnly(const VideoFrame& copy) {
+ mWidth = copy.mWidth;
+ mHeight = copy.mHeight;
+ mDisplayWidth = copy.mDisplayWidth;
+ mDisplayHeight = copy.mDisplayHeight;
+ mRotationAngle = copy.mRotationAngle;
+ mBytesPerPixel = copy.mBytesPerPixel;
+ mRowBytes = copy.mRowBytes;
+ }
};
}; // namespace android
diff --git a/include/radio/IRadio.h b/include/radio/IRadio.h
deleted file mode 100644
index 1877f8f..0000000
--- a/include/radio/IRadio.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2015 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_HARDWARE_IRADIO_H
-#define ANDROID_HARDWARE_IRADIO_H
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/IMemory.h>
-#include <binder/Parcel.h>
-#include <system/radio.h>
-
-namespace android {
-
-class IRadio : public IInterface
-{
-public:
-
- DECLARE_META_INTERFACE(Radio);
-
- virtual void detach() = 0;
-
- virtual status_t setConfiguration(const struct radio_band_config *config) = 0;
-
- virtual status_t getConfiguration(struct radio_band_config *config) = 0;
-
- virtual status_t setMute(bool mute) = 0;
-
- virtual status_t getMute(bool *mute) = 0;
-
- virtual status_t step(radio_direction_t direction, bool skipSubChannel) = 0;
-
- virtual status_t scan(radio_direction_t direction, bool skipSubChannel) = 0;
-
- virtual status_t tune(unsigned int channel, unsigned int subChannel) = 0;
-
- virtual status_t cancel() = 0;
-
- virtual status_t getProgramInformation(struct radio_program_info *info) = 0;
-
- virtual status_t hasControl(bool *hasControl) = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnRadio: public BnInterface<IRadio>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif //ANDROID_HARDWARE_IRADIO_H
diff --git a/include/radio/IRadioClient.h b/include/radio/IRadioClient.h
deleted file mode 100644
index 9062ad6..0000000
--- a/include/radio/IRadioClient.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2015 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_HARDWARE_IRADIO_CLIENT_H
-#define ANDROID_HARDWARE_IRADIO_CLIENT_H
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/IMemory.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-class IRadioClient : public IInterface
-{
-public:
-
- DECLARE_META_INTERFACE(RadioClient);
-
- virtual void onEvent(const sp<IMemory>& eventMemory) = 0;
-
-};
-
-// ----------------------------------------------------------------------------
-
-class BnRadioClient : public BnInterface<IRadioClient>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif //ANDROID_HARDWARE_IRADIO_CLIENT_H
diff --git a/include/radio/IRadioService.h b/include/radio/IRadioService.h
deleted file mode 100644
index a946dd5..0000000
--- a/include/radio/IRadioService.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2015 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_HARDWARE_IRADIO_SERVICE_H
-#define ANDROID_HARDWARE_IRADIO_SERVICE_H
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-#include <system/radio.h>
-
-namespace android {
-
-class IRadio;
-class IRadioClient;
-
-class IRadioService : public IInterface
-{
-public:
-
- DECLARE_META_INTERFACE(RadioService);
-
- virtual status_t listModules(struct radio_properties *properties,
- uint32_t *numModules) = 0;
-
- virtual status_t attach(const radio_handle_t handle,
- const sp<IRadioClient>& client,
- const struct radio_band_config *config,
- bool withAudio,
- sp<IRadio>& radio) = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnRadioService: public BnInterface<IRadioService>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif //ANDROID_HARDWARE_IRADIO_SERVICE_H
diff --git a/include/radio/Radio.h b/include/radio/Radio.h
deleted file mode 100644
index fb4dd2f..0000000
--- a/include/radio/Radio.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2015 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_HARDWARE_RADIO_H
-#define ANDROID_HARDWARE_RADIO_H
-
-#include <binder/IBinder.h>
-#include <utils/threads.h>
-#include <radio/RadioCallback.h>
-#include <radio/IRadio.h>
-#include <radio/IRadioService.h>
-#include <radio/IRadioClient.h>
-#include <system/radio.h>
-
-namespace android {
-
-class MemoryDealer;
-
-class Radio : public BnRadioClient,
- public IBinder::DeathRecipient
-{
-public:
-
- virtual ~Radio();
-
- static status_t listModules(struct radio_properties *properties,
- uint32_t *numModules);
- static sp<Radio> attach(radio_handle_t handle,
- const struct radio_band_config *config,
- bool withAudio,
- const sp<RadioCallback>& callback);
-
-
- void detach();
-
- status_t setConfiguration(const struct radio_band_config *config);
-
- status_t getConfiguration(struct radio_band_config *config);
-
- status_t setMute(bool mute);
-
- status_t getMute(bool *mute);
-
- status_t step(radio_direction_t direction, bool skipSubChannel);
-
- status_t scan(radio_direction_t direction, bool skipSubChannel);
-
- status_t tune(unsigned int channel, unsigned int subChannel);
-
- status_t cancel();
-
- status_t getProgramInformation(struct radio_program_info *info);
-
- status_t hasControl(bool *hasControl);
-
- // BpRadioClient
- virtual void onEvent(const sp<IMemory>& eventMemory);
-
- //IBinder::DeathRecipient
- virtual void binderDied(const wp<IBinder>& who);
-
-private:
- Radio(radio_handle_t handle,
- const sp<RadioCallback>&);
- static const sp<IRadioService> getRadioService();
-
- Mutex mLock;
- sp<IRadio> mIRadio;
- sp<RadioCallback> mCallback;
-};
-
-}; // namespace android
-
-#endif //ANDROID_HARDWARE_RADIO_H
diff --git a/include/radio/RadioCallback.h b/include/radio/RadioCallback.h
deleted file mode 100644
index 4a7f1a6..0000000
--- a/include/radio/RadioCallback.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2015 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_HARDWARE_RADIO_CALLBACK_H
-#define ANDROID_HARDWARE_RADIO_CALLBACK_H
-
-#include <utils/RefBase.h>
-#include <system/radio.h>
-
-namespace android {
-
-class RadioCallback : public RefBase
-{
-public:
-
- RadioCallback() {}
- virtual ~RadioCallback() {}
-
- virtual void onEvent(struct radio_event *event) = 0;
-
-};
-
-}; // namespace android
-
-#endif //ANDROID_HARDWARE_RADIO_CALLBACK_H
diff --git a/media/OWNERS b/media/OWNERS
new file mode 100644
index 0000000..1605efd
--- /dev/null
+++ b/media/OWNERS
@@ -0,0 +1,18 @@
+chz@google.com
+dwkang@google.com
+elaurent@google.com
+essick@google.com
+hunga@google.com
+jmtrivi@google.com
+krocard@google.com
+lajos@google.com
+marcone@google.com
+mnaganov@google.com
+pawin@google.com
+philburk@google.com
+pmclean@google.com
+rachad@google.com
+rago@google.com
+robertshih@google.com
+wjia@google.com
+wonsik@google.com
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index afd1189..3ee7494 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -14,7 +14,6 @@
liblog \
libmedialogservice \
libnbaio \
- libradioservice \
libsoundtriggerservice \
libutils \
libhwbinder
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
index ba47fd4..474ef97 100644
--- a/media/audioserver/main_audioserver.cpp
+++ b/media/audioserver/main_audioserver.cpp
@@ -32,11 +32,12 @@
#include <hwbinder/ProcessState.h>
// from LOCAL_C_INCLUDES
+#include "aaudio/AAudioTesting.h"
#include "AudioFlinger.h"
#include "AudioPolicyService.h"
#include "AAudioService.h"
+#include "utility/AAudioUtilities.h"
#include "MediaLogService.h"
-#include "RadioService.h"
#include "SoundTriggerHwService.h"
using namespace android;
@@ -132,9 +133,16 @@
ALOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
AudioPolicyService::instantiate();
- // AAudioService disabled because we do not support MMAP mode in OC or OC-DR1.
- // AAudioService::instantiate();
- RadioService::instantiate();
+
+ // AAudioService should only be used in OC-MR1 and later.
+ // And only enable the AAudioService if the system MMAP policy explicitly allows it.
+ // This prevents a client from misusing AAudioService when it is not supported.
+ aaudio_policy_t mmapPolicy = property_get_int32(AAUDIO_PROP_MMAP_POLICY,
+ AAUDIO_POLICY_NEVER);
+ if (mmapPolicy == AAUDIO_POLICY_AUTO || mmapPolicy == AAUDIO_POLICY_ALWAYS) {
+ AAudioService::instantiate();
+ }
+
SoundTriggerHwService::instantiate();
ProcessState::self()->startThreadPool();
diff --git a/media/libaaudio/Android.bp b/media/libaaudio/Android.bp
index f539ba9..6e60f24 100644
--- a/media/libaaudio/Android.bp
+++ b/media/libaaudio/Android.bp
@@ -16,12 +16,14 @@
name: "libAAudio_headers",
from: "include",
to: "",
- srcs: ["include/aaudio/*.h"],
+ // omit AAudioTesting.h; supplied separately to those who need it
+ srcs: ["include/aaudio/AAudio.h"],
license: "include/aaudio/NOTICE",
}
ndk_library {
name: "libaaudio",
+ // deliberately includes symbols from AAudioTesting.h
symbol_file: "libaaudio.map.txt",
first_version: "26",
unversioned_until: "current",
diff --git a/media/libaaudio/Doxyfile b/media/libaaudio/Doxyfile
index e2c4960..7298d11 100644
--- a/media/libaaudio/Doxyfile
+++ b/media/libaaudio/Doxyfile
@@ -744,12 +744,12 @@
# Note: If this tag is empty the current directory is searched.
INPUT = include/aaudio/AAudio.h \
+ src/binding/AAudioCommon.h \
src/legacy/AudioStreamTrack.h \
src/legacy/AudioStreamRecord.h \
src/legacy/AAudioLegacy.h \
src/core/AudioStreamBuilder.h \
src/core/AudioStream.h \
- src/utility/HandleTracker.h \
src/utility/MonotonicCounter.h \
src/utility/AudioClock.h \
src/utility/AAudioUtilities.h
diff --git a/media/libaaudio/OWNERS b/media/libaaudio/OWNERS
new file mode 100644
index 0000000..f4d51f9
--- /dev/null
+++ b/media/libaaudio/OWNERS
@@ -0,0 +1 @@
+philburk@google.com
diff --git a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
index 910b10c..9feb118 100644
--- a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
+++ b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
@@ -27,9 +27,11 @@
#include "AAudioSimpleRecorder.h"
// TODO support FLOAT
-#define REQUIRED_FORMAT AAUDIO_FORMAT_PCM_I16
+#define REQUIRED_FORMAT AAUDIO_FORMAT_PCM_I16
#define MIN_FRAMES_TO_READ 48 /* arbitrary, 1 msec at 48000 Hz */
+static const int FRAMES_PER_LINE = 20000;
+
int main(int argc, const char **argv)
{
AAudioArgsParser argParser;
@@ -46,7 +48,10 @@
int32_t framesPerRead = 0;
int32_t framesToRecord = 0;
int32_t framesLeft = 0;
+ int32_t nextFrameCount = 0;
+ int32_t frameCount = 0;
int32_t xRunCount = 0;
+ int64_t previousFramePosition = -1;
int16_t *data = nullptr;
float peakLevel = 0.0;
int loopCounter = 0;
@@ -56,7 +61,7 @@
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
- printf("%s - Monitor input level using AAudio\n", argv[0]);
+ printf("%s - Monitor input level using AAudio read, V0.1.2\n", argv[0]);
argParser.setFormat(REQUIRED_FORMAT);
if (argParser.parseArgs(argc, argv)) {
@@ -74,7 +79,7 @@
deviceId = AAudioStream_getDeviceId(aaudioStream);
printf("deviceId = %d\n", deviceId);
- actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(aaudioStream);
+ actualSamplesPerFrame = AAudioStream_getChannelCount(aaudioStream);
printf("SamplesPerFrame = %d\n", actualSamplesPerFrame);
actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
printf("SamplesPerFrame = %d\n", actualSampleRate);
@@ -133,6 +138,7 @@
goto finish;
}
framesLeft -= actual;
+ frameCount += actual;
// Peak finder.
for (int frameIndex = 0; frameIndex < actual; frameIndex++) {
@@ -143,9 +149,36 @@
}
// Display level as stars, eg. "******".
- if ((loopCounter++ % 10) == 0) {
+ if (frameCount > nextFrameCount) {
displayPeakLevel(peakLevel);
peakLevel = 0.0;
+ nextFrameCount += FRAMES_PER_LINE;
+ }
+
+ // Print timestamps.
+ int64_t framePosition = 0;
+ int64_t frameTime = 0;
+ aaudio_result_t timeResult;
+ timeResult = AAudioStream_getTimestamp(aaudioStream, CLOCK_MONOTONIC,
+ &framePosition, &frameTime);
+
+ if (timeResult == AAUDIO_OK) {
+ if (framePosition > (previousFramePosition + FRAMES_PER_LINE)) {
+ int64_t realTime = getNanoseconds();
+ int64_t framesRead = AAudioStream_getFramesRead(aaudioStream);
+
+ double latencyMillis = calculateLatencyMillis(framesRead, realTime,
+ framePosition, frameTime,
+ actualSampleRate);
+
+ printf("--- timestamp: result = %4d, position = %lld, at %lld nanos"
+ ", latency = %7.2f msec\n",
+ timeResult,
+ (long long) framePosition,
+ (long long) frameTime,
+ latencyMillis);
+ previousFramePosition = framePosition;
+ }
}
}
diff --git a/media/libaaudio/examples/input_monitor/src/input_monitor_callback.cpp b/media/libaaudio/examples/input_monitor/src/input_monitor_callback.cpp
index 9de2eb0..893795b 100644
--- a/media/libaaudio/examples/input_monitor/src/input_monitor_callback.cpp
+++ b/media/libaaudio/examples/input_monitor/src/input_monitor_callback.cpp
@@ -41,7 +41,7 @@
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
- printf("%s - Display audio input using an AAudio callback\n", argv[0]);
+ printf("%s - Display audio input using an AAudio callback, V0.1.2\n", argv[0]);
result = recorder.open(2, 48000, AAUDIO_FORMAT_PCM_I16,
SimpleRecorderDataCallbackProc, SimpleRecorderErrorCallbackProc, &myData);
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 144c941..df0df04 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -417,11 +417,18 @@
sleep(1);
printf("%4d: ", i);
loopbackData.loopbackProcessor->printStatus();
- int64_t framesWritten = AAudioStream_getFramesWritten(loopbackData.inputStream);
- int64_t framesRead = AAudioStream_getFramesRead(loopbackData.inputStream);
- printf(" input written = %lld, read %lld, xruns = %d\n",
- (long long) framesWritten,
- (long long) framesRead,
+
+ int64_t inputFramesWritten = AAudioStream_getFramesWritten(loopbackData.inputStream);
+ int64_t inputFramesRead = AAudioStream_getFramesRead(loopbackData.inputStream);
+ int64_t outputFramesWritten = AAudioStream_getFramesWritten(outputStream);
+ int64_t outputFramesRead = AAudioStream_getFramesRead(outputStream);
+ printf(" INPUT: wr %lld rd %lld state %s, OUTPUT: wr %lld rd %lld state %s, xruns %d\n",
+ (long long) inputFramesWritten,
+ (long long) inputFramesRead,
+ AAudio_convertStreamStateToText(AAudioStream_getState(loopbackData.inputStream)),
+ (long long) outputFramesWritten,
+ (long long) outputFramesRead,
+ AAudio_convertStreamStateToText(AAudioStream_getState(outputStream)),
AAudioStream_getXRunCount(outputStream)
);
}
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index 46bc99e..ada37e2 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -24,7 +24,8 @@
#include <aaudio/AAudio.h>
#include <aaudio/AAudioTesting.h>
-#include <AAudioExampleUtils.h>
+
+#include "AAudioExampleUtils.h"
// TODO use this as a base class within AAudio
class AAudioParameters {
@@ -149,6 +150,9 @@
setChannelCount(atoi(&arg[2]));
break;
case 'd':
+ setDeviceId(atoi(&arg[2]));
+ break;
+ case 's':
mDurationSeconds = atoi(&arg[2]);
break;
case 'm': {
@@ -201,7 +205,8 @@
printf(" Default values are UNSPECIFIED unless otherwise stated.\n");
printf(" -b{bufferCapacity} frames\n");
printf(" -c{channels} for example 2 for stereo\n");
- printf(" -d{duration} in seconds, default is %d\n", DEFAULT_DURATION_SECONDS);
+ printf(" -d{deviceId} default is %d\n", AAUDIO_UNSPECIFIED);
+ printf(" -s{duration} in seconds, default is %d\n", DEFAULT_DURATION_SECONDS);
printf(" -m{0|1|2|3} set MMAP policy\n");
printf(" 0 = _UNSPECIFIED, default\n");
printf(" 1 = _NEVER\n");
@@ -239,7 +244,7 @@
* Print stream parameters in comparison with requested values.
* @param stream
*/
- void compareWithStream(AAudioStream *stream) {
+ void compareWithStream(AAudioStream *stream) const {
printf(" DeviceId: requested = %d, actual = %d\n",
getDeviceId(), AAudioStream_getDeviceId(stream));
diff --git a/media/libaaudio/examples/utils/AAudioExampleUtils.h b/media/libaaudio/examples/utils/AAudioExampleUtils.h
index 66de25f..c179ce6 100644
--- a/media/libaaudio/examples/utils/AAudioExampleUtils.h
+++ b/media/libaaudio/examples/utils/AAudioExampleUtils.h
@@ -17,27 +17,71 @@
#ifndef AAUDIO_EXAMPLE_UTILS_H
#define AAUDIO_EXAMPLE_UTILS_H
-#include <unistd.h>
+#include <atomic>
+#include <linux/futex.h>
#include <sched.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
#include <aaudio/AAudio.h>
+#include <utils/Errors.h>
#define NANOS_PER_MICROSECOND ((int64_t)1000)
#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
#define NANOS_PER_SECOND (NANOS_PER_MILLISECOND * 1000)
-static const char *getSharingModeText(aaudio_sharing_mode_t mode) {
- const char *modeText = "unknown";
+const char *getSharingModeText(aaudio_sharing_mode_t mode) {
+ const char *text = "unknown";
switch (mode) {
- case AAUDIO_SHARING_MODE_EXCLUSIVE:
- modeText = "EXCLUSIVE";
- break;
- case AAUDIO_SHARING_MODE_SHARED:
- modeText = "SHARED";
- break;
- default:
- break;
+ case AAUDIO_SHARING_MODE_EXCLUSIVE:
+ text = "EXCLUSIVE";
+ break;
+ case AAUDIO_SHARING_MODE_SHARED:
+ text = "SHARED";
+ break;
+ default:
+ break;
}
- return modeText;
+ return text;
+}
+
+const char *getPerformanceModeText(aaudio_performance_mode_t mode) {
+ const char *text = "unknown";
+ switch (mode) {
+ case AAUDIO_PERFORMANCE_MODE_NONE:
+ text = "NONE";
+ break;
+ case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
+ text = "LOW_LATENCY";
+ break;
+ case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
+ text = "POWER_SAVING";
+ break;
+ default:
+ break;
+ }
+ return text;
+}
+
+const char *getDirectionText(aaudio_direction_t direction) {
+ const char *text = "unknown";
+ switch (direction) {
+ case AAUDIO_DIRECTION_INPUT:
+ text = "INPUT";
+ break;
+ case AAUDIO_DIRECTION_OUTPUT:
+ text = "OUTPUT";
+ break;
+ default:
+ break;
+ }
+ return text;
+}
+
+static void convertNanosecondsToTimespec(int64_t nanoseconds, struct timespec *time) {
+ time->tv_sec = nanoseconds / NANOS_PER_SECOND;
+ // Calculate the fractional nanoseconds. Avoids expensive % operation.
+ time->tv_nsec = nanoseconds - (time->tv_sec * NANOS_PER_SECOND);
}
static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
@@ -49,7 +93,7 @@
return (time.tv_sec * NANOS_PER_SECOND) + time.tv_nsec;
}
-void displayPeakLevel(float peakLevel) {
+static void displayPeakLevel(float peakLevel) {
printf("%5.3f ", peakLevel);
const int maxStars = 50; // arbitrary, fits on one line
int numStars = (int) (peakLevel * maxStars);
@@ -59,4 +103,97 @@
printf("\n");
}
+/**
+ * @param position1 position of hardware frame
+ * @param nanoseconds1
+ * @param position2 position of client read/write
+ * @param nanoseconds2
+ * @param sampleRate
+ * @return latency in milliseconds
+ */
+static double calculateLatencyMillis(int64_t position1, int64_t nanoseconds1,
+ int64_t position2, int64_t nanoseconds2,
+ int64_t sampleRate) {
+ int64_t deltaFrames = position2 - position1;
+ int64_t deltaTime =
+ (NANOS_PER_SECOND * deltaFrames / sampleRate);
+ int64_t timeCurrentFramePlayed = nanoseconds1 + deltaTime;
+ int64_t latencyNanos = timeCurrentFramePlayed - nanoseconds2;
+ double latencyMillis = latencyNanos / 1000000.0;
+ return latencyMillis;
+}
+
+// ================================================================================
+// These Futex calls are common online examples.
+static android::status_t sys_futex(void *addr1, int op, int val1,
+ struct timespec *timeout, void *addr2, int val3) {
+ android::status_t result = (android::status_t) syscall(SYS_futex, addr1,
+ op, val1, timeout,
+ addr2, val3);
+ return (result == 0) ? 0 : -errno;
+}
+
+static android::status_t futex_wake(void *addr, int numWake) {
+ // Use _PRIVATE because we are just using the futex in one process.
+ return sys_futex(addr, FUTEX_WAKE_PRIVATE, numWake, NULL, NULL, 0);
+}
+
+static android::status_t futex_wait(void *addr, int current, struct timespec *time) {
+ // Use _PRIVATE because we are just using the futex in one process.
+ return sys_futex(addr, FUTEX_WAIT_PRIVATE, current, time, NULL, 0);
+}
+
+// TODO better name?
+/**
+ * The WakeUp class is used to send a wakeup signal to one or more sleeping threads.
+ */
+class WakeUp {
+public:
+ WakeUp() : mValue(0) {}
+ explicit WakeUp(int32_t value) : mValue(value) {}
+
+ /**
+ * Wait until the internal value no longer matches the given value.
+ * Note that this code uses a futex, which is subject to spurious wake-ups.
+ * So check to make sure that the desired condition has been met.
+ *
+ * @return zero if the value changes or various negative errors including
+ * -ETIMEDOUT if a timeout occurs,
+ * or -EINTR if interrupted by a signal,
+ * or -EAGAIN or -EWOULDBLOCK if the internal value does not match the specified value
+ */
+ android::status_t wait(int32_t value, int64_t timeoutNanoseconds) {
+ struct timespec time;
+ convertNanosecondsToTimespec(timeoutNanoseconds, &time);
+ return futex_wait(&mValue, value, &time);
+ }
+
+ /**
+ * Increment value and wake up any threads that need to be woken.
+ *
+ * @return number of waiters woken up
+ */
+ android::status_t wake() {
+ ++mValue;
+ return futex_wake(&mValue, INT_MAX);
+ }
+
+ /**
+ * Set value and wake up any threads that need to be woken.
+ *
+ * @return number of waiters woken up
+ */
+ android::status_t wake(int32_t value) {
+ mValue.store(value);
+ return futex_wake(&mValue, INT_MAX);
+ }
+
+ int32_t get() {
+ return mValue.load();
+ }
+
+private:
+ std::atomic<int32_t> mValue;
+};
+
#endif // AAUDIO_EXAMPLE_UTILS_H
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index cc0cb34..606c4ba 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -23,6 +23,7 @@
#include <sched.h>
#include <aaudio/AAudio.h>
+#include <atomic>
#include "AAudioArgsParser.h"
#include "SineGenerator.h"
@@ -35,6 +36,13 @@
// How long to sleep in a callback to cause an intentional glitch. For testing.
#define FORCED_UNDERRUN_SLEEP_MICROS (10 * 1000)
+#define MAX_TIMESTAMPS 16
+
+typedef struct Timestamp {
+ int64_t position;
+ int64_t nanoseconds;
+} Timestamp;
+
/**
* Simple wrapper for AAudio that opens an output stream either in callback or blocking write mode.
*/
@@ -219,18 +227,28 @@
AAudioStream *mStream = nullptr;
aaudio_sharing_mode_t mRequestedSharingMode = SHARING_MODE;
aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE;
+
};
typedef struct SineThreadedData_s {
+
SineGenerator sineOsc1;
SineGenerator sineOsc2;
+ Timestamp timestamps[MAX_TIMESTAMPS];
int64_t framesTotal = 0;
int64_t nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
int32_t minNumFrames = INT32_MAX;
int32_t maxNumFrames = 0;
- int scheduler;
+ int32_t timestampCount = 0; // in timestamps
+
+ int scheduler = 0;
bool schedulerChecked = false;
bool forceUnderruns = false;
+
+ AAudioSimplePlayer simplePlayer;
+ int32_t callbackCount = 0;
+ WakeUp waker{AAUDIO_OK};
+
} SineThreadedData_t;
// Callback function that fills the audio output buffer.
@@ -247,6 +265,7 @@
return AAUDIO_CALLBACK_RESULT_STOP;
}
SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
+ sineData->callbackCount++;
sineData->framesTotal += numFrames;
@@ -263,6 +282,17 @@
sineData->schedulerChecked = true;
}
+ if (sineData->timestampCount < MAX_TIMESTAMPS) {
+ Timestamp *timestamp = &sineData->timestamps[sineData->timestampCount];
+ aaudio_result_t result = AAudioStream_getTimestamp(stream,
+ CLOCK_MONOTONIC, ×tamp->position, ×tamp->nanoseconds);
+ if (result == AAUDIO_OK && // valid?
+ (sineData->timestampCount == 0 || // first one?
+ (timestamp->position != (timestamp - 1)->position))) { // advanced position?
+ sineData->timestampCount++; // keep this one
+ }
+ }
+
if (numFrames > sineData->maxNumFrames) {
sineData->maxNumFrames = numFrames;
}
@@ -304,9 +334,16 @@
void SimplePlayerErrorCallbackProc(
AAudioStream *stream __unused,
void *userData __unused,
- aaudio_result_t error)
-{
- printf("Error Callback, error: %d\n",(int)error);
+ aaudio_result_t error) {
+ // should not happen but just in case...
+ if (userData == nullptr) {
+ printf("ERROR - MyPlayerErrorCallbackProc needs userData\n");
+ return;
+ }
+ SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
+ android::status_t ret = sineData->waker.wake(error);
+ printf("Error Callback, error: %d, futex wake returns %d\n", error, ret);
}
+
#endif //AAUDIO_SIMPLE_PLAYER_H
diff --git a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
index 5ecac04..1344273 100644
--- a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
+++ b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
@@ -77,7 +77,7 @@
if (mStream == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
- return AAudioStream_getChannelCount(mStream);
+ return AAudioStream_getChannelCount(mStream);;
}
/**
@@ -187,7 +187,7 @@
// Write zero data to fill up the buffer and prevent underruns.
aaudio_result_t prime() {
- int32_t samplesPerFrame = AAudioStream_getSamplesPerFrame(mStream);
+ int32_t samplesPerFrame = AAudioStream_getChannelCount(mStream);
const int numFrames = 32; // arbitrary
float zeros[numFrames * samplesPerFrame];
memset(zeros, 0, sizeof(zeros));
@@ -260,7 +260,7 @@
}
PeakTrackerData_t *data = (PeakTrackerData_t *) userData;
// printf("MyCallbackProc(): frameCount = %d\n", numFrames);
- int32_t samplesPerFrame = AAudioStream_getSamplesPerFrame(stream);
+ int32_t samplesPerFrame = AAudioStream_getChannelCount(stream);
float sample;
// This code assume mono or stereo.
switch (AAudioStream_getFormat(stream)) {
diff --git a/media/libaaudio/examples/utils/SineGenerator.h b/media/libaaudio/examples/utils/SineGenerator.h
index 64b772d..a755582 100644
--- a/media/libaaudio/examples/utils/SineGenerator.h
+++ b/media/libaaudio/examples/utils/SineGenerator.h
@@ -58,6 +58,13 @@
}
}
+ void setAmplitude(double amplitude) {
+ mAmplitude = amplitude;
+ }
+ double getAmplitude() const {
+ return mAmplitude;
+ }
+
private:
void advancePhase() {
mPhase += mPhaseIncrement;
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index 87fb40b..677fb6c 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -57,7 +57,7 @@
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
- printf("%s - Play a sine wave using AAudio V0.1.1\n", argv[0]);
+ printf("%s - Play a sine wave using AAudio V0.1.2\n", argv[0]);
if (argParser.parseArgs(argc, argv)) {
return EXIT_FAILURE;
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index b5602e9..4f9cde6 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -15,6 +15,7 @@
*/
// Play sine waves using an AAudio callback.
+// If a disconnection occurs then reopen the stream on the new device.
#include <assert.h>
#include <unistd.h>
@@ -22,33 +23,32 @@
#include <sched.h>
#include <stdio.h>
#include <math.h>
+#include <string.h>
#include <time.h>
#include <aaudio/AAudio.h>
#include "AAudioExampleUtils.h"
#include "AAudioSimplePlayer.h"
#include "../../utils/AAudioSimplePlayer.h"
-int main(int argc, const char **argv)
+/**
+ * Open stream, play some sine waves, then close the stream.
+ *
+ * @param argParser
+ * @return AAUDIO_OK or negative error code
+ */
+static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser)
{
- AAudioArgsParser argParser;
- AAudioSimplePlayer player;
SineThreadedData_t myData;
- aaudio_result_t result;
- int32_t actualSampleRate;
+ AAudioSimplePlayer &player = myData.simplePlayer;
+ aaudio_result_t result = AAUDIO_OK;
+ bool disconnected = false;
+ int64_t startedAtNanos;
- // Make printf print immediately so that debug info is not stuck
- // in a buffer if we hang or crash.
- setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
-
- printf("%s - Play a sine sweep using an AAudio callback V0.1.2\n", argv[0]);
-
+ printf("----------------------- run complete test --------------------------\n");
myData.schedulerChecked = false;
+ myData.callbackCount = 0;
myData.forceUnderruns = false; // set true to test AAudioStream_getXRunCount()
- if (argParser.parseArgs(argc, argv)) {
- return EXIT_FAILURE;
- }
-
result = player.open(argParser,
SimplePlayerDataCallbackProc, SimplePlayerErrorCallbackProc, &myData);
if (result != AAUDIO_OK) {
@@ -58,13 +58,19 @@
argParser.compareWithStream(player.getStream());
- actualSampleRate = player.getSampleRate();
- myData.sineOsc1.setup(440.0, actualSampleRate);
- myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
- myData.sineOsc2.setup(660.0, actualSampleRate);
- myData.sineOsc2.setSweep(350.0, 900.0, 7.0);
+ // Setup sine wave generators.
+ {
+ int32_t actualSampleRate = player.getSampleRate();
+ myData.sineOsc1.setup(440.0, actualSampleRate);
+ myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
+ myData.sineOsc1.setAmplitude(0.2);
+ myData.sineOsc2.setup(660.0, actualSampleRate);
+ myData.sineOsc2.setSweep(350.0, 900.0, 7.0);
+ myData.sineOsc2.setAmplitude(0.2);
+ }
#if 0
+ // writes not allowed for callback streams
result = player.prime(); // FIXME crashes AudioTrack.cpp
if (result != AAUDIO_OK) {
fprintf(stderr, "ERROR - player.prime() returned %d\n", result);
@@ -78,34 +84,32 @@
goto error;
}
+ // Play a sine wave in the background.
printf("Sleep for %d seconds while audio plays in a callback thread.\n",
argParser.getDurationSeconds());
+ startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
for (int second = 0; second < argParser.getDurationSeconds(); second++)
{
- const struct timespec request = { .tv_sec = 1, .tv_nsec = 0 };
- (void) clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, &request, NULL /*remain*/);
-
- aaudio_stream_state_t state;
- result = AAudioStream_waitForStateChange(player.getStream(),
- AAUDIO_STREAM_STATE_CLOSED,
- &state,
- 0);
+ // Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
+ long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
+ int64_t millis = (getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
+ result = myData.waker.get();
+ printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
+ ", second = %d, framesWritten = %8d, underruns = %d\n",
+ ret, result, (int) millis,
+ second,
+ (int) AAudioStream_getFramesWritten(player.getStream()),
+ (int) AAudioStream_getXRunCount(player.getStream()));
if (result != AAUDIO_OK) {
- fprintf(stderr, "ERROR - AAudioStream_waitForStateChange() returned %d\n", result);
- goto error;
- }
- if (state != AAUDIO_STREAM_STATE_STARTING && state != AAUDIO_STREAM_STATE_STARTED) {
- printf("Stream state is %d %s!\n", state, AAudio_convertStreamStateToText(state));
+ if (result == AAUDIO_ERROR_DISCONNECTED) {
+ disconnected = true;
+ }
break;
}
- printf("framesWritten = %d, underruns = %d\n",
- (int) AAudioStream_getFramesWritten(player.getStream()),
- (int) AAudioStream_getXRunCount(player.getStream())
- );
}
- printf("Woke up now.\n");
+ printf("AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
- printf("call stop()\n");
+ printf("call stop() callback # = %d\n", myData.callbackCount);
result = player.stop();
if (result != AAUDIO_OK) {
goto error;
@@ -116,6 +120,18 @@
goto error;
}
+ for (int i = 0; i < myData.timestampCount; i++) {
+ Timestamp *timestamp = &myData.timestamps[i];
+ bool retro = (i > 0 &&
+ ((timestamp->position < (timestamp - 1)->position)
+ || ((timestamp->nanoseconds < (timestamp - 1)->nanoseconds))));
+ const char *message = retro ? " <= RETROGRADE!" : "";
+ printf("Timestamp %3d : %8lld, %8lld %s\n", i,
+ (long long) timestamp->position,
+ (long long) timestamp->nanoseconds,
+ message);
+ }
+
if (myData.schedulerChecked) {
printf("scheduler = 0x%08x, SCHED_FIFO = 0x%08X\n",
myData.scheduler,
@@ -126,10 +142,28 @@
printf("max numFrames = %8d\n", (int) myData.maxNumFrames);
printf("SUCCESS\n");
- return EXIT_SUCCESS;
error:
player.close();
- printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
- return EXIT_FAILURE;
+ return disconnected ? AAUDIO_ERROR_DISCONNECTED : result;
}
+int main(int argc, const char **argv)
+{
+ AAudioArgsParser argParser;
+ aaudio_result_t result;
+
+ // Make printf print immediately so that debug info is not stuck
+ // in a buffer if we hang or crash.
+ setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+ printf("%s - Play a sine sweep using an AAudio callback V0.1.2\n", argv[0]);
+
+ if (argParser.parseArgs(argc, argv)) {
+ return EXIT_FAILURE;
+ }
+
+ // Keep looping until we can complete the test without disconnecting.
+ while((result = testOpenPlayClose(argParser)) == AAUDIO_ERROR_DISCONNECTED);
+
+ return (result) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index e1886ac..3c23736 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -234,10 +234,11 @@
int32_t channelCount);
/**
+ * Identical to AAudioStreamBuilder_setChannelCount().
*
- * @deprecated use AAudioStreamBuilder_setChannelCount()
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param samplesPerFrame Number of samples in a frame.
*/
-// TODO remove as soon as the NDK and OS are in sync, before RC1
AAUDIO_API void AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder* builder,
int32_t samplesPerFrame);
@@ -729,11 +730,10 @@
AAUDIO_API int32_t AAudioStream_getChannelCount(AAudioStream* stream);
/**
- * The samplesPerFrame is also known as channelCount.
+ * Identical to AAudioStream_getChannelCount().
*
- * @deprecated use AAudioStream_getChannelCount()
* @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return actual samples per frame
+ * @return actual number of samples frame
*/
AAUDIO_API int32_t AAudioStream_getSamplesPerFrame(AAudioStream* stream);
@@ -810,7 +810,7 @@
* The position and time passed back are monotonically increasing.
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
- * @param clockid AAUDIO_CLOCK_MONOTONIC or AAUDIO_CLOCK_BOOTTIME
+ * @param clockid CLOCK_MONOTONIC or CLOCK_BOOTTIME
* @param framePosition pointer to a variable to receive the position
* @param timeNanoseconds pointer to a variable to receive the time
* @return AAUDIO_OK or a negative error
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
index cfcf27a..6861248 100644
--- a/media/libaaudio/src/Android.mk
+++ b/media/libaaudio/src/Android.mk
@@ -36,7 +36,6 @@
legacy/AudioStreamLegacy.cpp \
legacy/AudioStreamRecord.cpp \
legacy/AudioStreamTrack.cpp \
- utility/HandleTracker.cpp \
utility/AAudioUtilities.cpp \
utility/FixedBlockAdapter.cpp \
utility/FixedBlockReader.cpp \
@@ -95,7 +94,6 @@
legacy/AudioStreamLegacy.cpp \
legacy/AudioStreamRecord.cpp \
legacy/AudioStreamTrack.cpp \
- utility/HandleTracker.cpp \
utility/AAudioUtilities.cpp \
utility/FixedBlockAdapter.cpp \
utility/FixedBlockReader.cpp \
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index a268e49..07ee2de 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -45,6 +45,7 @@
using android::IInterface;
using android::IAAudioService;
using android::Mutex;
+using android::ProcessState;
using android::sp;
using android::wp;
@@ -52,15 +53,19 @@
ANDROID_SINGLETON_STATIC_INSTANCE(AAudioBinderClient);
+// If we don't keep a strong pointer here then this singleton can get deleted!
+android::sp<AAudioBinderClient> gKeepBinderClient;
+
AAudioBinderClient::AAudioBinderClient()
: AAudioServiceInterface()
, Singleton<AAudioBinderClient>() {
-
+ gKeepBinderClient = this; // so this singleton won't get deleted
mAAudioClient = new AAudioClient(this);
- ALOGV("AAudioBinderClient() created mAAudioClient = %p", mAAudioClient.get());
+ ALOGV("AAudioBinderClient() this = %p, created mAAudioClient = %p", this, mAAudioClient.get());
}
AAudioBinderClient::~AAudioBinderClient() {
+ ALOGV("AAudioBinderClient()::~AAudioBinderClient() destroying %p", this);
Mutex::Autolock _l(mServiceLock);
if (mAAudioService != 0) {
IInterface::asBinder(mAAudioService)->unlinkToDeath(mAAudioClient);
@@ -75,19 +80,19 @@
bool needToRegister = false;
{
Mutex::Autolock _l(mServiceLock);
- if (mAAudioService == 0) {
+ if (mAAudioService.get() == nullptr) {
sp<IBinder> binder;
sp<IServiceManager> sm = defaultServiceManager();
// Try several times to get the service.
int retries = 4;
do {
binder = sm->getService(String16(AAUDIO_SERVICE_NAME)); // This will wait a while.
- if (binder != 0) {
+ if (binder.get() != nullptr) {
break;
}
} while (retries-- > 0);
- if (binder != 0) {
+ if (binder.get() != nullptr) {
// Ask for notification if the service dies.
status_t status = binder->linkToDeath(mAAudioClient);
// TODO review what we should do if this fails
@@ -98,7 +103,7 @@
mAAudioService = interface_cast<IAAudioService>(binder);
needToRegister = true;
// Make sure callbacks can be received by mAAudioClient
- android::ProcessState::self()->startThreadPool();
+ ProcessState::self()->startThreadPool();
} else {
ALOGE("AAudioBinderClient could not connect to %s", AAUDIO_SERVICE_NAME);
}
@@ -106,7 +111,7 @@
aaudioService = mAAudioService;
}
// Do this outside the mutex lock.
- if (needToRegister && aaudioService != 0) { // new client?
+ if (needToRegister && aaudioService.get() != nullptr) { // new client?
aaudioService->registerClient(mAAudioClient);
}
return aaudioService;
@@ -117,7 +122,6 @@
mAAudioService.clear(); // force a reconnect
}
-
/**
* @param request info needed to create the stream
* @param configuration contains information about the created stream
@@ -128,14 +132,12 @@
aaudio_handle_t stream;
for (int i = 0; i < 2; i++) {
const sp<IAAudioService> &service = getAAudioService();
- if (service == 0) {
- return AAUDIO_ERROR_NO_SERVICE;
- }
+ if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
stream = service->openStream(request, configurationOutput);
if (stream == AAUDIO_ERROR_NO_SERVICE) {
- ALOGE("AAudioBinderClient: lost connection to AAudioService.");
+ ALOGE("AAudioBinderClient::openStream lost connection to AAudioService.");
dropAAudioService(); // force a reconnect
} else {
break;
@@ -145,8 +147,8 @@
}
aaudio_result_t AAudioBinderClient::closeStream(aaudio_handle_t streamHandle) {
- const sp<IAAudioService> &service = getAAudioService();
- if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ const sp<IAAudioService> service = getAAudioService();
+ if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
return service->closeStream(streamHandle);
}
@@ -155,32 +157,32 @@
*/
aaudio_result_t AAudioBinderClient::getStreamDescription(aaudio_handle_t streamHandle,
AudioEndpointParcelable &parcelable) {
- const sp<IAAudioService> &service = getAAudioService();
- if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ const sp<IAAudioService> service = getAAudioService();
+ if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
return service->getStreamDescription(streamHandle, parcelable);
}
aaudio_result_t AAudioBinderClient::startStream(aaudio_handle_t streamHandle) {
- const sp<IAAudioService> &service = getAAudioService();
- if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ const sp<IAAudioService> service = getAAudioService();
+ if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
return service->startStream(streamHandle);
}
aaudio_result_t AAudioBinderClient::pauseStream(aaudio_handle_t streamHandle) {
- const sp<IAAudioService> &service = getAAudioService();
- if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ const sp<IAAudioService> service = getAAudioService();
+ if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
return service->pauseStream(streamHandle);
}
aaudio_result_t AAudioBinderClient::stopStream(aaudio_handle_t streamHandle) {
- const sp<IAAudioService> &service = getAAudioService();
- if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ const sp<IAAudioService> service = getAAudioService();
+ if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
return service->stopStream(streamHandle);
}
aaudio_result_t AAudioBinderClient::flushStream(aaudio_handle_t streamHandle) {
- const sp<IAAudioService> &service = getAAudioService();
- if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ const sp<IAAudioService> service = getAAudioService();
+ if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
return service->flushStream(streamHandle);
}
@@ -190,8 +192,8 @@
aaudio_result_t AAudioBinderClient::registerAudioThread(aaudio_handle_t streamHandle,
pid_t clientThreadId,
int64_t periodNanoseconds) {
- const sp<IAAudioService> &service = getAAudioService();
- if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ const sp<IAAudioService> service = getAAudioService();
+ if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
return service->registerAudioThread(streamHandle,
clientThreadId,
periodNanoseconds);
@@ -199,8 +201,8 @@
aaudio_result_t AAudioBinderClient::unregisterAudioThread(aaudio_handle_t streamHandle,
pid_t clientThreadId) {
- const sp<IAAudioService> &service = getAAudioService();
- if (service == 0) return AAUDIO_ERROR_NO_SERVICE;
+ const sp<IAAudioService> service = getAAudioService();
+ if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
return service->unregisterAudioThread(streamHandle,
clientThreadId);
}
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
index 89ae85c..f9da8b4 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.h
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -118,13 +118,13 @@
{
public:
AAudioClient(android::wp<AAudioBinderClient> aaudioBinderClient)
- : mBinderClient(aaudioBinderClient) {
+ : mBinderClient(aaudioBinderClient) {
}
// implement DeathRecipient
virtual void binderDied(const android::wp<android::IBinder>& who __unused) {
android::sp<AAudioBinderClient> client = mBinderClient.promote();
- if (client != 0) {
+ if (client.get() != nullptr) {
client->dropAAudioService();
}
ALOGW("AAudio service binderDied()!");
@@ -133,7 +133,7 @@
// implement BnAAudioClient
void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) {
android::sp<AAudioBinderClient> client = mBinderClient.promote();
- if (client != 0) {
+ if (client.get() != nullptr) {
client->onStreamChange(handle, opcode, value);
}
}
@@ -141,10 +141,11 @@
android::wp<AAudioBinderClient> mBinderClient;
};
+private:
- android::Mutex mServiceLock;
+ android::Mutex mServiceLock;
android::sp<android::IAAudioService> mAAudioService;
- android::sp<AAudioClient> mAAudioClient;
+ android::sp<AAudioClient> mAAudioClient;
};
diff --git a/drm/libmediadrm/aidl/android/media/MediaDescrambler.aidl b/media/libaaudio/src/binding/AAudioCommon.h
similarity index 69%
rename from drm/libmediadrm/aidl/android/media/MediaDescrambler.aidl
rename to media/libaaudio/src/binding/AAudioCommon.h
index e789244..e3e9e82 100644
--- a/drm/libmediadrm/aidl/android/media/MediaDescrambler.aidl
+++ b/media/libaaudio/src/binding/AAudioCommon.h
@@ -14,7 +14,19 @@
* limitations under the License.
*/
-package android.media;
+#ifndef ANDROID_AAUDIO_COMMON_H
+#define ANDROID_AAUDIO_COMMON_H
-/** @hide */
-parcelable MediaDescrambler.DescrambleInfo cpp_header "media/MediaCasDefs.h";
\ No newline at end of file
+#include <stdint.h>
+
+/*
+ * Internal header that is common to both client and server.
+ *
+ */
+namespace aaudio {
+
+typedef int32_t aaudio_handle_t;
+
+} /* namespace aaudio */
+
+#endif // ANDROID_AAUDIO_COMMON_H
diff --git a/media/libaaudio/src/binding/AAudioServiceMessage.h b/media/libaaudio/src/binding/AAudioServiceMessage.h
index b4377fb..54e8001 100644
--- a/media/libaaudio/src/binding/AAudioServiceMessage.h
+++ b/media/libaaudio/src/binding/AAudioServiceMessage.h
@@ -28,7 +28,6 @@
// Used to send information about the HAL to the client.
struct AAudioMessageTimestamp {
int64_t position; // number of frames transferred so far
- int64_t deviceOffset; // add to client position to get device position
int64_t timestamp; // time when that position was reached
};
@@ -51,7 +50,8 @@
typedef struct AAudioServiceMessage_s {
enum class code : uint32_t {
NOTHING,
- TIMESTAMP,
+ TIMESTAMP_SERVICE, // when frame is read or written by the service to the client
+ TIMESTAMP_HARDWARE, // when frame is at DAC or ADC
EVENT,
};
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index e763934..153fce3 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -46,6 +46,8 @@
if (status != NO_ERROR) goto error;
status = parcel->writeInt32((int32_t) getFormat());
if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32((int32_t) getDirection());
+ if (status != NO_ERROR) goto error;
status = parcel->writeInt32(getBufferCapacity());
if (status != NO_ERROR) goto error;
return NO_ERROR;
@@ -73,9 +75,12 @@
setFormat(value);
status = parcel->readInt32(&value);
if (status != NO_ERROR) goto error;
+ setDirection((aaudio_direction_t) value);
+ status = parcel->readInt32(&value);
+ if (status != NO_ERROR) goto error;
setBufferCapacity(value);
return NO_ERROR;
error:
ALOGE("AAudioStreamConfiguration.readFromParcel(): read failed = %d", status);
return status;
-}
\ No newline at end of file
+}
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index abdcf5b..1200ab2 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -46,9 +46,6 @@
status_t status = parcel->writeInt32((int32_t) mUserId);
if (status != NO_ERROR) goto error;
- status = parcel->writeInt32((int32_t) mDirection);
- if (status != NO_ERROR) goto error;
-
status = parcel->writeBool(mSharingModeMatchRequired);
if (status != NO_ERROR) goto error;
@@ -71,10 +68,6 @@
if (status != NO_ERROR) goto error;
mUserId = (uid_t) temp;
- status = parcel->readInt32(&temp);
- if (status != NO_ERROR) goto error;
- mDirection = (aaudio_direction_t) temp;
-
status = parcel->readBool(&mSharingModeMatchRequired);
if (status != NO_ERROR) goto error;
@@ -98,7 +91,6 @@
void AAudioStreamRequest::dump() const {
ALOGD("AAudioStreamRequest mUserId = %d", mUserId);
ALOGD("AAudioStreamRequest mProcessId = %d", mProcessId);
- ALOGD("AAudioStreamRequest mDirection = %d", mDirection);
ALOGD("AAudioStreamRequest mSharingModeMatchRequired = %d", mSharingModeMatchRequired);
ALOGD("AAudioStreamRequest mInService = %d", mInService);
mConfiguration.dump();
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
index b0fa96a..492f69d 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.h
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -52,14 +52,6 @@
mProcessId = processId;
}
- aaudio_direction_t getDirection() const {
- return mDirection;
- }
-
- void setDirection(aaudio_direction_t direction) {
- mDirection = direction;
- }
-
bool isSharingModeMatchRequired() const {
return mSharingModeMatchRequired;
}
@@ -94,9 +86,8 @@
protected:
AAudioStreamConfiguration mConfiguration;
- uid_t mUserId;
- pid_t mProcessId;
- aaudio_direction_t mDirection;
+ uid_t mUserId = (uid_t) -1;
+ pid_t mProcessId = (pid_t) -1;
bool mSharingModeMatchRequired = false;
bool mInService = false; // Stream opened by AAudioservice
};
diff --git a/media/libaaudio/src/binding/IAAudioClient.h b/media/libaaudio/src/binding/IAAudioClient.h
index 21cc33b..f21fd93 100644
--- a/media/libaaudio/src/binding/IAAudioClient.h
+++ b/media/libaaudio/src/binding/IAAudioClient.h
@@ -22,7 +22,7 @@
#include <aaudio/AAudio.h>
-#include "utility/HandleTracker.h"
+#include "binding/AAudioCommon.h"
namespace android {
@@ -33,7 +33,7 @@
DECLARE_META_INTERFACE(AAudioClient);
- virtual void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) = 0;
+ virtual void onStreamChange(aaudio::aaudio_handle_t handle, int32_t opcode, int32_t value) = 0;
};
diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
index 30b3ead..6bdb826 100644
--- a/media/libaaudio/src/binding/IAAudioService.h
+++ b/media/libaaudio/src/binding/IAAudioService.h
@@ -24,12 +24,12 @@
#include <aaudio/AAudio.h>
+#include "binding/AAudioCommon.h"
#include "binding/AAudioServiceDefinitions.h"
-#include "binding/AudioEndpointParcelable.h"
-#include "binding/AAudioStreamRequest.h"
#include "binding/AAudioStreamConfiguration.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AudioEndpointParcelable.h"
#include "binding/IAAudioClient.h"
-#include "utility/HandleTracker.h"
namespace android {
@@ -51,7 +51,7 @@
* @param configuration contains information about the created stream
* @return handle to the stream or a negative error
*/
- virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+ virtual aaudio::aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
aaudio::AAudioStreamConfiguration &configurationOutput) = 0;
virtual aaudio_result_t closeStream(aaudio::aaudio_handle_t streamHandle) = 0;
@@ -89,11 +89,11 @@
/**
* Manage the specified thread as a low latency audio thread.
*/
- virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+ virtual aaudio_result_t registerAudioThread(aaudio::aaudio_handle_t streamHandle,
pid_t clientThreadId,
int64_t periodNanoseconds) = 0;
- virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+ virtual aaudio_result_t unregisterAudioThread(aaudio::aaudio_handle_t streamHandle,
pid_t clientThreadId) = 0;
};
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 6ec285f..604eed5 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -32,14 +32,17 @@
#define RIDICULOUSLY_LARGE_FRAME_SIZE 4096
AudioEndpoint::AudioEndpoint()
- : mFreeRunning(false)
+ : mUpCommandQueue(nullptr)
+ , mDataQueue(nullptr)
+ , mFreeRunning(false)
, mDataReadCounter(0)
, mDataWriteCounter(0)
{
}
-AudioEndpoint::~AudioEndpoint()
-{
+AudioEndpoint::~AudioEndpoint() {
+ delete mDataQueue;
+ delete mUpCommandQueue;
}
static aaudio_result_t AudioEndpoint_validateQueueDescriptor(const char *type,
@@ -118,24 +121,28 @@
{
aaudio_result_t result = AudioEndpoint_validateDescriptor(pEndpointDescriptor);
if (result != AAUDIO_OK) {
- ALOGE("AudioEndpoint_validateQueueDescriptor returned %d %s",
- result, AAudio_convertResultToText(result));
return result;
}
// ============================ up message queue =============================
const RingBufferDescriptor *descriptor = &pEndpointDescriptor->upMessageQueueDescriptor;
if(descriptor->bytesPerFrame != sizeof(AAudioServiceMessage)) {
- ALOGE("AudioEndpoint::configure() bytesPerFrame != sizeof(AAudioServiceMessage) = %d",
+ ALOGE("AudioEndpoint.configure() bytesPerFrame != sizeof(AAudioServiceMessage) = %d",
descriptor->bytesPerFrame);
return AAUDIO_ERROR_INTERNAL;
}
if(descriptor->readCounterAddress == nullptr || descriptor->writeCounterAddress == nullptr) {
- ALOGE("AudioEndpoint_validateQueueDescriptor() NULL counter address");
+ ALOGE("AudioEndpoint.configure() NULL counter address");
return AAUDIO_ERROR_NULL;
}
+ // Prevent memory leak and reuse.
+ if(mUpCommandQueue != nullptr || mDataQueue != nullptr) {
+ ALOGE("AudioEndpoint.configure() endpoint already used");
+ return AAUDIO_ERROR_INTERNAL;
+ }
+
mUpCommandQueue = new FifoBuffer(
descriptor->bytesPerFrame,
descriptor->capacityInFrames,
@@ -146,8 +153,8 @@
// ============================ data queue =============================
descriptor = &pEndpointDescriptor->dataQueueDescriptor;
- ALOGV("AudioEndpoint::configure() data framesPerBurst = %d", descriptor->framesPerBurst);
- ALOGV("AudioEndpoint::configure() data readCounterAddress = %p",
+ ALOGV("AudioEndpoint.configure() data framesPerBurst = %d", descriptor->framesPerBurst);
+ ALOGV("AudioEndpoint.configure() data readCounterAddress = %p",
descriptor->readCounterAddress);
// An example of free running is when the other side is read or written by hardware DMA
@@ -156,7 +163,7 @@
? descriptor->readCounterAddress // read by other side
: descriptor->writeCounterAddress; // written by other side
mFreeRunning = (remoteCounter == nullptr);
- ALOGV("AudioEndpoint::configure() mFreeRunning = %d", mFreeRunning ? 1 : 0);
+ ALOGV("AudioEndpoint.configure() mFreeRunning = %d", mFreeRunning ? 1 : 0);
int64_t *readCounterAddress = (descriptor->readCounterAddress == nullptr)
? &mDataReadCounter
@@ -254,3 +261,7 @@
ALOGD("AudioEndpoint: data readCounter = %lld", (long long) mDataQueue->getReadCounter());
ALOGD("AudioEndpoint: data writeCounter = %lld", (long long) mDataQueue->getWriteCounter());
}
+
+void AudioEndpoint::eraseDataMemory() {
+ mDataQueue->eraseMemory();
+}
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
index 81a4f7b..f5b67e8 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -86,6 +86,11 @@
int32_t getBufferCapacityInFrames() const;
+ /**
+ * Write zeros to the data queue memory.
+ */
+ void eraseDataMemory();
+
void dump() const;
private:
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 4c7d0f7..2fdbfaf 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -23,7 +23,6 @@
#define ATRACE_TAG ATRACE_TAG_AUDIO
#include <stdint.h>
-#include <assert.h>
#include <binder/IServiceManager.h>
@@ -55,7 +54,7 @@
// Wait at least this many times longer than the operation should take.
#define MIN_TIMEOUT_OPERATIONS 4
-#define LOG_TIMESTAMPS 0
+#define LOG_TIMESTAMPS 0
AudioStreamInternal::AudioStreamInternal(AAudioServiceInterface &serviceInterface, bool inService)
: AudioStream()
@@ -63,9 +62,9 @@
, mAudioEndpoint()
, mServiceStreamHandle(AAUDIO_HANDLE_INVALID)
, mFramesPerBurst(16)
- , mStreamVolume(1.0f)
, mInService(inService)
, mServiceInterface(serviceInterface)
+ , mAtomicTimestamp()
, mWakeupDelayNanos(AAudioProperty_getWakeupDelayMicros() * AAUDIO_NANOS_PER_MICROSECOND)
, mMinimumSleepNanos(AAudioProperty_getMinimumSleepMicros() * AAUDIO_NANOS_PER_MICROSECOND)
{
@@ -79,9 +78,16 @@
aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) {
aaudio_result_t result = AAUDIO_OK;
+ int32_t capacity;
AAudioStreamRequest request;
- AAudioStreamConfiguration configuration;
+ AAudioStreamConfiguration configurationOutput;
+ if (getState() != AAUDIO_STREAM_STATE_UNINITIALIZED) {
+ ALOGE("AudioStreamInternal::open(): already open! state = %d", getState());
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+
+ // Copy requested parameters to the stream.
result = AudioStream::open(builder);
if (result < 0) {
return result;
@@ -97,103 +103,108 @@
// Build the request to send to the server.
request.setUserId(getuid());
request.setProcessId(getpid());
- request.setDirection(getDirection());
request.setSharingModeMatchRequired(isSharingModeMatchRequired());
request.setInService(mInService);
request.getConfiguration().setDeviceId(getDeviceId());
request.getConfiguration().setSampleRate(getSampleRate());
request.getConfiguration().setSamplesPerFrame(getSamplesPerFrame());
+ request.getConfiguration().setDirection(getDirection());
request.getConfiguration().setSharingMode(getSharingMode());
request.getConfiguration().setBufferCapacity(builder.getBufferCapacity());
- mServiceStreamHandle = mServiceInterface.openStream(request, configuration);
+ mServiceStreamHandle = mServiceInterface.openStream(request, configurationOutput);
if (mServiceStreamHandle < 0) {
result = mServiceStreamHandle;
- ALOGE("AudioStreamInternal.open(): openStream() returned %d", result);
- } else {
- result = configuration.validate();
- if (result != AAUDIO_OK) {
- close();
- return result;
- }
- // Save results of the open.
- setSampleRate(configuration.getSampleRate());
- setSamplesPerFrame(configuration.getSamplesPerFrame());
- setDeviceId(configuration.getDeviceId());
- setSharingMode(configuration.getSharingMode());
-
- // Save device format so we can do format conversion and volume scaling together.
- mDeviceFormat = configuration.getFormat();
-
- result = mServiceInterface.getStreamDescription(mServiceStreamHandle, mEndPointParcelable);
- if (result != AAUDIO_OK) {
- mServiceInterface.closeStream(mServiceStreamHandle);
- return result;
- }
-
- // resolve parcelable into a descriptor
- result = mEndPointParcelable.resolve(&mEndpointDescriptor);
- if (result != AAUDIO_OK) {
- mServiceInterface.closeStream(mServiceStreamHandle);
- return result;
- }
-
- // Configure endpoint based on descriptor.
- mAudioEndpoint.configure(&mEndpointDescriptor, getDirection());
-
- mFramesPerBurst = mEndpointDescriptor.dataQueueDescriptor.framesPerBurst;
- int32_t capacity = mEndpointDescriptor.dataQueueDescriptor.capacityInFrames;
-
- // Validate result from server.
- if (mFramesPerBurst < 16 || mFramesPerBurst > 16 * 1024) {
- ALOGE("AudioStream::open(): framesPerBurst out of range = %d", mFramesPerBurst);
- return AAUDIO_ERROR_OUT_OF_RANGE;
- }
- if (capacity < mFramesPerBurst || capacity > 32 * 1024) {
- ALOGE("AudioStream::open(): bufferCapacity out of range = %d", capacity);
- return AAUDIO_ERROR_OUT_OF_RANGE;
- }
-
- mClockModel.setSampleRate(getSampleRate());
- mClockModel.setFramesPerBurst(mFramesPerBurst);
-
- if (getDataCallbackProc()) {
- mCallbackFrames = builder.getFramesPerDataCallback();
- if (mCallbackFrames > getBufferCapacity() / 2) {
- ALOGE("AudioStreamInternal::open(): framesPerCallback too big = %d, capacity = %d",
- mCallbackFrames, getBufferCapacity());
- mServiceInterface.closeStream(mServiceStreamHandle);
- return AAUDIO_ERROR_OUT_OF_RANGE;
-
- } else if (mCallbackFrames < 0) {
- ALOGE("AudioStreamInternal::open(): framesPerCallback negative");
- mServiceInterface.closeStream(mServiceStreamHandle);
- return AAUDIO_ERROR_OUT_OF_RANGE;
-
- }
- if (mCallbackFrames == AAUDIO_UNSPECIFIED) {
- mCallbackFrames = mFramesPerBurst;
- }
-
- int32_t bytesPerFrame = getSamplesPerFrame()
- * AAudioConvert_formatToSizeInBytes(getFormat());
- int32_t callbackBufferSize = mCallbackFrames * bytesPerFrame;
- mCallbackBuffer = new uint8_t[callbackBufferSize];
- }
-
- setState(AAUDIO_STREAM_STATE_OPEN);
- // only connect to AudioManager if this is a playback stream running in client process
- if (!mInService && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
- init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
- }
+ ALOGE("AudioStreamInternal::open(): openStream() returned %d", result);
+ return result;
}
+
+ result = configurationOutput.validate();
+ if (result != AAUDIO_OK) {
+ goto error;
+ }
+ // Save results of the open.
+ setSampleRate(configurationOutput.getSampleRate());
+ setSamplesPerFrame(configurationOutput.getSamplesPerFrame());
+ setDeviceId(configurationOutput.getDeviceId());
+ setSharingMode(configurationOutput.getSharingMode());
+
+ // Save device format so we can do format conversion and volume scaling together.
+ mDeviceFormat = configurationOutput.getFormat();
+
+ result = mServiceInterface.getStreamDescription(mServiceStreamHandle, mEndPointParcelable);
+ if (result != AAUDIO_OK) {
+ goto error;
+ }
+
+ // Resolve parcelable into a descriptor.
+ result = mEndPointParcelable.resolve(&mEndpointDescriptor);
+ if (result != AAUDIO_OK) {
+ goto error;
+ }
+
+ // Configure endpoint based on descriptor.
+ result = mAudioEndpoint.configure(&mEndpointDescriptor, getDirection());
+ if (result != AAUDIO_OK) {
+ goto error;
+ }
+
+ mFramesPerBurst = mEndpointDescriptor.dataQueueDescriptor.framesPerBurst;
+ capacity = mEndpointDescriptor.dataQueueDescriptor.capacityInFrames;
+
+ // Validate result from server.
+ if (mFramesPerBurst < 16 || mFramesPerBurst > 16 * 1024) {
+ ALOGE("AudioStreamInternal::open(): framesPerBurst out of range = %d", mFramesPerBurst);
+ result = AAUDIO_ERROR_OUT_OF_RANGE;
+ goto error;
+ }
+ if (capacity < mFramesPerBurst || capacity > 32 * 1024) {
+ ALOGE("AudioStreamInternal::open(): bufferCapacity out of range = %d", capacity);
+ result = AAUDIO_ERROR_OUT_OF_RANGE;
+ goto error;
+ }
+
+ mClockModel.setSampleRate(getSampleRate());
+ mClockModel.setFramesPerBurst(mFramesPerBurst);
+
+ if (getDataCallbackProc()) {
+ mCallbackFrames = builder.getFramesPerDataCallback();
+ if (mCallbackFrames > getBufferCapacity() / 2) {
+ ALOGE("AudioStreamInternal::open(): framesPerCallback too big = %d, capacity = %d",
+ mCallbackFrames, getBufferCapacity());
+ result = AAUDIO_ERROR_OUT_OF_RANGE;
+ goto error;
+
+ } else if (mCallbackFrames < 0) {
+ ALOGE("AudioStreamInternal::open(): framesPerCallback negative");
+ result = AAUDIO_ERROR_OUT_OF_RANGE;
+ goto error;
+
+ }
+ if (mCallbackFrames == AAUDIO_UNSPECIFIED) {
+ mCallbackFrames = mFramesPerBurst;
+ }
+
+ int32_t bytesPerFrame = getSamplesPerFrame()
+ * AAudioConvert_formatToSizeInBytes(getFormat());
+ int32_t callbackBufferSize = mCallbackFrames * bytesPerFrame;
+ mCallbackBuffer = new uint8_t[callbackBufferSize];
+ }
+
+ setState(AAUDIO_STREAM_STATE_OPEN);
+
+ return result;
+
+error:
+ close();
return result;
}
aaudio_result_t AudioStreamInternal::close() {
- ALOGD("AudioStreamInternal::close(): mServiceStreamHandle = 0x%08X",
+ aaudio_result_t result = AAUDIO_OK;
+ ALOGD("close(): mServiceStreamHandle = 0x%08X",
mServiceStreamHandle);
if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
// Don't close a stream while it is running.
@@ -202,10 +213,10 @@
requestStop();
aaudio_stream_state_t nextState;
int64_t timeoutNanoseconds = MIN_TIMEOUT_NANOS;
- aaudio_result_t result = waitForStateChange(currentState, &nextState,
+ result = waitForStateChange(currentState, &nextState,
timeoutNanoseconds);
if (result != AAUDIO_OK) {
- ALOGE("AudioStreamInternal::close() waitForStateChange() returned %d %s",
+ ALOGE("close() waitForStateChange() returned %d %s",
result, AAudio_convertResultToText(result));
}
}
@@ -216,14 +227,16 @@
mServiceInterface.closeStream(serviceStreamHandle);
delete[] mCallbackBuffer;
mCallbackBuffer = nullptr;
+
setState(AAUDIO_STREAM_STATE_CLOSED);
- return mEndPointParcelable.close();
+ result = mEndPointParcelable.close();
+ aaudio_result_t result2 = AudioStream::close();
+ return (result != AAUDIO_OK) ? result : result2;
} else {
return AAUDIO_ERROR_INVALID_HANDLE;
}
}
-
static void *aaudio_callback_thread_proc(void *context)
{
AudioStreamInternal *stream = (AudioStreamInternal *)context;
@@ -235,24 +248,46 @@
}
}
+/*
+ * It normally takes about 20-30 msec to start a stream on the server.
+ * But the first time can take as much as 200-300 msec. The HW
+ * starts right away so by the time the client gets a chance to write into
+ * the buffer, it is already in a deep underflow state. That can cause the
+ * XRunCount to be non-zero, which could lead an app to tune its latency higher.
+ * To avoid this problem, we set a request for the processing code to start the
+ * client stream at the same position as the server stream.
+ * The processing code will then save the current offset
+ * between client and server and apply that to any position given to the app.
+ */
aaudio_result_t AudioStreamInternal::requestStart()
{
int64_t startTime;
- ALOGD("AudioStreamInternal()::requestStart()");
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+ ALOGE("requestStart() mServiceStreamHandle invalid");
return AAUDIO_ERROR_INVALID_STATE;
}
if (isActive()) {
+ ALOGE("requestStart() already active");
return AAUDIO_ERROR_INVALID_STATE;
}
- aaudio_stream_state_t originalState = getState();
+ aaudio_stream_state_t originalState = getState();
+ if (originalState == AAUDIO_STREAM_STATE_DISCONNECTED) {
+ ALOGE("requestStart() but DISCONNECTED");
+ return AAUDIO_ERROR_DISCONNECTED;
+ }
setState(AAUDIO_STREAM_STATE_STARTING);
- aaudio_result_t result = AAudioConvert_androidToAAudioResult(startWithStatus());
+
+ // Clear any stale timestamps from the previous run.
+ drainTimestampsFromService();
+
+ aaudio_result_t result = mServiceInterface.startStream(mServiceStreamHandle);
startTime = AudioClock::getNanoseconds();
mClockModel.start(startTime);
+ mNeedCatchUp.request(); // Ask data processing code to catch up when first timestamp received.
+ // Start data callback thread.
if (result == AAUDIO_OK && getDataCallbackProc() != nullptr) {
// Launch the callback loop thread.
int64_t periodNanos = mCallbackFrames
@@ -297,14 +332,16 @@
aaudio_result_t AudioStreamInternal::requestStopInternal()
{
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
- ALOGE("AudioStreamInternal::requestStopInternal() mServiceStreamHandle invalid = 0x%08X",
+ ALOGE("requestStopInternal() mServiceStreamHandle invalid = 0x%08X",
mServiceStreamHandle);
return AAUDIO_ERROR_INVALID_STATE;
}
mClockModel.stop(AudioClock::getNanoseconds());
setState(AAUDIO_STREAM_STATE_STOPPING);
- return AAudioConvert_androidToAAudioResult(stopWithStatus());
+ mAtomicTimestamp.clear();
+
+ return mServiceInterface.stopStream(mServiceStreamHandle);
}
aaudio_result_t AudioStreamInternal::requestStop()
@@ -319,6 +356,7 @@
aaudio_result_t AudioStreamInternal::registerThread() {
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+ ALOGE("registerThread() mServiceStreamHandle invalid");
return AAUDIO_ERROR_INVALID_STATE;
}
return mServiceInterface.registerAudioThread(mServiceStreamHandle,
@@ -328,6 +366,7 @@
aaudio_result_t AudioStreamInternal::unregisterThread() {
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+ ALOGE("unregisterThread() mServiceStreamHandle invalid");
return AAUDIO_ERROR_INVALID_STATE;
}
return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, gettid());
@@ -338,6 +377,7 @@
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
return AAUDIO_ERROR_INVALID_STATE;
}
+
return mServiceInterface.startClient(mServiceStreamHandle, client, clientHandle);
}
@@ -351,15 +391,20 @@
aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId,
int64_t *framePosition,
int64_t *timeNanoseconds) {
- // TODO Generate in server and pass to client. Return latest.
- int64_t time = AudioClock::getNanoseconds();
- *framePosition = mClockModel.convertTimeToPosition(time) + mFramesOffsetFromService;
- // TODO Get a more accurate timestamp from the service. This code just adds a fudge factor.
- *timeNanoseconds = time + (6 * AAUDIO_NANOS_PER_MILLISECOND);
- return AAUDIO_OK;
+ // Generated in server and passed to client. Return latest.
+ if (mAtomicTimestamp.isValid()) {
+ Timestamp timestamp = mAtomicTimestamp.read();
+ int64_t position = timestamp.getPosition() + mFramesOffsetFromService;
+ if (position >= 0) {
+ *framePosition = position;
+ *timeNanoseconds = timestamp.getNanoseconds();
+ return AAUDIO_OK;
+ }
+ }
+ return AAUDIO_ERROR_INVALID_STATE;
}
-aaudio_result_t AudioStreamInternal::updateStateWhileWaiting() {
+aaudio_result_t AudioStreamInternal::updateStateMachine() {
if (isDataCallbackActive()) {
return AAUDIO_OK; // state is getting updated by the callback thread read/write call
}
@@ -371,21 +416,21 @@
static int64_t oldTime = 0;
int64_t framePosition = command.timestamp.position;
int64_t nanoTime = command.timestamp.timestamp;
- ALOGD("AudioStreamInternal: timestamp says framePosition = %08lld at nanoTime %lld",
+ ALOGD("logTimestamp: timestamp says framePosition = %8lld at nanoTime %lld",
(long long) framePosition,
(long long) nanoTime);
int64_t nanosDelta = nanoTime - oldTime;
if (nanosDelta > 0 && oldTime > 0) {
int64_t framesDelta = framePosition - oldPosition;
int64_t rate = (framesDelta * AAUDIO_NANOS_PER_SECOND) / nanosDelta;
- ALOGD("AudioStreamInternal: framesDelta = %08lld, nanosDelta = %08lld, rate = %lld",
+ ALOGD("logTimestamp: framesDelta = %8lld, nanosDelta = %8lld, rate = %lld",
(long long) framesDelta, (long long) nanosDelta, (long long) rate);
}
oldPosition = framePosition;
oldTime = nanoTime;
}
-aaudio_result_t AudioStreamInternal::onTimestampFromServer(AAudioServiceMessage *message) {
+aaudio_result_t AudioStreamInternal::onTimestampService(AAudioServiceMessage *message) {
#if LOG_TIMESTAMPS
logTimestamp(*message);
#endif
@@ -393,23 +438,29 @@
return AAUDIO_OK;
}
+aaudio_result_t AudioStreamInternal::onTimestampHardware(AAudioServiceMessage *message) {
+ Timestamp timestamp(message->timestamp.position, message->timestamp.timestamp);
+ mAtomicTimestamp.write(timestamp);
+ return AAUDIO_OK;
+}
+
aaudio_result_t AudioStreamInternal::onEventFromServer(AAudioServiceMessage *message) {
aaudio_result_t result = AAUDIO_OK;
switch (message->event.event) {
case AAUDIO_SERVICE_EVENT_STARTED:
- ALOGD("AudioStreamInternal::onEventFromServergot() AAUDIO_SERVICE_EVENT_STARTED");
+ ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_STARTED");
if (getState() == AAUDIO_STREAM_STATE_STARTING) {
setState(AAUDIO_STREAM_STATE_STARTED);
}
break;
case AAUDIO_SERVICE_EVENT_PAUSED:
- ALOGD("AudioStreamInternal::onEventFromServergot() AAUDIO_SERVICE_EVENT_PAUSED");
+ ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_PAUSED");
if (getState() == AAUDIO_STREAM_STATE_PAUSING) {
setState(AAUDIO_STREAM_STATE_PAUSED);
}
break;
case AAUDIO_SERVICE_EVENT_STOPPED:
- ALOGD("AudioStreamInternal::onEventFromServergot() AAUDIO_SERVICE_EVENT_STOPPED");
+ ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_STOPPED");
if (getState() == AAUDIO_STREAM_STATE_STOPPING) {
setState(AAUDIO_STREAM_STATE_STOPPED);
}
@@ -426,10 +477,14 @@
setState(AAUDIO_STREAM_STATE_CLOSED);
break;
case AAUDIO_SERVICE_EVENT_DISCONNECTED:
+ // Prevent hardware from looping on old data and making buzzing sounds.
+ if (getDirection() == AAUDIO_DIRECTION_OUTPUT) {
+ mAudioEndpoint.eraseDataMemory();
+ }
result = AAUDIO_ERROR_DISCONNECTED;
setState(AAUDIO_STREAM_STATE_DISCONNECTED);
ALOGW("WARNING - AudioStreamInternal::onEventFromServer()"
- " AAUDIO_SERVICE_EVENT_DISCONNECTED");
+ " AAUDIO_SERVICE_EVENT_DISCONNECTED - FIFO cleared");
break;
case AAUDIO_SERVICE_EVENT_VOLUME:
mStreamVolume = (float)message->event.dataDouble;
@@ -445,6 +500,34 @@
return result;
}
+aaudio_result_t AudioStreamInternal::drainTimestampsFromService() {
+ aaudio_result_t result = AAUDIO_OK;
+
+ while (result == AAUDIO_OK) {
+ AAudioServiceMessage message;
+ if (mAudioEndpoint.readUpCommand(&message) != 1) {
+ break; // no command this time, no problem
+ }
+ switch (message.what) {
+ // ignore most messages
+ case AAudioServiceMessage::code::TIMESTAMP_SERVICE:
+ case AAudioServiceMessage::code::TIMESTAMP_HARDWARE:
+ break;
+
+ case AAudioServiceMessage::code::EVENT:
+ result = onEventFromServer(&message);
+ break;
+
+ default:
+ ALOGE("WARNING - drainTimestampsFromService() Unrecognized what = %d",
+ (int) message.what);
+ result = AAUDIO_ERROR_INTERNAL;
+ break;
+ }
+ }
+ return result;
+}
+
// Process all the commands coming from the server.
aaudio_result_t AudioStreamInternal::processCommands() {
aaudio_result_t result = AAUDIO_OK;
@@ -456,8 +539,12 @@
break; // no command this time, no problem
}
switch (message.what) {
- case AAudioServiceMessage::code::TIMESTAMP:
- result = onTimestampFromServer(&message);
+ case AAudioServiceMessage::code::TIMESTAMP_SERVICE:
+ result = onTimestampService(&message);
+ break;
+
+ case AAudioServiceMessage::code::TIMESTAMP_HARDWARE:
+ result = onTimestampHardware(&message);
break;
case AAudioServiceMessage::code::EVENT:
@@ -465,7 +552,7 @@
break;
default:
- ALOGE("WARNING - AudioStreamInternal::processCommands() Unrecognized what = %d",
+ ALOGE("WARNING - processCommands() Unrecognized what = %d",
(int) message.what);
result = AAUDIO_ERROR_INTERNAL;
break;
@@ -517,12 +604,19 @@
wakeTimeNanos += mWakeupDelayNanos;
}
+ currentTimeNanos = AudioClock::getNanoseconds();
+ int64_t earliestWakeTime = currentTimeNanos + mMinimumSleepNanos;
+ // Guarantee a minimum sleep time.
+ if (wakeTimeNanos < earliestWakeTime) {
+ wakeTimeNanos = earliestWakeTime;
+ }
+
if (wakeTimeNanos > deadlineNanos) {
// If we time out, just return the framesWritten so far.
// TODO remove after we fix the deadline bug
ALOGW("AudioStreamInternal::processData(): entered at %lld nanos, currently %lld",
(long long) entryTimeNanos, (long long) currentTimeNanos);
- ALOGW("AudioStreamInternal::processData(): timed out after %lld nanos",
+ ALOGW("AudioStreamInternal::processData(): TIMEOUT after %lld nanos",
(long long) timeoutNanoseconds);
ALOGW("AudioStreamInternal::processData(): wakeTime = %lld, deadline = %lld nanos",
(long long) wakeTimeNanos, (long long) deadlineNanos);
@@ -533,13 +627,6 @@
break;
}
- currentTimeNanos = AudioClock::getNanoseconds();
- int64_t earliestWakeTime = currentTimeNanos + mMinimumSleepNanos;
- // Guarantee a minimum sleep time.
- if (wakeTimeNanos < earliestWakeTime) {
- wakeTimeNanos = earliestWakeTime;
- }
-
if (ATRACE_ENABLED()) {
int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable();
ATRACE_INT(fifoName, fullFrames);
@@ -576,7 +663,7 @@
}
aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(requestedFrames, &actualFrames);
- ALOGD("AudioStreamInternal::setBufferSize() req = %d => %d", requestedFrames, actualFrames);
+ ALOGD("setBufferSize() req = %d => %d", requestedFrames, actualFrames);
if (result < 0) {
return result;
} else {
@@ -599,32 +686,3 @@
aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) {
return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst()));
}
-
-void AudioStreamInternal::doSetVolume() {
- // No pan and only left volume is taken into account from IPLayer interface
- mVolumeRamp.setTarget(mStreamVolume * mVolumeMultiplierL /* * mPanMultiplierL */);
-}
-
-
-//------------------------------------------------------------------------------
-// Implementation of PlayerBase
-status_t AudioStreamInternal::playerStart() {
- return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.startStream(mServiceStreamHandle));
-}
-
-status_t AudioStreamInternal::playerPause() {
- return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.pauseStream(mServiceStreamHandle));
-}
-
-status_t AudioStreamInternal::playerStop() {
- return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.stopStream(mServiceStreamHandle));
-}
-
-status_t AudioStreamInternal::playerSetVolume() {
- doSetVolume();
- return NO_ERROR;
-}
-
-void AudioStreamInternal::destroy() {
- baseDestroy();
-}
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 1b991de..47024c0 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -18,7 +18,6 @@
#define ANDROID_AAUDIO_AUDIO_STREAM_INTERNAL_H
#include <stdint.h>
-#include <media/PlayerBase.h>
#include <aaudio/AAudio.h>
#include "binding/IAAudioService.h"
@@ -36,7 +35,7 @@
namespace aaudio {
// A stream that talks to the AAudioService or directly to a HAL.
-class AudioStreamInternal : public AudioStream, public android::PlayerBase {
+class AudioStreamInternal : public AudioStream {
public:
AudioStreamInternal(AAudioServiceInterface &serviceInterface, bool inService);
@@ -50,7 +49,7 @@
int64_t *framePosition,
int64_t *timeNanoseconds) override;
- virtual aaudio_result_t updateStateWhileWaiting() override;
+ virtual aaudio_result_t updateStateMachine() override;
aaudio_result_t open(const AudioStreamBuilder &builder) override;
@@ -85,14 +84,15 @@
// Calculate timeout based on framesPerBurst
int64_t calculateReasonableTimeout();
- //PlayerBase virtuals
- virtual void destroy();
-
aaudio_result_t startClient(const android::AudioClient& client,
audio_port_handle_t *clientHandle);
aaudio_result_t stopClient(audio_port_handle_t clientHandle);
+ aaudio_handle_t getServiceHandle() const {
+ return mServiceStreamHandle;
+ }
+
protected:
aaudio_result_t processData(void *buffer,
@@ -111,32 +111,29 @@
int64_t currentTimeNanos,
int64_t *wakeTimePtr) = 0;
+ aaudio_result_t drainTimestampsFromService();
+
aaudio_result_t processCommands();
aaudio_result_t requestStopInternal();
aaudio_result_t stopCallback();
+ virtual void advanceClientToMatchServerPosition() = 0;
virtual void onFlushFromServer() {}
aaudio_result_t onEventFromServer(AAudioServiceMessage *message);
- aaudio_result_t onTimestampFromServer(AAudioServiceMessage *message);
+ aaudio_result_t onTimestampService(AAudioServiceMessage *message);
+
+ aaudio_result_t onTimestampHardware(AAudioServiceMessage *message);
void logTimestamp(AAudioServiceMessage &message);
// Calculate timeout for an operation involving framesPerOperation.
int64_t calculateReasonableTimeout(int32_t framesPerOperation);
- void doSetVolume();
-
- //PlayerBase virtuals
- virtual status_t playerStart();
- virtual status_t playerPause();
- virtual status_t playerStop();
- virtual status_t playerSetVolume();
-
aaudio_format_t mDeviceFormat = AAUDIO_FORMAT_UNSPECIFIED;
IsochronousClockModel mClockModel; // timing model for chasing the HAL
@@ -147,9 +144,6 @@
int32_t mFramesPerBurst; // frames per HAL transfer
int32_t mXRunCount = 0; // how many underrun events?
- LinearRamp mVolumeRamp;
- float mStreamVolume;
-
// Offset from underlying frame position.
int64_t mFramesOffsetFromService = 0; // offset for timestamps
@@ -161,6 +155,12 @@
AAudioServiceInterface &mServiceInterface; // abstract interface to the service
+ SimpleDoubleBuffer<Timestamp> mAtomicTimestamp;
+
+ AtomicRequestor mNeedCatchUp; // Ask read() or write() to sync on first timestamp.
+
+ float mStreamVolume = 1.0f;
+
private:
/*
* Asynchronous write with data conversion.
@@ -181,6 +181,8 @@
AudioEndpointParcelable mEndPointParcelable; // description of the buffers filled by service
EndpointDescriptor mEndpointDescriptor; // buffer description with resolved addresses
+
+ int64_t mServiceLatencyNanos = 0;
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 7b1e53e..b792ecd 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -39,6 +39,21 @@
AudioStreamInternalCapture::~AudioStreamInternalCapture() {}
+void AudioStreamInternalCapture::advanceClientToMatchServerPosition() {
+ int64_t readCounter = mAudioEndpoint.getDataReadCounter();
+ int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
+
+ // Bump offset so caller does not see the retrograde motion in getFramesRead().
+ int64_t offset = readCounter - writeCounter;
+ mFramesOffsetFromService += offset;
+ ALOGD("advanceClientToMatchServerPosition() readN = %lld, writeN = %lld, offset = %lld",
+ (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
+
+ // Force readCounter to match writeCounter.
+ // This is because we cannot change the write counter in the hardware.
+ mAudioEndpoint.setDataReadCounter(writeCounter);
+}
+
// Write the data, block if needed and timeoutMillis > 0
aaudio_result_t AudioStreamInternalCapture::read(void *buffer, int32_t numFrames,
int64_t timeoutNanoseconds)
@@ -57,6 +72,18 @@
const char *traceName = "aaRdNow";
ATRACE_BEGIN(traceName);
+ if (mClockModel.isStarting()) {
+ // Still haven't got any timestamps from server.
+ // Keep waiting until we get some valid timestamps then start writing to the
+ // current buffer position.
+ ALOGD("processDataNow() wait for valid timestamps");
+ // Sleep very briefly and hope we get a timestamp soon.
+ *wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
+ ATRACE_END();
+ return 0;
+ }
+ // If we have gotten this far then we have at least one timestamp from server.
+
if (mAudioEndpoint.isFreeRunning()) {
//ALOGD("AudioStreamInternalCapture::processDataNow() - update remote counter");
// Update data queue based on the timing model.
@@ -65,6 +92,14 @@
mAudioEndpoint.setDataWriteCounter(estimatedRemoteCounter);
}
+ // This code assumes that we have already received valid timestamps.
+ if (mNeedCatchUp.isRequested()) {
+ // Catch an MMAP pointer that is already advancing.
+ // This will avoid initial underruns caused by a slow cold start.
+ advanceClientToMatchServerPosition();
+ mNeedCatchUp.acknowledge();
+ }
+
// If the write index passed the read index then consider it an overrun.
if (mAudioEndpoint.getEmptyFramesAvailable() < 0) {
mXRunCount++;
@@ -100,8 +135,8 @@
// Calculate frame position based off of the readCounter because
// the writeCounter might have just advanced in the background,
// causing us to sleep until a later burst.
- int64_t nextReadPosition = mAudioEndpoint.getDataReadCounter() + mFramesPerBurst;
- wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
+ int64_t nextPosition = mAudioEndpoint.getDataReadCounter() + mFramesPerBurst;
+ wakeTime = mClockModel.convertPositionToTime(nextPosition);
}
break;
default:
@@ -186,8 +221,7 @@
}
int64_t AudioStreamInternalCapture::getFramesRead() {
- int64_t frames = mAudioEndpoint.getDataWriteCounter()
- + mFramesOffsetFromService;
+ int64_t frames = mAudioEndpoint.getDataReadCounter() + mFramesOffsetFromService;
//ALOGD("AudioStreamInternalCapture::getFramesRead() returns %lld", (long long)frames);
return frames;
}
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.h b/media/libaaudio/src/client/AudioStreamInternalCapture.h
index 17f37e8..294dbaf 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.h
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.h
@@ -46,6 +46,8 @@
}
protected:
+ void advanceClientToMatchServerPosition() override;
+
/**
* Low level data processing that will not block. It will just read or write as much as it can.
*
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 31e0a40..1e02eee 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -48,7 +48,8 @@
mClockModel.stop(AudioClock::getNanoseconds());
setState(AAUDIO_STREAM_STATE_PAUSING);
- return AAudioConvert_androidToAAudioResult(pauseWithStatus());
+ mAtomicTimestamp.clear();
+ return mServiceInterface.pauseStream(mServiceStreamHandle);
}
aaudio_result_t AudioStreamInternalPlay::requestPause()
@@ -72,21 +73,25 @@
return mServiceInterface.flushStream(mServiceStreamHandle);
}
-void AudioStreamInternalPlay::onFlushFromServer() {
+void AudioStreamInternalPlay::advanceClientToMatchServerPosition() {
int64_t readCounter = mAudioEndpoint.getDataReadCounter();
int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
// Bump offset so caller does not see the retrograde motion in getFramesRead().
- int64_t framesFlushed = writeCounter - readCounter;
- mFramesOffsetFromService += framesFlushed;
- ALOGD("AudioStreamInternal::onFlushFromServer() readN = %lld, writeN = %lld, offset = %lld",
+ int64_t offset = writeCounter - readCounter;
+ mFramesOffsetFromService += offset;
+ ALOGD("advanceClientToMatchServerPosition() readN = %lld, writeN = %lld, offset = %lld",
(long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
- // Flush written frames by forcing writeCounter to readCounter.
- // This is because we cannot move the read counter in the hardware.
+ // Force writeCounter to match readCounter.
+ // This is because we cannot change the read counter in the hardware.
mAudioEndpoint.setDataWriteCounter(readCounter);
}
+void AudioStreamInternalPlay::onFlushFromServer() {
+ advanceClientToMatchServerPosition();
+}
+
// Write the data, block if needed and timeoutMillis > 0
aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames,
int64_t timeoutNanoseconds)
@@ -106,6 +111,18 @@
const char *traceName = "aaWrNow";
ATRACE_BEGIN(traceName);
+ if (mClockModel.isStarting()) {
+ // Still haven't got any timestamps from server.
+ // Keep waiting until we get some valid timestamps then start writing to the
+ // current buffer position.
+ ALOGD("processDataNow() wait for valid timestamps");
+ // Sleep very briefly and hope we get a timestamp soon.
+ *wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
+ ATRACE_END();
+ return 0;
+ }
+ // If we have gotten this far then we have at least one timestamp from server.
+
// If a DMA channel or DSP is reading the other end then we have to update the readCounter.
if (mAudioEndpoint.isFreeRunning()) {
// Update data queue based on the timing model.
@@ -114,6 +131,13 @@
mAudioEndpoint.setDataReadCounter(estimatedReadCounter);
}
+ if (mNeedCatchUp.isRequested()) {
+ // Catch an MMAP pointer that is already advancing.
+ // This will avoid initial underruns caused by a slow cold start.
+ advanceClientToMatchServerPosition();
+ mNeedCatchUp.acknowledge();
+ }
+
// If the read index passed the write index then consider it an underrun.
if (mAudioEndpoint.getFullFramesAvailable() < 0) {
mXRunCount++;
@@ -153,9 +177,9 @@
// Calculate frame position based off of the writeCounter because
// the readCounter might have just advanced in the background,
// causing us to sleep until a later burst.
- int64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
+ int64_t nextPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
- mAudioEndpoint.getBufferSizeInFrames();
- wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
+ wakeTime = mClockModel.convertPositionToTime(nextPosition);
}
break;
default:
@@ -266,7 +290,6 @@
return framesWritten;
}
-
int64_t AudioStreamInternalPlay::getFramesRead()
{
int64_t framesReadHardware;
@@ -340,3 +363,10 @@
result, (int) isActive());
return NULL;
}
+
+//------------------------------------------------------------------------------
+// Implementation of PlayerBase
+status_t AudioStreamInternalPlay::doSetVolume() {
+ mVolumeRamp.setTarget(mStreamVolume * getDuckAndMuteVolume());
+ return android::NO_ERROR;
+}
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h
index e59d02c..d5c1b1e 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.h
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h
@@ -54,8 +54,12 @@
aaudio_result_t requestPauseInternal();
+ void advanceClientToMatchServerPosition() override;
+
void onFlushFromServer() override;
+ android::status_t doSetVolume() override;
+
/**
* Low level write that will not block. It will just write as much as it can.
*
@@ -78,6 +82,9 @@
int32_t numFrames);
int64_t mLastFramesRead = 0; // used to prevent retrograde motion
+
+ LinearRamp mVolumeRamp;
+
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index 4d0a7b8..bac69f1 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "AAudio"
//#define LOG_NDEBUG 0
-#include <utils/Log.h>
+#include <log/log.h>
#include <stdint.h>
@@ -25,7 +25,6 @@
#define MIN_LATENESS_NANOS (10 * AAUDIO_NANOS_PER_MICROSECOND)
-using namespace android;
using namespace aaudio;
IsochronousClockModel::IsochronousClockModel()
@@ -49,19 +48,26 @@
}
void IsochronousClockModel::start(int64_t nanoTime) {
- ALOGD("IsochronousClockModel::start(nanos = %lld)\n", (long long) nanoTime);
+ ALOGV("IsochronousClockModel::start(nanos = %lld)\n", (long long) nanoTime);
mMarkerNanoTime = nanoTime;
mState = STATE_STARTING;
}
void IsochronousClockModel::stop(int64_t nanoTime) {
- ALOGD("IsochronousClockModel::stop(nanos = %lld)\n", (long long) nanoTime);
+ ALOGV("IsochronousClockModel::stop(nanos = %lld)\n", (long long) nanoTime);
setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime);
// TODO should we set position?
mState = STATE_STOPPED;
}
+bool IsochronousClockModel::isStarting() {
+ return mState == STATE_STARTING;
+}
+
void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nanoTime) {
+// ALOGD("processTimestamp() - framePosition = %lld at nanoTime %llu",
+// (long long)framePosition,
+// (long long)nanoTime);
int64_t framesDelta = framePosition - mMarkerFramePosition;
int64_t nanosDelta = nanoTime - mMarkerNanoTime;
if (nanosDelta < 1000) {
@@ -71,9 +77,6 @@
// ALOGD("processTimestamp() - mMarkerFramePosition = %lld at mMarkerNanoTime %llu",
// (long long)mMarkerFramePosition,
// (long long)mMarkerNanoTime);
-// ALOGD("processTimestamp() - framePosition = %lld at nanoTime %llu",
-// (long long)framePosition,
-// (long long)nanoTime);
int64_t expectedNanosDelta = convertDeltaPositionToTime(framesDelta);
// ALOGD("processTimestamp() - expectedNanosDelta = %lld, nanosDelta = %llu",
@@ -117,6 +120,8 @@
default:
break;
}
+
+// ALOGD("processTimestamp() - mState = %d", mState);
}
void IsochronousClockModel::setSampleRate(int32_t sampleRate) {
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index 585f53a..7182376 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -36,6 +36,8 @@
void start(int64_t nanoTime);
void stop(int64_t nanoTime);
+ bool isStarting();
+
void processTimestamp(int64_t framePosition, int64_t nanoTime);
/**
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 3f5de77..1eaee81 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -24,15 +24,14 @@
#include <aaudio/AAudio.h>
#include <aaudio/AAudioTesting.h>
+#include "AudioClock.h"
#include "AudioStreamBuilder.h"
#include "AudioStream.h"
-#include "AudioClock.h"
+#include "binding/AAudioCommon.h"
#include "client/AudioStreamInternal.h"
-#include "HandleTracker.h"
using namespace aaudio;
-
// Macros for common code that includes a return.
// TODO Consider using do{}while(0) construct. I tried but it hung AndroidStudio
#define CONVERT_BUILDER_HANDLE_OR_RETURN() \
@@ -101,7 +100,6 @@
*/
static aaudio_policy_t s_MMapPolicy = AAUDIO_UNSPECIFIED;
-
static AudioStream *convertAAudioStreamToAudioStream(AAudioStream* stream)
{
return (AudioStream*) stream;
@@ -144,17 +142,16 @@
}
AAUDIO_API void AAudioStreamBuilder_setChannelCount(AAudioStreamBuilder* builder,
- int32_t channelCount)
+ int32_t channelCount)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setSamplesPerFrame(channelCount);
}
AAUDIO_API void AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder* builder,
- int32_t samplesPerFrame)
+ int32_t channelCount)
{
- AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
- streamBuilder->setSamplesPerFrame(samplesPerFrame);
+ AAudioStreamBuilder_setChannelCount(builder, channelCount);
}
AAUDIO_API void AAudioStreamBuilder_setDirection(AAudioStreamBuilder* builder,
@@ -221,6 +218,7 @@
ALOGD("AAudioStreamBuilder_openStream() returns %d = %s for (%p) ----------------",
result, AAudio_convertResultToText(result), audioStream);
if (result == AAUDIO_OK) {
+ audioStream->registerPlayerBase();
*streamPtr = (AAudioStream*) audioStream;
} else {
*streamPtr = nullptr;
@@ -244,6 +242,7 @@
ALOGD("AAudioStream_close(%p)", stream);
if (audioStream != nullptr) {
audioStream->close();
+ audioStream->unregisterPlayerBase();
delete audioStream;
return AAUDIO_OK;
}
@@ -254,8 +253,8 @@
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
ALOGD("AAudioStream_requestStart(%p) called --------------", stream);
- aaudio_result_t result = audioStream->requestStart();
- ALOGD("AAudioStream_requestStart(%p) returned ------------", stream);
+ aaudio_result_t result = audioStream->systemStart();
+ ALOGD("AAudioStream_requestStart(%p) returned %d ---------", stream, result);
return result;
}
@@ -263,7 +262,7 @@
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
ALOGD("AAudioStream_requestPause(%p)", stream);
- return audioStream->requestPause();
+ return audioStream->systemPause();
}
AAUDIO_API aaudio_result_t AAudioStream_requestFlush(AAudioStream* stream)
@@ -277,7 +276,7 @@
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
ALOGD("AAudioStream_requestStop(%p)", stream);
- return audioStream->requestStop();
+ return audioStream->systemStop();
}
AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream* stream,
@@ -359,8 +358,7 @@
AAUDIO_API int32_t AAudioStream_getSamplesPerFrame(AAudioStream* stream)
{
- AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
- return audioStream->getSamplesPerFrame();
+ return AAudioStream_getChannelCount(stream);
}
AAUDIO_API aaudio_stream_state_t AAudioStream_getState(AAudioStream* stream)
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 65c2b46..82445e7 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -34,6 +34,16 @@
AAudioStreamParameters::AAudioStreamParameters() {}
AAudioStreamParameters::~AAudioStreamParameters() {}
+void AAudioStreamParameters::copyFrom(const AAudioStreamParameters &other) {
+ mSamplesPerFrame = other.mSamplesPerFrame;
+ mSampleRate = other.mSampleRate;
+ mDeviceId = other.mDeviceId;
+ mSharingMode = other.mSharingMode;
+ mAudioFormat = other.mAudioFormat;
+ mDirection = other.mDirection;
+ mBufferCapacity = other.mBufferCapacity;
+}
+
aaudio_result_t AAudioStreamParameters::validate() const {
if (mSamplesPerFrame != AAUDIO_UNSPECIFIED
&& (mSamplesPerFrame < SAMPLES_PER_FRAME_MIN || mSamplesPerFrame > SAMPLES_PER_FRAME_MAX)) {
@@ -78,6 +88,16 @@
return AAUDIO_ERROR_OUT_OF_RANGE;
}
+ switch (mDirection) {
+ case AAUDIO_DIRECTION_INPUT:
+ case AAUDIO_DIRECTION_OUTPUT:
+ break; // valid
+ default:
+ ALOGE("AAudioStreamParameters: direction not valid = %d", mDirection);
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ // break;
+ }
+
return AAUDIO_OK;
}
@@ -87,5 +107,7 @@
ALOGD("AAudioStreamParameters mSamplesPerFrame = %d", mSamplesPerFrame);
ALOGD("AAudioStreamParameters mSharingMode = %d", (int)mSharingMode);
ALOGD("AAudioStreamParameters mAudioFormat = %d", (int)mAudioFormat);
+ ALOGD("AAudioStreamParameters mDirection = %d", mDirection);
ALOGD("AAudioStreamParameters mBufferCapacity = %d", mBufferCapacity);
-}
\ No newline at end of file
+}
+
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
index 97379cc..5e67c93 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.h
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <aaudio/AAudio.h>
+#include <utility/AAudioUtilities.h>
namespace aaudio {
@@ -79,6 +80,24 @@
mBufferCapacity = frames;
}
+ aaudio_direction_t getDirection() const {
+ return mDirection;
+ }
+
+ void setDirection(aaudio_direction_t direction) {
+ mDirection = direction;
+ }
+
+ int32_t calculateBytesPerFrame() const {
+ return getSamplesPerFrame() * AAudioConvert_formatToSizeInBytes(getFormat());
+ }
+
+ /**
+ * Copy variables defined in other AAudioStreamParameters instance to this one.
+ * @param other
+ */
+ void copyFrom(const AAudioStreamParameters &other);
+
virtual aaudio_result_t validate() const;
void dump() const;
@@ -89,9 +108,10 @@
int32_t mDeviceId = AAUDIO_UNSPECIFIED;
aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED;
aaudio_format_t mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED;
+ aaudio_direction_t mDirection = AAUDIO_DIRECTION_OUTPUT;
int32_t mBufferCapacity = AAUDIO_UNSPECIFIED;
};
} /* namespace aaudio */
-#endif //AAUDIO_STREAM_PARAMETERS_H
\ No newline at end of file
+#endif //AAUDIO_STREAM_PARAMETERS_H
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 4859c69..8dcc37a 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AAudioStream"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -29,13 +29,26 @@
using namespace aaudio;
AudioStream::AudioStream()
- : mCallbackEnabled(false)
+ : mPlayerBase(new MyPlayerBase(this))
{
// mThread is a pthread_t of unknown size so we need memset.
memset(&mThread, 0, sizeof(mThread));
setPeriodNanoseconds(0);
}
+AudioStream::~AudioStream() {
+ ALOGD("destroying %p, state = %s", this, AAudio_convertStreamStateToText(getState()));
+ // If the stream is deleted when OPEN or in use then audio resources will leak.
+ // This would indicate an internal error. So we want to find this ASAP.
+ LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
+ || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED
+ || getState() == AAUDIO_STREAM_STATE_DISCONNECTED),
+ "aaudio stream still in use, state = %s",
+ AAudio_convertStreamStateToText(getState()));
+
+ mPlayerBase->clearParentReference(); // remove reference to this AudioStream
+}
+
static const char *AudioStream_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
const char *result;
switch (sharingMode) {
@@ -90,15 +103,12 @@
return AAUDIO_OK;
}
-AudioStream::~AudioStream() {
- close();
-}
aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
aaudio_stream_state_t *nextState,
int64_t timeoutNanoseconds)
{
- aaudio_result_t result = updateStateWhileWaiting();
+ aaudio_result_t result = updateStateMachine();
if (result != AAUDIO_OK) {
return result;
}
@@ -112,7 +122,7 @@
AudioClock::sleepForNanos(durationNanos);
timeoutNanoseconds -= durationNanos;
- aaudio_result_t result = updateStateWhileWaiting();
+ aaudio_result_t result = updateStateMachine();
if (result != AAUDIO_OK) {
return result;
}
@@ -153,6 +163,7 @@
void* threadArg)
{
if (mHasThread) {
+ ALOGE("AudioStream::createThread() - mHasThread already true");
return AAUDIO_ERROR_INVALID_STATE;
}
if (threadProc == nullptr) {
@@ -174,6 +185,7 @@
aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds)
{
if (!mHasThread) {
+ ALOGE("AudioStream::joinThread() - but has no thread");
return AAUDIO_ERROR_INVALID_STATE;
}
#if 0
@@ -187,3 +199,38 @@
return err ? AAudioConvert_androidToAAudioResult(-errno) : mThreadRegistrationResult;
}
+
+#if AAUDIO_USE_VOLUME_SHAPER
+android::media::VolumeShaper::Status AudioStream::applyVolumeShaper(
+ const android::media::VolumeShaper::Configuration& configuration __unused,
+ const android::media::VolumeShaper::Operation& operation __unused) {
+ ALOGW("applyVolumeShaper() is not supported");
+ return android::media::VolumeShaper::Status::ok();
+}
+#endif
+
+AudioStream::MyPlayerBase::MyPlayerBase(AudioStream *parent) : mParent(parent) {
+}
+
+AudioStream::MyPlayerBase::~MyPlayerBase() {
+ ALOGV("MyPlayerBase::~MyPlayerBase(%p) deleted", this);
+}
+
+void AudioStream::MyPlayerBase::registerWithAudioManager() {
+ if (!mRegistered) {
+ init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
+ mRegistered = true;
+ }
+}
+
+void AudioStream::MyPlayerBase::unregisterWithAudioManager() {
+ if (mRegistered) {
+ baseDestroy();
+ mRegistered = false;
+ }
+}
+
+
+void AudioStream::MyPlayerBase::destroy() {
+ unregisterWithAudioManager();
+}
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index e5fdcc6..34202d2 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -21,10 +21,18 @@
#include <mutex>
#include <stdint.h>
#include <aaudio/AAudio.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <utils/StrongPointer.h>
+#include "media/VolumeShaper.h"
+#include "media/PlayerBase.h"
#include "utility/AAudioUtilities.h"
#include "utility/MonotonicCounter.h"
+// Cannot get android::media::VolumeShaper to compile!
+#define AAUDIO_USE_VOLUME_SHAPER 0
+
namespace aaudio {
typedef void *(*aaudio_audio_thread_proc_t)(void *);
@@ -68,10 +76,10 @@
/**
- * Update state while in the middle of waitForStateChange()
+ * Update state machine.()
* @return
*/
- virtual aaudio_result_t updateStateWhileWaiting() = 0;
+ virtual aaudio_result_t updateStateMachine() = 0;
// =========== End ABSTRACT methods ===========================
@@ -234,8 +242,132 @@
return AAUDIO_ERROR_UNIMPLEMENTED;
}
+ // This is used by the AudioManager to duck and mute the stream when changing audio focus.
+ void setDuckAndMuteVolume(float duckAndMuteVolume) {
+ mDuckAndMuteVolume = duckAndMuteVolume;
+ doSetVolume(); // apply this change
+ }
+
+ float getDuckAndMuteVolume() {
+ return mDuckAndMuteVolume;
+ }
+
+ // Implement this in the output subclasses.
+ virtual android::status_t doSetVolume() { return android::NO_ERROR; }
+
+#if AAUDIO_USE_VOLUME_SHAPER
+ virtual ::android::binder::Status applyVolumeShaper(
+ const ::android::media::VolumeShaper::Configuration& configuration __unused,
+ const ::android::media::VolumeShaper::Operation& operation __unused);
+#endif
+
+ /**
+ * Register this stream's PlayerBase with the AudioManager if needed.
+ * Only register output streams.
+ * This should only be called for client streams and not for streams
+ * that run in the service.
+ */
+ void registerPlayerBase() {
+ if (getDirection() == AAUDIO_DIRECTION_OUTPUT) {
+ mPlayerBase->registerWithAudioManager();
+ }
+ }
+
+ /**
+ * Unregister this stream's PlayerBase with the AudioManager.
+ * This will only unregister if already registered.
+ */
+ void unregisterPlayerBase() {
+ mPlayerBase->unregisterWithAudioManager();
+ }
+
+ // Pass start request through PlayerBase for tracking.
+ aaudio_result_t systemStart() {
+ mPlayerBase->start();
+ // Pass aaudio_result_t around the PlayerBase interface, which uses status__t.
+ return mPlayerBase->getResult();
+ }
+
+ aaudio_result_t systemPause() {
+ mPlayerBase->pause();
+ return mPlayerBase->getResult();
+ }
+
+ aaudio_result_t systemStop() {
+ mPlayerBase->stop();
+ return mPlayerBase->getResult();
+ }
+
protected:
+ // PlayerBase allows the system to control the stream.
+ // Calling through PlayerBase->start() notifies the AudioManager of the player state.
+ // The AudioManager also can start/stop a stream by calling mPlayerBase->playerStart().
+ // systemStart() ==> mPlayerBase->start() mPlayerBase->playerStart() ==> requestStart()
+ // \ /
+ // ------ AudioManager -------
+ class MyPlayerBase : public android::PlayerBase {
+ public:
+ explicit MyPlayerBase(AudioStream *parent);
+
+ virtual ~MyPlayerBase();
+
+ /**
+ * Register for volume changes and remote control.
+ */
+ void registerWithAudioManager();
+
+ /**
+ * UnRegister.
+ */
+ void unregisterWithAudioManager();
+
+ /**
+ * Just calls unregisterWithAudioManager().
+ */
+ void destroy() override;
+
+ void clearParentReference() { mParent = nullptr; }
+
+ android::status_t playerStart() override {
+ // mParent should NOT be null. So go ahead and crash if it is.
+ mResult = mParent->requestStart();
+ return AAudioConvert_aaudioToAndroidStatus(mResult);
+ }
+
+ android::status_t playerPause() override {
+ mResult = mParent->requestPause();
+ return AAudioConvert_aaudioToAndroidStatus(mResult);
+ }
+
+ android::status_t playerStop() override {
+ mResult = mParent->requestStop();
+ return AAudioConvert_aaudioToAndroidStatus(mResult);
+ }
+
+ android::status_t playerSetVolume() override {
+ // No pan and only left volume is taken into account from IPLayer interface
+ mParent->setDuckAndMuteVolume(mVolumeMultiplierL /* * mPanMultiplierL */);
+ return android::NO_ERROR;
+ }
+
+#if AAUDIO_USE_VOLUME_SHAPER
+ ::android::binder::Status applyVolumeShaper(
+ const ::android::media::VolumeShaper::Configuration& configuration,
+ const ::android::media::VolumeShaper::Operation& operation) {
+ return mParent->applyVolumeShaper(configuration, operation);
+ }
+#endif
+
+ aaudio_result_t getResult() {
+ return mResult;
+ }
+
+ private:
+ AudioStream *mParent;
+ aaudio_result_t mResult = AAUDIO_OK;
+ bool mRegistered = false;
+ };
/**
* This should not be called after the open() call.
@@ -275,7 +407,9 @@
std::mutex mStreamMutex;
- std::atomic<bool> mCallbackEnabled;
+ std::atomic<bool> mCallbackEnabled{false};
+
+ float mDuckAndMuteVolume = 1.0f;
protected:
@@ -288,6 +422,8 @@
}
private:
+ const android::sp<MyPlayerBase> mPlayerBase;
+
// These do not change after open().
int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED;
int32_t mSampleRate = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 43a1ef1..09ebb3e 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -184,16 +184,6 @@
return result;
}
- switch (mDirection) {
- case AAUDIO_DIRECTION_INPUT:
- case AAUDIO_DIRECTION_OUTPUT:
- break; // valid
- default:
- ALOGE("AudioStreamBuilder: direction not valid = %d", mDirection);
- return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
- // break;
- }
-
switch (mPerformanceMode) {
case AAUDIO_PERFORMANCE_MODE_NONE:
case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
index 6e548b1..a43cfa8 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.h
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -35,15 +35,6 @@
~AudioStreamBuilder();
- aaudio_direction_t getDirection() const {
- return mDirection;
- }
-
- AudioStreamBuilder* setDirection(aaudio_direction_t direction) {
- mDirection = direction;
- return this;
- }
-
bool isSharingModeMatchRequired() const {
return mSharingModeMatchRequired;
}
@@ -113,7 +104,6 @@
private:
bool mSharingModeMatchRequired = false; // must match sharing mode requested
- aaudio_direction_t mDirection = AAUDIO_DIRECTION_OUTPUT;
aaudio_performance_mode_t mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
AAudioStream_dataCallback mDataCallbackProc = nullptr; // external callback functions
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
index 8d2c62d..c8ec150 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.cpp
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -22,6 +22,8 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <algorithm>
+
#include "FifoControllerBase.h"
#include "FifoController.h"
#include "FifoControllerIndirect.h"
@@ -85,15 +87,14 @@
wrappingBuffer->data[1] = nullptr;
wrappingBuffer->numFrames[1] = 0;
if (framesAvailable > 0) {
-
uint8_t *source = &mStorage[convertFramesToBytes(startIndex)];
// Does the available data cross the end of the FIFO?
if ((startIndex + framesAvailable) > mFrameCapacity) {
wrappingBuffer->data[0] = source;
- wrappingBuffer->numFrames[0] = mFrameCapacity - startIndex;
+ fifo_frames_t firstFrames = mFrameCapacity - startIndex;
+ wrappingBuffer->numFrames[0] = firstFrames;
wrappingBuffer->data[1] = &mStorage[0];
- wrappingBuffer->numFrames[1] = mFrameCapacity - startIndex;
-
+ wrappingBuffer->numFrames[1] = framesAvailable - firstFrames;
} else {
wrappingBuffer->data[0] = source;
wrappingBuffer->numFrames[0] = framesAvailable;
@@ -102,18 +103,19 @@
wrappingBuffer->data[0] = nullptr;
wrappingBuffer->numFrames[0] = 0;
}
-
}
fifo_frames_t FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) {
- fifo_frames_t framesAvailable = mFifo->getFullFramesAvailable();
+ // The FIFO might be overfull so clip to capacity.
+ fifo_frames_t framesAvailable = std::min(mFifo->getFullFramesAvailable(), mFrameCapacity);
fifo_frames_t startIndex = mFifo->getReadIndex();
fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
return framesAvailable;
}
fifo_frames_t FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) {
- fifo_frames_t framesAvailable = mFifo->getEmptyFramesAvailable();
+ // The FIFO might have underrun so clip to capacity.
+ fifo_frames_t framesAvailable = std::min(mFifo->getEmptyFramesAvailable(), mFrameCapacity);
fifo_frames_t startIndex = mFifo->getWriteIndex();
fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
return framesAvailable;
@@ -210,3 +212,9 @@
return mFifo->getCapacity();
}
+void FifoBuffer::eraseMemory() {
+ int32_t numBytes = convertFramesToBytes(getBufferCapacityInFrames());
+ if (numBytes > 0) {
+ memset(mStorage, 0, (size_t) numBytes);
+ }
+}
diff --git a/media/libaaudio/src/fifo/FifoBuffer.h b/media/libaaudio/src/fifo/FifoBuffer.h
index a94e9b0..f5a9e27 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.h
+++ b/media/libaaudio/src/fifo/FifoBuffer.h
@@ -111,6 +111,11 @@
mFifo->setWriteCounter(n);
}
+ /*
+ * This is generally only called before or after the buffer is used.
+ */
+ void eraseMemory();
+
private:
void fillWrappingBuffer(WrappingBuffer *wrappingBuffer,
diff --git a/media/libaaudio/src/fifo/FifoControllerBase.cpp b/media/libaaudio/src/fifo/FifoControllerBase.cpp
index 14a2be1..51a8e34 100644
--- a/media/libaaudio/src/fifo/FifoControllerBase.cpp
+++ b/media/libaaudio/src/fifo/FifoControllerBase.cpp
@@ -38,7 +38,7 @@
fifo_frames_t FifoControllerBase::getReadIndex() {
// % works with non-power of two sizes
- return (fifo_frames_t) (getReadCounter() % mCapacity);
+ return (fifo_frames_t) ((uint64_t)getReadCounter() % mCapacity);
}
void FifoControllerBase::advanceReadIndex(fifo_frames_t numFrames) {
@@ -51,7 +51,7 @@
fifo_frames_t FifoControllerBase::getWriteIndex() {
// % works with non-power of two sizes
- return (fifo_frames_t) (getWriteCounter() % mCapacity);
+ return (fifo_frames_t) ((uint64_t)getWriteCounter() % mCapacity);
}
void FifoControllerBase::advanceWriteIndex(fifo_frames_t numFrames) {
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index dd5e3c0..ee2504d 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -21,6 +21,7 @@
#include <stdint.h>
#include <utils/String16.h>
#include <media/AudioTrack.h>
+#include <media/AudioTimestamp.h>
#include <aaudio/AAudio.h>
#include "core/AudioStream.h"
@@ -30,7 +31,8 @@
using namespace aaudio;
AudioStreamLegacy::AudioStreamLegacy()
- : AudioStream(), mDeviceCallback(new StreamDeviceCallback(this)) {
+ : AudioStream()
+ , mDeviceCallback(new StreamDeviceCallback(this)) {
}
AudioStreamLegacy::~AudioStreamLegacy() {
@@ -46,33 +48,51 @@
return AudioStreamLegacy_callback;
}
-// Implement FixedBlockProcessor
-int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
- int32_t frameCount = numBytes / getBytesPerFrame();
+int32_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer, int32_t numFrames) {
+ if (getDirection() == AAUDIO_DIRECTION_INPUT) {
+ // Increment before because we already got the data from the device.
+ incrementFramesRead(numFrames);
+ }
+
// Call using the AAudio callback interface.
AAudioStream_dataCallback appCallback = getDataCallbackProc();
- return (*appCallback)(
+ aaudio_data_callback_result_t callbackResult = (*appCallback)(
(AAudioStream *) this,
getDataCallbackUserData(),
buffer,
- frameCount);
+ numFrames);
+
+ if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE
+ && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
+ // Increment after because we are going to write the data to the device.
+ incrementFramesWritten(numFrames);
+ }
+ return callbackResult;
+}
+
+// Implement FixedBlockProcessor
+int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
+ int32_t numFrames = numBytes / getBytesPerFrame();
+ return callDataCallbackFrames(buffer, numFrames);
}
void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) {
aaudio_data_callback_result_t callbackResult;
- if (!mCallbackEnabled.load()) {
- return;
- }
-
switch (opcode) {
case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: {
- if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
- // Note that this code assumes an AudioTrack::Buffer is the same as
- // AudioRecord::Buffer
- // TODO define our own AudioBuffer and pass it from the subclasses.
- AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
- if (audioBuffer->frameCount == 0) return;
+ checkForDisconnectRequest();
+
+ // Note that this code assumes an AudioTrack::Buffer is the same as
+ // AudioRecord::Buffer
+ // TODO define our own AudioBuffer and pass it from the subclasses.
+ AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
+ if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED || !mCallbackEnabled.load()) {
+ audioBuffer->size = 0; // silence the buffer
+ } else {
+ if (audioBuffer->frameCount == 0) {
+ return;
+ }
// If the caller specified an exact size then use a block size adapter.
if (mBlockAdapter != nullptr) {
@@ -81,44 +101,59 @@
(uint8_t *) audioBuffer->raw, byteCount);
} else {
// Call using the AAudio callback interface.
- callbackResult = (*getDataCallbackProc())(
- (AAudioStream *) this,
- getDataCallbackUserData(),
- audioBuffer->raw,
- audioBuffer->frameCount
- );
+ callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw,
+ audioBuffer->frameCount);
}
if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
audioBuffer->size = audioBuffer->frameCount * getBytesPerFrame();
- incrementClientFrameCounter(audioBuffer->frameCount);
} else {
audioBuffer->size = 0;
}
- break;
- }
- }
- /// FALL THROUGH
- // Stream got rerouted so we disconnect.
- case AAUDIO_CALLBACK_OPERATION_DISCONNECTED: {
- setState(AAUDIO_STREAM_STATE_DISCONNECTED);
- ALOGD("processCallbackCommon() stream disconnected");
- if (getErrorCallbackProc() != nullptr) {
- (*getErrorCallbackProc())(
- (AAudioStream *) this,
- getErrorCallbackUserData(),
- AAUDIO_ERROR_DISCONNECTED
- );
+ if (updateStateMachine() != AAUDIO_OK) {
+ forceDisconnect();
+ mCallbackEnabled.store(false);
+ }
}
- mCallbackEnabled.store(false);
}
break;
+ // Stream got rerouted so we disconnect.
+ case AAUDIO_CALLBACK_OPERATION_DISCONNECTED:
+ ALOGD("processCallbackCommon() stream disconnected");
+ forceDisconnect();
+ mCallbackEnabled.store(false);
+ break;
+
default:
break;
}
}
+
+
+void AudioStreamLegacy::checkForDisconnectRequest() {
+ if (mRequestDisconnect.isRequested()) {
+ ALOGD("checkForDisconnectRequest() mRequestDisconnect acknowledged");
+ forceDisconnect();
+ mRequestDisconnect.acknowledge();
+ mCallbackEnabled.store(false);
+ }
+}
+
+void AudioStreamLegacy::forceDisconnect() {
+ if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
+ setState(AAUDIO_STREAM_STATE_DISCONNECTED);
+ if (getErrorCallbackProc() != nullptr) {
+ (*getErrorCallbackProc())(
+ (AAudioStream *) this,
+ getErrorCallbackUserData(),
+ AAUDIO_ERROR_DISCONNECTED
+ );
+ }
+ }
+}
+
aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
int64_t *framePosition,
int64_t *timeNanoseconds,
@@ -136,8 +171,23 @@
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
break;
}
- status_t status = extendedTimestamp->getBestTimestamp(framePosition, timeNanoseconds, timebase);
- return AAudioConvert_androidToAAudioResult(status);
+ ExtendedTimestamp::Location location = ExtendedTimestamp::Location::LOCATION_INVALID;
+ int64_t localPosition;
+ status_t status = extendedTimestamp->getBestTimestamp(&localPosition, timeNanoseconds,
+ timebase, &location);
+ // use MonotonicCounter to prevent retrograde motion.
+ mTimestampPosition.update32((int32_t)localPosition);
+ *framePosition = mTimestampPosition.get();
+
+// ALOGD("getBestTimestamp() fposition: server = %6lld, kernel = %6lld, location = %d",
+// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_SERVER],
+// (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_KERNEL],
+// (int)location);
+ if (status == WOULD_BLOCK) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ } else {
+ return AAudioConvert_androidToAAudioResult(status);
+ }
}
void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId)
@@ -145,15 +195,18 @@
ALOGD("onAudioDeviceUpdate() deviceId %d", (int)deviceId);
if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId &&
getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
- setState(AAUDIO_STREAM_STATE_DISCONNECTED);
- // if we have a data callback and the stream is active, send the error callback from
- // data callback thread when it sees the DISCONNECTED state
- if (!isDataCallbackActive() && getErrorCallbackProc() != nullptr) {
- (*getErrorCallbackProc())(
- (AAudioStream *) this,
- getErrorCallbackUserData(),
- AAUDIO_ERROR_DISCONNECTED
- );
+ // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
+ // If we have a data callback and the stream is active, then ask the data callback
+ // to DISCONNECT and call the error callback.
+ if (isDataCallbackActive()) {
+ ALOGD("onAudioDeviceUpdate() request DISCONNECT in data callback due to device change");
+ // If the stream is stopped before the data callback has a chance to handle the
+ // request then the requestStop() and requestPause() methods will handle it after
+ // the callback has stopped.
+ mRequestDisconnect.request();
+ } else {
+ ALOGD("onAudioDeviceUpdate() DISCONNECT the stream now");
+ forceDisconnect();
}
}
setDeviceId(deviceId);
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h
index d2ef3c7..7e28579 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.h
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h
@@ -24,6 +24,7 @@
#include "AudioStream.h"
#include "AAudioLegacy.h"
+#include "utility/AAudioUtilities.h"
#include "utility/FixedBlockAdapter.h"
namespace aaudio {
@@ -63,6 +64,8 @@
aaudio_legacy_callback_t getLegacyCallback();
+ int32_t callDataCallbackFrames(uint8_t *buffer, int32_t numFrames);
+
// This is public so it can be called from the C callback function.
// This is called from the AudioTrack/AudioRecord client.
virtual void processCallback(int event, void *info) = 0;
@@ -109,6 +112,10 @@
void onAudioDeviceUpdate(audio_port_handle_t deviceId);
+ void checkForDisconnectRequest();
+
+ void forceDisconnect();
+
void onStart() { mCallbackEnabled.store(true); }
void onStop() { mCallbackEnabled.store(false); }
@@ -122,11 +129,14 @@
MonotonicCounter mFramesWritten;
MonotonicCounter mFramesRead;
+ MonotonicCounter mTimestampPosition;
FixedBlockAdapter *mBlockAdapter = nullptr;
aaudio_wrapping_frames_t mPositionWhenStarting = 0;
int32_t mCallbackBufferSize = 0;
const android::sp<StreamDeviceCallback> mDeviceCallback;
+
+ AtomicRequestor mRequestDisconnect;
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 8e8070c..bc6e60c 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioStreamRecord"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -159,6 +159,9 @@
actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
}
setPerformanceMode(actualPerformanceMode);
+
+ setSharingMode(AAUDIO_SHARING_MODE_SHARED); // EXCLUSIVE mode not supported in legacy
+
// Log warning if we did not get what we asked for.
ALOGW_IF(actualFlags != flags,
"AudioStreamRecord::open() flags changed from 0x%08X to 0x%08X",
@@ -178,11 +181,12 @@
{
// TODO add close() or release() to AudioRecord API then call it from here
if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
+ mAudioRecord->removeAudioDeviceCallback(mDeviceCallback);
mAudioRecord.clear();
setState(AAUDIO_STREAM_STATE_CLOSED);
}
mFixedBlockWriter.close();
- return AAUDIO_OK;
+ return AudioStream::close();
}
void AudioStreamRecord::processCallback(int event, void *info) {
@@ -207,7 +211,7 @@
if (mAudioRecord.get() == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
- // Get current position so we can detect when the track is playing.
+ // Get current position so we can detect when the track is recording.
status_t err = mAudioRecord->getPosition(&mPositionWhenStarting);
if (err != OK) {
return AAudioConvert_androidToAAudioResult(err);
@@ -230,12 +234,15 @@
onStop();
setState(AAUDIO_STREAM_STATE_STOPPING);
incrementFramesWritten(getFramesRead() - getFramesWritten()); // TODO review
+ mTimestampPosition.set(getFramesRead());
mAudioRecord->stop();
mFramesRead.reset32();
+ mTimestampPosition.reset32();
+ checkForDisconnectRequest();
return AAUDIO_OK;
}
-aaudio_result_t AudioStreamRecord::updateStateWhileWaiting()
+aaudio_result_t AudioStreamRecord::updateStateMachine()
{
aaudio_result_t result = AAUDIO_OK;
aaudio_wrapping_frames_t position;
@@ -292,6 +299,12 @@
}
int32_t framesRead = (int32_t)(bytesRead / bytesPerFrame);
incrementFramesRead(framesRead);
+
+ result = updateStateMachine();
+ if (result != AAUDIO_OK) {
+ return result;
+ }
+
return (aaudio_result_t) framesRead;
}
@@ -325,8 +338,28 @@
int64_t *timeNanoseconds) {
ExtendedTimestamp extendedTimestamp;
status_t status = mAudioRecord->getTimestamp(&extendedTimestamp);
- if (status != NO_ERROR) {
+ if (status == WOULD_BLOCK) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ } else if (status != NO_ERROR) {
return AAudioConvert_androidToAAudioResult(status);
}
return getBestTimestamp(clockId, framePosition, timeNanoseconds, &extendedTimestamp);
}
+
+int64_t AudioStreamRecord::getFramesWritten() {
+ aaudio_wrapping_frames_t position;
+ status_t result;
+ switch (getState()) {
+ case AAUDIO_STREAM_STATE_STARTING:
+ case AAUDIO_STREAM_STATE_STARTED:
+ case AAUDIO_STREAM_STATE_STOPPING:
+ result = mAudioRecord->getPosition(&position);
+ if (result == OK) {
+ mFramesWritten.update32(position);
+ }
+ break;
+ default:
+ break;
+ }
+ return AudioStreamLegacy::getFramesWritten();
+}
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
index 2c6a7eb..c1723ba 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -59,9 +59,11 @@
int32_t getXRunCount() const override;
+ int64_t getFramesWritten() override;
+
int32_t getFramesPerBurst() const override;
- aaudio_result_t updateStateWhileWaiting() override;
+ aaudio_result_t updateStateMachine() override;
aaudio_direction_t getDirection() const override {
return AAUDIO_DIRECTION_INPUT;
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 77f31e2..0e9aaef 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioStreamTrack"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -115,7 +115,7 @@
ALOGD("AudioStreamTrack::open(), request notificationFrames = %d, frameCount = %u",
notificationFrames, (uint)frameCount);
- mAudioTrack = new AudioTrack();
+ mAudioTrack = new AudioTrack(); // TODO review
if (getDeviceId() != AAUDIO_UNSPECIFIED) {
mAudioTrack->setOutputDevice(getDeviceId());
}
@@ -143,8 +143,7 @@
return AAudioConvert_androidToAAudioResult(status);
}
- //TrackPlayerBase init
- init(mAudioTrack.get(), PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
+ doSetVolume();
// Get the actual values from the AudioTrack.
setSamplesPerFrame(mAudioTrack->channelCount());
@@ -171,18 +170,20 @@
setDeviceId(mAudioTrack->getRoutedDeviceId());
mAudioTrack->addAudioDeviceCallback(mDeviceCallback);
- // Update performance mode based on the actual stream.
+ // Update performance mode based on the actual stream flags.
// For example, if the sample rate is not allowed then you won't get a FAST track.
audio_output_flags_t actualFlags = mAudioTrack->getFlags();
aaudio_performance_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
- if ((actualFlags & (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW))
- == (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW)) {
+ // We may not get the RAW flag. But as long as we get the FAST flag we can call it LOW_LATENCY.
+ if ((actualFlags & AUDIO_OUTPUT_FLAG_FAST) != 0) {
actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
-
} else if ((actualFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
}
setPerformanceMode(actualPerformanceMode);
+
+ setSharingMode(AAUDIO_SHARING_MODE_SHARED); // EXCLUSIVE mode not supported in legacy
+
// Log warning if we did not get what we asked for.
ALOGW_IF(actualFlags != flags,
"AudioStreamTrack::open() flags changed from 0x%08X to 0x%08X",
@@ -197,7 +198,7 @@
aaudio_result_t AudioStreamTrack::close()
{
if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
- destroy();
+ mAudioTrack->removeAudioDeviceCallback(mDeviceCallback);
setState(AAUDIO_STREAM_STATE_CLOSED);
}
mFixedBlockReader.close();
@@ -222,11 +223,11 @@
return;
}
-aaudio_result_t AudioStreamTrack::requestStart()
-{
+aaudio_result_t AudioStreamTrack::requestStart() {
std::lock_guard<std::mutex> lock(mStreamMutex);
if (mAudioTrack.get() == nullptr) {
+ ALOGE("AudioStreamTrack::requestStart() no AudioTrack");
return AAUDIO_ERROR_INVALID_STATE;
}
// Get current position so we can detect when the track is playing.
@@ -235,7 +236,7 @@
return AAudioConvert_androidToAAudioResult(err);
}
- err = startWithStatus();
+ err = mAudioTrack->start();
if (err != OK) {
return AAudioConvert_androidToAAudioResult(err);
} else {
@@ -245,11 +246,11 @@
return AAUDIO_OK;
}
-aaudio_result_t AudioStreamTrack::requestPause()
-{
+aaudio_result_t AudioStreamTrack::requestPause() {
std::lock_guard<std::mutex> lock(mStreamMutex);
if (mAudioTrack.get() == nullptr) {
+ ALOGE("requestPause() no AudioTrack");
return AAUDIO_ERROR_INVALID_STATE;
} else if (getState() != AAUDIO_STREAM_STATE_STARTING
&& getState() != AAUDIO_STREAM_STATE_STARTED) {
@@ -259,7 +260,8 @@
}
onStop();
setState(AAUDIO_STREAM_STATE_PAUSING);
- pause();
+ mAudioTrack->pause();
+ checkForDisconnectRequest();
status_t err = mAudioTrack->getPosition(&mPositionWhenPausing);
if (err != OK) {
return AAudioConvert_androidToAAudioResult(err);
@@ -271,14 +273,17 @@
std::lock_guard<std::mutex> lock(mStreamMutex);
if (mAudioTrack.get() == nullptr) {
+ ALOGE("AudioStreamTrack::requestFlush() no AudioTrack");
return AAUDIO_ERROR_INVALID_STATE;
} else if (getState() != AAUDIO_STREAM_STATE_PAUSED) {
+ ALOGE("AudioStreamTrack::requestFlush() not paused");
return AAUDIO_ERROR_INVALID_STATE;
}
setState(AAUDIO_STREAM_STATE_FLUSHING);
incrementFramesRead(getFramesWritten() - getFramesRead());
mAudioTrack->flush();
mFramesWritten.reset32();
+ mTimestampPosition.reset32();
return AAUDIO_OK;
}
@@ -286,17 +291,21 @@
std::lock_guard<std::mutex> lock(mStreamMutex);
if (mAudioTrack.get() == nullptr) {
+ ALOGE("AudioStreamTrack::requestStop() no AudioTrack");
return AAUDIO_ERROR_INVALID_STATE;
}
onStop();
setState(AAUDIO_STREAM_STATE_STOPPING);
incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review
- stop();
+ mTimestampPosition.set(getFramesWritten());
mFramesWritten.reset32();
+ mTimestampPosition.reset32();
+ mAudioTrack->stop();
+ checkForDisconnectRequest();
return AAUDIO_OK;
}
-aaudio_result_t AudioStreamTrack::updateStateWhileWaiting()
+aaudio_result_t AudioStreamTrack::updateStateMachine()
{
status_t err;
aaudio_wrapping_frames_t position;
@@ -373,6 +382,12 @@
}
int32_t framesWritten = (int32_t)(bytesWritten / bytesPerFrame);
incrementFramesWritten(framesWritten);
+
+ result = updateStateMachine();
+ if (result != AAUDIO_OK) {
+ return result;
+ }
+
return framesWritten;
}
@@ -431,8 +446,59 @@
int64_t *timeNanoseconds) {
ExtendedTimestamp extendedTimestamp;
status_t status = mAudioTrack->getTimestamp(&extendedTimestamp);
- if (status != NO_ERROR) {
+ if (status == WOULD_BLOCK) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ } if (status != NO_ERROR) {
return AAudioConvert_androidToAAudioResult(status);
}
- return getBestTimestamp(clockId, framePosition, timeNanoseconds, &extendedTimestamp);
+ int64_t position = 0;
+ int64_t nanoseconds = 0;
+ aaudio_result_t result = getBestTimestamp(clockId, &position,
+ &nanoseconds, &extendedTimestamp);
+ if (result == AAUDIO_OK) {
+ if (position < getFramesWritten()) {
+ *framePosition = position;
+ *timeNanoseconds = nanoseconds;
+ return result;
+ } else {
+ return AAUDIO_ERROR_INVALID_STATE; // TODO review, documented but not consistent
+ }
+ }
+ return result;
}
+
+status_t AudioStreamTrack::doSetVolume() {
+ status_t status = NO_INIT;
+ if (mAudioTrack.get() != nullptr) {
+ float volume = getDuckAndMuteVolume();
+ mAudioTrack->setVolume(volume, volume);
+ status = NO_ERROR;
+ }
+ return status;
+}
+
+#if AAUDIO_USE_VOLUME_SHAPER
+
+using namespace android::media::VolumeShaper;
+
+binder::Status AudioStreamTrack::applyVolumeShaper(
+ const VolumeShaper::Configuration& configuration,
+ const VolumeShaper::Operation& operation) {
+
+ sp<VolumeShaper::Configuration> spConfiguration = new VolumeShaper::Configuration(configuration);
+ sp<VolumeShaper::Operation> spOperation = new VolumeShaper::Operation(operation);
+
+ if (mAudioTrack.get() != nullptr) {
+ ALOGD("applyVolumeShaper() from IPlayer");
+ binder::Status status = mAudioTrack->applyVolumeShaper(spConfiguration, spOperation);
+ if (status < 0) { // a non-negative value is the volume shaper id.
+ ALOGE("applyVolumeShaper() failed with status %d", status);
+ }
+ return binder::Status::fromStatusT(status);
+ } else {
+ ALOGD("applyVolumeShaper()"
+ " no AudioTrack for volume control from IPlayer");
+ return binder::Status::ok();
+ }
+}
+#endif
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
index ff429ea..a871db4 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.h
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -19,6 +19,7 @@
#include <math.h>
#include <media/TrackPlayerBase.h>
+#include <media/AudioTrack.h>
#include <aaudio/AAudio.h>
#include "AudioStreamBuilder.h"
@@ -32,7 +33,7 @@
/**
* Internal stream that uses the legacy AudioTrack path.
*/
-class AudioStreamTrack : public AudioStreamLegacy, public android::TrackPlayerBase {
+class AudioStreamTrack : public AudioStreamLegacy {
public:
AudioStreamTrack();
@@ -67,7 +68,7 @@
return AAUDIO_DIRECTION_OUTPUT;
}
- aaudio_result_t updateStateWhileWaiting() override;
+ aaudio_result_t updateStateMachine() override;
// This is public so it can be called from the C callback function.
void processCallback(int event, void *info) override;
@@ -76,13 +77,22 @@
return incrementFramesWritten(frames);
}
+ android::status_t doSetVolume() override;
+
+#if AAUDIO_USE_VOLUME_SHAPER
+ virtual android::binder::Status applyVolumeShaper(
+ const android::media::VolumeShaper::Configuration& configuration,
+ const android::media::VolumeShaper::Operation& operation) override;
+#endif
+
private:
+ android::sp<android::AudioTrack> mAudioTrack;
+
// adapts between variable sized blocks and fixed size blocks
FixedBlockReader mFixedBlockReader;
- // TODO add 64-bit position reporting to AudioRecord and use it.
- aaudio_wrapping_frames_t mPositionWhenStarting = 0;
+ // TODO add 64-bit position reporting to AudioTrack and use it.
aaudio_wrapping_frames_t mPositionWhenPausing = 0;
};
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index acd319b..3afa976 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -258,4 +258,112 @@
}
}
+
+/**
+ * Simple double buffer for a structure that can be written occasionally and read occasionally.
+ * This allows a SINGLE writer with multiple readers.
+ *
+ * It is OK if the FIFO overflows and we lose old values.
+ * It is also OK if we read an old value.
+ * Thread may return a non-atomic result if the other thread is rapidly writing
+ * new values on another core.
+ */
+template <class T>
+class SimpleDoubleBuffer {
+public:
+ SimpleDoubleBuffer()
+ : mValues() {}
+
+ __attribute__((no_sanitize("integer")))
+ void write(T value) {
+ int index = mCounter.load() & 1;
+ mValues[index] = value;
+ mCounter++; // Increment AFTER updating storage, OK if it wraps.
+ }
+
+ /**
+ * This should only be called by the same thread that calls write() or when
+ * no other thread is calling write.
+ */
+ void clear() {
+ mCounter.store(0);
+ }
+
+ T read() const {
+ T result;
+ int before;
+ int after;
+ int timeout = 3;
+ do {
+ // Check to see if a write occurred while were reading.
+ before = mCounter.load();
+ int index = (before & 1) ^ 1;
+ result = mValues[index];
+ after = mCounter.load();
+ } while ((after != before) && (after > 0) && (--timeout > 0));
+ return result;
+ }
+
+ /**
+ * @return true if at least one value has been written
+ */
+ bool isValid() const {
+ return mCounter.load() > 0;
+ }
+
+private:
+ T mValues[2];
+ std::atomic<int> mCounter{0};
+};
+
+class Timestamp {
+public:
+ Timestamp()
+ : mPosition(0)
+ , mNanoseconds(0) {}
+ Timestamp(int64_t position, int64_t nanoseconds)
+ : mPosition(position)
+ , mNanoseconds(nanoseconds) {}
+
+ int64_t getPosition() const { return mPosition; }
+
+ int64_t getNanoseconds() const { return mNanoseconds; }
+
+private:
+ // These cannot be const because we need to implement the copy assignment operator.
+ int64_t mPosition;
+ int64_t mNanoseconds;
+};
+
+
+/**
+ * Pass a request to another thread.
+ * This is used when one thread, A, wants another thread, B, to do something.
+ * A naive approach would be for A to set a flag and for B to clear it when done.
+ * But that creates a race condition. This technique avoids the race condition.
+ *
+ * Assumes only one requester and one acknowledger.
+ */
+class AtomicRequestor {
+public:
+
+ __attribute__((no_sanitize("integer")))
+ void request() {
+ mRequested++;
+ }
+
+ __attribute__((no_sanitize("integer")))
+ bool isRequested() {
+ return (mRequested.load() - mAcknowledged.load()) > 0;
+ }
+
+ __attribute__((no_sanitize("integer")))
+ void acknowledge() {
+ mAcknowledged++;
+ }
+
+private:
+ std::atomic<int> mRequested{0};
+ std::atomic<int> mAcknowledged{0};
+};
#endif //UTILITY_AAUDIO_UTILITIES_H
diff --git a/media/libaaudio/src/utility/HandleTracker.cpp b/media/libaaudio/src/utility/HandleTracker.cpp
deleted file mode 100644
index 35ce95a..0000000
--- a/media/libaaudio/src/utility/HandleTracker.cpp
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#define LOG_TAG "AAudio"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <assert.h>
-#include <functional>
-#include <iomanip>
-#include <new>
-#include <sstream>
-#include <stdint.h>
-#include <utils/Mutex.h>
-
-#include <aaudio/AAudio.h>
-#include "AAudioUtilities.h"
-#include "HandleTracker.h"
-
-using android::Mutex;
-
-// Handle format is: tgggiiii
-// where each letter is 4 bits, t=type, g=generation, i=index
-
-#define TYPE_SIZE 4
-#define GENERATION_SIZE 12
-#define INDEX_SIZE 16
-
-#define GENERATION_INVALID 0
-#define GENERATION_SHIFT INDEX_SIZE
-
-#define TYPE_MASK ((1 << TYPE_SIZE) - 1)
-#define GENERATION_MASK ((1 << GENERATION_SIZE) - 1)
-#define INDEX_MASK ((1 << INDEX_SIZE) - 1)
-
-#define SLOT_UNAVAILABLE (-1)
-
-// Error if handle is negative so type is limited to bottom half.
-#define HANDLE_INVALID_TYPE TYPE_MASK
-
-static_assert(HANDLE_TRACKER_MAX_TYPES == (1 << (TYPE_SIZE - 1)),
- "Mismatch between header and cpp.");
-static_assert(HANDLE_TRACKER_MAX_HANDLES == (1 << (INDEX_SIZE)),
- "Mismatch between header and cpp.");
-
-HandleTracker::HandleTracker(uint32_t maxHandles)
- : mMaxHandleCount(maxHandles)
- , mHandleHeaders(nullptr)
-{
- assert(maxHandles <= HANDLE_TRACKER_MAX_HANDLES);
- // Allocate arrays to hold addresses and validation info.
- mHandleAddresses = (handle_tracker_address_t *)
- new(std::nothrow) handle_tracker_address_t[maxHandles];
- if (mHandleAddresses != nullptr) {
- mHandleHeaders = new(std::nothrow) handle_tracker_header_t[maxHandles];
-
- if (mHandleHeaders != nullptr) {
- handle_tracker_header_t initialHeader = buildHeader(0, 1);
- // Initialize linked list of free nodes. nullptr terminated.
- for (uint32_t i = 0; i < (maxHandles - 1); i++) {
- mHandleAddresses[i] = &mHandleAddresses[i + 1]; // point to next node
- mHandleHeaders[i] = initialHeader;
- }
- mNextFreeAddress = &mHandleAddresses[0];
- mHandleAddresses[maxHandles - 1] = nullptr;
- mHandleHeaders[maxHandles - 1] = 0;
- } else {
- delete[] mHandleAddresses; // so the class appears uninitialized
- mHandleAddresses = nullptr;
- }
- }
-}
-
-HandleTracker::~HandleTracker()
-{
- Mutex::Autolock _l(mLock);
- delete[] mHandleAddresses;
- delete[] mHandleHeaders;
- mHandleAddresses = nullptr;
-}
-
-bool HandleTracker::isInitialized() const {
- return mHandleAddresses != nullptr;
-}
-
-
-
-std::string HandleTracker::dump() const {
- if (!isInitialized()) {
- return "HandleTracker is not initialized\n";
- }
-
- std::stringstream result;
- const bool isLocked = AAudio_tryUntilTrue(
- [this]()->bool { return mLock.tryLock(); } /* f */,
- 50 /* times */,
- 20 /* sleepMs */);
- if (!isLocked) {
- result << "HandleTracker may be deadlocked\n";
- }
-
- result << "HandleTracker:\n";
- result << " HandleHeaders:\n";
- // atLineStart() can be changed to support an arbitrary line breaking algorithm;
- // it should return true when a new line starts.
- // For simplicity, we will use a constant 16 items per line.
- const auto atLineStart = [](int index) -> bool {
- // Magic constant of 0xf used for mask to detect start every 16 items.
- return (index & 0xf) == 0; };
- const auto atLineEnd = [this, &atLineStart](int index) -> bool {
- return atLineStart(index + 1) || index == mMaxHandleCount - 1; };
-
- for (int i = 0; i < mMaxHandleCount; ++i) {
- if (atLineStart(i)) {
- result << " ";
- }
- result << std::hex << std::setw(4) << std::setfill('0') << mHandleHeaders[i]
- << (atLineEnd(i) ? "\n" : " ");
- }
-
- if (isLocked) {
- mLock.unlock();
- }
- return result.str();
-}
-
-handle_tracker_slot_t HandleTracker::allocateSlot_l() {
- void **allocated = mNextFreeAddress;
- if (allocated == nullptr) {
- return SLOT_UNAVAILABLE;
- }
- // Remove this slot from the head of the linked list.
- mNextFreeAddress = (void **) *allocated;
- return (allocated - mHandleAddresses);
-}
-
-handle_tracker_generation_t HandleTracker::nextGeneration_l(handle_tracker_slot_t index) {
- handle_tracker_generation_t generation = (mHandleHeaders[index] + 1) & GENERATION_MASK;
- // Avoid generation zero so that 0x0 is not a valid handle.
- if (generation == GENERATION_INVALID) {
- generation++;
- }
- return generation;
-}
-
-aaudio_handle_t HandleTracker::put(handle_tracker_type_t type, void *address)
-{
- if (type < 0 || type >= HANDLE_TRACKER_MAX_TYPES) {
- return static_cast<aaudio_handle_t>(AAUDIO_ERROR_OUT_OF_RANGE);
- }
- if (!isInitialized()) {
- return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_MEMORY);
- }
-
- Mutex::Autolock _l(mLock);
-
- // Find an empty slot.
- handle_tracker_slot_t index = allocateSlot_l();
- if (index == SLOT_UNAVAILABLE) {
- ALOGE("HandleTracker::put() no room for more handles");
- return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_FREE_HANDLES);
- }
-
- // Cycle the generation counter so stale handles can be detected.
- handle_tracker_generation_t generation = nextGeneration_l(index); // reads header table
- handle_tracker_header_t inputHeader = buildHeader(type, generation);
-
- // These two writes may need to be observed by other threads or cores during get().
- mHandleHeaders[index] = inputHeader;
- mHandleAddresses[index] = address;
- // TODO use store release to enforce memory order with get()
-
- // Generate a handle.
- aaudio_handle_t handle = buildHandle(inputHeader, index);
-
- ALOGV("HandleTracker::put(%p) returns 0x%08x", address, handle);
- return handle;
-}
-
-handle_tracker_slot_t HandleTracker::handleToIndex(handle_tracker_type_t type,
- aaudio_handle_t handle) const
-{
- // Validate the handle.
- handle_tracker_slot_t index = extractIndex(handle);
- if (index >= mMaxHandleCount) {
- ALOGE("HandleTracker::handleToIndex() invalid handle = 0x%08X", handle);
- return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
- }
- handle_tracker_generation_t handleGeneration = extractGeneration(handle);
- handle_tracker_header_t inputHeader = buildHeader(type, handleGeneration);
- // We do not need to synchronize this access to mHandleHeaders because it is constant for
- // the lifetime of the handle.
- if (inputHeader != mHandleHeaders[index]) {
- ALOGE("HandleTracker::handleToIndex() inputHeader = 0x%08x != mHandleHeaders[%d] = 0x%08x",
- inputHeader, index, mHandleHeaders[index]);
- return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
- }
- return index;
-}
-
-handle_tracker_address_t HandleTracker::get(handle_tracker_type_t type, aaudio_handle_t handle) const
-{
- if (!isInitialized()) {
- return nullptr;
- }
- handle_tracker_slot_t index = handleToIndex(type, handle);
- if (index >= 0) {
- // We do not need to synchronize this access to mHandleHeaders because this slot
- // is allocated and, therefore, not part of the linked list of free slots.
- return mHandleAddresses[index];
- } else {
- return nullptr;
- }
-}
-
-handle_tracker_address_t HandleTracker::remove(handle_tracker_type_t type, aaudio_handle_t handle) {
- if (!isInitialized()) {
- return nullptr;
- }
-
- Mutex::Autolock _l(mLock);
-
- handle_tracker_slot_t index = handleToIndex(type,handle);
- if (index >= 0) {
- handle_tracker_address_t address = mHandleAddresses[index];
-
- // Invalidate the header type but preserve the generation count.
- handle_tracker_generation_t generation = mHandleHeaders[index] & GENERATION_MASK;
- handle_tracker_header_t inputHeader = buildHeader(
- (handle_tracker_type_t) HANDLE_INVALID_TYPE, generation);
- mHandleHeaders[index] = inputHeader;
-
- // Add this slot to the head of the linked list.
- mHandleAddresses[index] = mNextFreeAddress;
- mNextFreeAddress = (handle_tracker_address_t *) &mHandleAddresses[index];
- return address;
- } else {
- return nullptr;
- }
-}
-
-aaudio_handle_t HandleTracker::buildHandle(handle_tracker_header_t typeGeneration,
- handle_tracker_slot_t index) {
- return (aaudio_handle_t)((typeGeneration << GENERATION_SHIFT) | (index & INDEX_MASK));
-}
-
-handle_tracker_header_t HandleTracker::buildHeader(handle_tracker_type_t type,
- handle_tracker_generation_t generation)
-{
- return (handle_tracker_header_t) (((type & TYPE_MASK) << GENERATION_SIZE)
- | (generation & GENERATION_MASK));
-}
-
-handle_tracker_slot_t HandleTracker::extractIndex(aaudio_handle_t handle)
-{
- return handle & INDEX_MASK;
-}
-
-handle_tracker_generation_t HandleTracker::extractGeneration(aaudio_handle_t handle)
-{
- return (handle >> GENERATION_SHIFT) & GENERATION_MASK;
-}
diff --git a/media/libaaudio/src/utility/HandleTracker.h b/media/libaaudio/src/utility/HandleTracker.h
deleted file mode 100644
index a4c51c0..0000000
--- a/media/libaaudio/src/utility/HandleTracker.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef UTILITY_HANDLE_TRACKER_H
-#define UTILITY_HANDLE_TRACKER_H
-
-#include <stdint.h>
-#include <string>
-#include <utils/Mutex.h>
-
-typedef int32_t aaudio_handle_t;
-typedef int32_t handle_tracker_type_t; // what kind of handle
-typedef int32_t handle_tracker_slot_t; // index in allocation table
-typedef int32_t handle_tracker_generation_t; // incremented when slot used
-typedef uint16_t handle_tracker_header_t; // combines type and generation
-typedef void *handle_tracker_address_t; // address of something that is stored here
-
-#define HANDLE_TRACKER_MAX_TYPES (1 << 3)
-#define HANDLE_TRACKER_MAX_HANDLES (1 << 16)
-
-/**
- * Represent Objects using an integer handle that can be used with Java.
- * This also makes the 'C' ABI more robust.
- *
- * Note that this should only be called from a single thread.
- * If you call it from more than one thread then you need to use your own mutex.
- */
-class HandleTracker {
-
-public:
- /**
- * @param maxHandles cannot exceed HANDLE_TRACKER_MAX_HANDLES
- */
- HandleTracker(uint32_t maxHandles = 256);
- virtual ~HandleTracker();
-
- /**
- * Don't use if this returns false;
- * @return true if the internal allocation succeeded
- */
- bool isInitialized() const;
-
- /**
- * Returns HandleTracker information.
- *
- * Will attempt to get the object lock, but will proceed
- * even if it cannot.
- *
- * Each line of information ends with a newline.
- *
- * @return a string representing the HandleTracker info.
- */
- std::string dump() const;
-
- /**
- * Store a pointer and return a handle that can be used to retrieve the pointer.
- *
- * It is safe to call put() or remove() from multiple threads.
- *
- * @param expectedType the type of the object to be tracked
- * @param address pointer to be converted to a handle
- * @return a valid handle or a negative error
- */
- aaudio_handle_t put(handle_tracker_type_t expectedType, handle_tracker_address_t address);
-
- /**
- * Get the original pointer associated with the handle.
- * The handle will be validated to prevent stale handles from being reused.
- * Note that the validation is designed to prevent common coding errors and not
- * to prevent deliberate hacking.
- *
- * @param expectedType shouldmatch the type we passed to put()
- * @param handle to be converted to a pointer
- * @return address associated with handle or nullptr
- */
- handle_tracker_address_t get(handle_tracker_type_t expectedType, aaudio_handle_t handle) const;
-
- /**
- * Free up the storage associated with the handle.
- * Subsequent attempts to use the handle will fail.
- *
- * Do NOT remove() a handle while get() is being called for the same handle from another thread.
- *
- * @param expectedType shouldmatch the type we passed to put()
- * @param handle to be removed from tracking
- * @return address associated with handle or nullptr if not found
- */
- handle_tracker_address_t remove(handle_tracker_type_t expectedType, aaudio_handle_t handle);
-
-private:
- const int32_t mMaxHandleCount; // size of array
- // This address is const after initialization.
- handle_tracker_address_t * mHandleAddresses; // address of objects or a free linked list node
- // This address is const after initialization.
- handle_tracker_header_t * mHandleHeaders; // combination of type and generation
- // head of the linked list of free nodes in mHandleAddresses
- handle_tracker_address_t * mNextFreeAddress;
-
- // This Mutex protects the linked list of free nodes.
- // The list is managed using mHandleAddresses and mNextFreeAddress.
- // The data in mHandleHeaders is only changed by put() and remove().
- mutable android::Mutex mLock;
-
- /**
- * Pull slot off of a list of empty slots.
- * @return index or a negative error
- */
- handle_tracker_slot_t allocateSlot_l();
-
- /**
- * Increment the generation for the slot, avoiding zero.
- */
- handle_tracker_generation_t nextGeneration_l(handle_tracker_slot_t index);
-
- /**
- * Validate the handle and return the corresponding index.
- * @return slot index or a negative error
- */
- handle_tracker_slot_t handleToIndex(aaudio_handle_t handle, handle_tracker_type_t type) const;
-
- /**
- * Construct a handle from a header and an index.
- * @param header combination of a type and a generation
- * @param index slot index returned from allocateSlot
- * @return handle or a negative error
- */
- static aaudio_handle_t buildHandle(handle_tracker_header_t header, handle_tracker_slot_t index);
-
- /**
- * Combine a type and a generation field into a header.
- */
- static handle_tracker_header_t buildHeader(handle_tracker_type_t type,
- handle_tracker_generation_t generation);
-
- /**
- * Extract the index from a handle.
- * Does not validate the handle.
- * @return index associated with a handle
- */
- static handle_tracker_slot_t extractIndex(aaudio_handle_t handle);
-
- /**
- * Extract the generation from a handle.
- * Does not validate the handle.
- * @return generation associated with a handle
- */
- static handle_tracker_generation_t extractGeneration(aaudio_handle_t handle);
-
-};
-
-#endif //UTILITY_HANDLE_TRACKER_H
diff --git a/media/libaaudio/src/utility/MonotonicCounter.h b/media/libaaudio/src/utility/MonotonicCounter.h
index 81d7f89..5833eab 100644
--- a/media/libaaudio/src/utility/MonotonicCounter.h
+++ b/media/libaaudio/src/utility/MonotonicCounter.h
@@ -41,6 +41,13 @@
}
/**
+ * set the current value of the counter
+ */
+ void set(int64_t counter) {
+ mCounter64 = counter;
+ }
+
+ /**
* Advance the counter if delta is positive.
* @return current value of the counter
*/
@@ -82,6 +89,18 @@
mCounter32 = 0;
}
+ /**
+ * Round 64-bit counter up to a multiple of the period.
+ *
+ * @param period might be, for example, a buffer capacity
+ */
+ void roundUp64(int32_t period) {
+ if (period > 0) {
+ int64_t numPeriods = (mCounter64 + period - 1) / period;
+ mCounter64 = numPeriods * period;
+ }
+ }
+
private:
int64_t mCounter64 = 0;
int32_t mCounter32 = 0;
diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk
index e4eef06..8117181 100644
--- a/media/libaaudio/tests/Android.mk
+++ b/media/libaaudio/tests/Android.mk
@@ -5,16 +5,6 @@
$(call include-path-for, audio-utils) \
frameworks/av/media/libaaudio/include \
frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_handle_tracker.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_handle_tracker
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
LOCAL_SRC_FILES:= test_marshalling.cpp
LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
LOCAL_MODULE := test_aaudio_marshalling
@@ -34,6 +24,17 @@
LOCAL_C_INCLUDES := \
$(call include-path-for, audio-utils) \
frameworks/av/media/libaaudio/include \
+ frameworks/av/media/libaaudio/src \
+ frameworks/av/media/libaaudio/examples
+LOCAL_SRC_FILES:= test_timestamps.cpp
+LOCAL_SHARED_LIBRARIES := libaaudio
+LOCAL_MODULE := test_timestamps
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, audio-utils) \
+ frameworks/av/media/libaaudio/include \
frameworks/av/media/libaaudio/src
LOCAL_SRC_FILES:= test_linear_ramp.cpp
LOCAL_SHARED_LIBRARIES := libaaudio
@@ -79,3 +80,13 @@
LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
LOCAL_MODULE := test_n_streams
include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, audio-utils) \
+ frameworks/av/media/libaaudio/include \
+ frameworks/av/media/libaaudio/src
+LOCAL_SRC_FILES:= test_atomic_fifo.cpp
+LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
+LOCAL_MODULE := test_atomic_fifo
+include $(BUILD_NATIVE_TEST)
diff --git a/media/libaaudio/tests/test_atomic_fifo.cpp b/media/libaaudio/tests/test_atomic_fifo.cpp
new file mode 100644
index 0000000..0edfebe
--- /dev/null
+++ b/media/libaaudio/tests/test_atomic_fifo.cpp
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+#include <stdlib.h>
+
+#include "fifo/FifoBuffer.h"
+#include "fifo/FifoController.h"
+
+using android::fifo_frames_t;
+using android::fifo_counter_t;
+using android::FifoController;
+using android::FifoBuffer;
+using android::WrappingBuffer;
+
+TEST(test_fifo_controller, fifo_indices) {
+ // Values are arbitrary primes designed to trigger edge cases.
+ constexpr int capacity = 83;
+ constexpr int threshold = 47;
+ FifoController fifoController(capacity, threshold);
+ ASSERT_EQ(capacity, fifoController.getCapacity());
+ ASSERT_EQ(threshold, fifoController.getThreshold());
+
+ ASSERT_EQ(0, fifoController.getReadCounter());
+ ASSERT_EQ(0, fifoController.getWriteCounter());
+ ASSERT_EQ(0, fifoController.getFullFramesAvailable());
+ ASSERT_EQ(threshold, fifoController.getEmptyFramesAvailable());
+
+ // Pretend to write some data.
+ constexpr int advance1 = 23;
+ fifoController.advanceWriteIndex(advance1);
+ int advanced = advance1;
+ ASSERT_EQ(0, fifoController.getReadCounter());
+ ASSERT_EQ(0, fifoController.getReadIndex());
+ ASSERT_EQ(advanced, fifoController.getWriteCounter());
+ ASSERT_EQ(advanced, fifoController.getWriteIndex());
+ ASSERT_EQ(advanced, fifoController.getFullFramesAvailable());
+ ASSERT_EQ(threshold - advanced, fifoController.getEmptyFramesAvailable());
+
+ // Pretend to read the data.
+ fifoController.advanceReadIndex(advance1);
+ ASSERT_EQ(advanced, fifoController.getReadCounter());
+ ASSERT_EQ(advanced, fifoController.getReadIndex());
+ ASSERT_EQ(advanced, fifoController.getWriteCounter());
+ ASSERT_EQ(advanced, fifoController.getWriteIndex());
+ ASSERT_EQ(0, fifoController.getFullFramesAvailable());
+ ASSERT_EQ(threshold, fifoController.getEmptyFramesAvailable());
+
+ // Write past end of buffer.
+ constexpr int advance2 = 13 + capacity - advance1;
+ fifoController.advanceWriteIndex(advance2);
+ advanced += advance2;
+ ASSERT_EQ(advance1, fifoController.getReadCounter());
+ ASSERT_EQ(advance1, fifoController.getReadIndex());
+ ASSERT_EQ(advanced, fifoController.getWriteCounter());
+ ASSERT_EQ(advanced - capacity, fifoController.getWriteIndex());
+ ASSERT_EQ(advance2, fifoController.getFullFramesAvailable());
+ ASSERT_EQ(threshold - advance2, fifoController.getEmptyFramesAvailable());
+}
+
+TEST(test_fifo_controller, fifo_wrap_around_zero) {
+ constexpr int capacity = 7; // arbitrary prime
+ constexpr int threshold = capacity;
+ FifoController fifoController(capacity, threshold);
+ ASSERT_EQ(capacity, fifoController.getCapacity());
+ ASSERT_EQ(threshold, fifoController.getThreshold());
+
+ fifoController.setReadCounter(-10); // a bit less than negative capacity
+ for (int i = 0; i < 20; i++) {
+ EXPECT_EQ(i - 10, fifoController.getReadCounter());
+ EXPECT_GE(fifoController.getReadIndex(), 0);
+ EXPECT_LT(fifoController.getReadIndex(), capacity);
+ fifoController.advanceReadIndex(1);
+ }
+
+ fifoController.setWriteCounter(-10);
+ for (int i = 0; i < 20; i++) {
+ EXPECT_EQ(i - 10, fifoController.getWriteCounter());
+ EXPECT_GE(fifoController.getWriteIndex(), 0);
+ EXPECT_LT(fifoController.getWriteIndex(), capacity);
+ fifoController.advanceWriteIndex(1);
+ }
+}
+
+
+// TODO consider using a template for other data types.
+
+// Create a big array and then use a region in the middle for the unit tests.
+// Then we can scan the rest of the array to see if it got clobbered.
+static constexpr fifo_frames_t kBigArraySize = 1024;
+static constexpr fifo_frames_t kFifoDataOffset = 128; // starting index of FIFO data
+static constexpr int16_t kSafeDataValue = 0x7654; // original value of BigArray
+
+class TestFifoBuffer {
+public:
+ explicit TestFifoBuffer(fifo_frames_t capacity, fifo_frames_t threshold = 0)
+ : mFifoBuffer(sizeof(int16_t), capacity,
+ &mReadIndex,
+ &mWriteIndex,
+ &mVeryBigArray[kFifoDataOffset]) // address of start of FIFO data
+ {
+
+ // Assume a frame is one int16_t.
+ // For reading and writing.
+ if (threshold <= 0) {
+ threshold = capacity;
+ }
+ mFifoBuffer.setThreshold(threshold);
+ mThreshold = threshold;
+
+ for (fifo_frames_t i = 0; i < kBigArraySize; i++) {
+ mVeryBigArray[i] = kSafeDataValue;
+ }
+ }
+
+ void checkMisc() {
+ ASSERT_EQ((int32_t)(2 * sizeof(int16_t)), mFifoBuffer.convertFramesToBytes(2));
+ ASSERT_EQ(mThreshold, mFifoBuffer.getThreshold());
+ }
+
+ void verifyAddressInRange(void *p, void *valid, size_t numBytes) {
+ uintptr_t p_int = (uintptr_t) p;
+ uintptr_t valid_int = (uintptr_t) valid;
+ EXPECT_GE(p_int, valid_int);
+ EXPECT_LT(p_int, (valid_int + numBytes));
+ }
+
+ void verifyStorageIntegrity() {
+ for (fifo_frames_t i = 0; i < kFifoDataOffset; i++) {
+ EXPECT_EQ(mVeryBigArray[i], kSafeDataValue);
+ }
+ fifo_frames_t firstFrameAfter = kFifoDataOffset + mFifoBuffer.getBufferCapacityInFrames();
+ for (fifo_frames_t i = firstFrameAfter; i < kBigArraySize; i++) {
+ EXPECT_EQ(mVeryBigArray[i], kSafeDataValue);
+ }
+ }
+
+ // Verify that the available frames in each part add up correctly.
+ void verifyWrappingBuffer() {
+ WrappingBuffer wrappingBuffer;
+
+
+ // Does the sum of the two parts match the available value returned?
+ // For EmptyRoom
+ fifo_frames_t framesAvailable =
+ mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
+ fifo_frames_t wrapAvailable = mFifoBuffer.getEmptyRoomAvailable(&wrappingBuffer);
+ EXPECT_EQ(framesAvailable, wrapAvailable);
+ fifo_frames_t bothAvailable = wrappingBuffer.numFrames[0] + wrappingBuffer.numFrames[1];
+ EXPECT_EQ(framesAvailable, bothAvailable);
+ // For FullData
+ framesAvailable =
+ mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
+ wrapAvailable = mFifoBuffer.getFullDataAvailable(&wrappingBuffer);
+ EXPECT_EQ(framesAvailable, wrapAvailable);
+ bothAvailable = wrappingBuffer.numFrames[0] + wrappingBuffer.numFrames[1];
+ EXPECT_EQ(framesAvailable, bothAvailable);
+
+ // Are frame counts in legal range?
+ fifo_frames_t capacity = mFifoBuffer.getBufferCapacityInFrames();
+ EXPECT_GE(wrappingBuffer.numFrames[0], 0);
+ EXPECT_LE(wrappingBuffer.numFrames[0], capacity);
+ EXPECT_GE(wrappingBuffer.numFrames[1], 0);
+ EXPECT_LE(wrappingBuffer.numFrames[1], capacity);
+
+ // Are addresses within the FIFO data area?
+ size_t validBytes = capacity * sizeof(int16_t);
+ if (wrappingBuffer.numFrames[0]) {
+ verifyAddressInRange(wrappingBuffer.data[0], mFifoStorage, validBytes);
+ uint8_t *last = ((uint8_t *)wrappingBuffer.data[0])
+ + mFifoBuffer.convertFramesToBytes(wrappingBuffer.numFrames[0]) - 1;
+ verifyAddressInRange(last, mFifoStorage, validBytes);
+ }
+ if (wrappingBuffer.numFrames[1]) {
+ verifyAddressInRange(wrappingBuffer.data[1], mFifoStorage, validBytes);
+ uint8_t *last = ((uint8_t *)wrappingBuffer.data[1])
+ + mFifoBuffer.convertFramesToBytes(wrappingBuffer.numFrames[1]) - 1;
+ verifyAddressInRange(last, mFifoStorage, validBytes);
+ }
+
+ }
+
+ // Write data but do not overflow.
+ void writeMultipleDataFrames(fifo_frames_t numFrames) {
+ fifo_frames_t framesAvailable =
+ mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
+ fifo_frames_t framesToWrite = std::min(framesAvailable, numFrames);
+ for (int i = 0; i < framesToWrite; i++) {
+ mData[i] = mNextWriteIndex++;
+ }
+ fifo_frames_t actual = mFifoBuffer.write(mData, framesToWrite);
+ ASSERT_EQ(framesToWrite, actual);
+ }
+
+ // Read whatever data is available, Do not underflow.
+ void verifyMultipleDataFrames(fifo_frames_t numFrames) {
+ fifo_frames_t framesAvailable =
+ mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
+ fifo_frames_t framesToRead = std::min(framesAvailable, numFrames);
+ fifo_frames_t actual = mFifoBuffer.read(mData, framesToRead);
+ ASSERT_EQ(framesToRead, actual);
+ for (int i = 0; i < framesToRead; i++) {
+ ASSERT_EQ(mNextVerifyIndex++, mData[i]);
+ }
+ }
+
+ // Read specified number of frames
+ void verifyRequestedData(fifo_frames_t numFrames) {
+ fifo_frames_t framesAvailable =
+ mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
+ ASSERT_LE(numFrames, framesAvailable);
+ fifo_frames_t framesToRead = std::min(framesAvailable, numFrames);
+ fifo_frames_t actual = mFifoBuffer.read(mData, framesToRead);
+ ASSERT_EQ(actual, numFrames);
+ for (int i = 0; i < actual; i++) {
+ ASSERT_EQ(mNextVerifyIndex++, mData[i]);
+ }
+ }
+
+ // Wrap around the end of the buffer.
+ void checkWrappingWriteRead() {
+ constexpr int frames1 = 43;
+ constexpr int frames2 = 15;
+
+ writeMultipleDataFrames(frames1);
+ verifyWrappingBuffer();
+ verifyRequestedData(frames1);
+ verifyWrappingBuffer();
+
+ writeMultipleDataFrames(frames2);
+ verifyWrappingBuffer();
+ verifyRequestedData(frames2);
+ verifyWrappingBuffer();
+
+ verifyStorageIntegrity();
+ }
+
+ // Write and Read a specific amount of data.
+ void checkWriteRead() {
+ const fifo_frames_t capacity = mFifoBuffer.getBufferCapacityInFrames();
+ // Wrap around with the smaller region in the second half.
+ const int frames1 = capacity - 4;
+ const int frames2 = 7; // arbitrary, small
+ writeMultipleDataFrames(frames1);
+ verifyRequestedData(frames1);
+ writeMultipleDataFrames(frames2);
+ verifyRequestedData(frames2);
+
+ verifyStorageIntegrity();
+ }
+
+ // Write and Read a specific amount of data.
+ void checkWriteReadSmallLarge() {
+ const fifo_frames_t capacity = mFifoBuffer.getBufferCapacityInFrames();
+ // Wrap around with the larger region in the second half.
+ const int frames1 = capacity - 4;
+ const int frames2 = capacity - 9; // arbitrary, large
+ writeMultipleDataFrames(frames1);
+ verifyRequestedData(frames1);
+ writeMultipleDataFrames(frames2);
+ verifyRequestedData(frames2);
+
+ verifyStorageIntegrity();
+ }
+
+ // Randomly read or write up to the maximum amount of data.
+ void checkRandomWriteRead() {
+ for (int i = 0; i < 20; i++) {
+ fifo_frames_t framesEmpty =
+ mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
+ fifo_frames_t numFrames = (fifo_frames_t)(drand48() * framesEmpty);
+ writeMultipleDataFrames(numFrames);
+
+ fifo_frames_t framesFull =
+ mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
+ numFrames = (fifo_frames_t)(drand48() * framesFull);
+ verifyMultipleDataFrames(numFrames);
+ }
+
+ verifyStorageIntegrity();
+ }
+
+ // Write and Read a specific amount of data.
+ void checkNegativeCounters() {
+ fifo_counter_t counter = -9876;
+ mFifoBuffer.setWriteCounter(counter);
+ mFifoBuffer.setReadCounter(counter);
+ checkWrappingWriteRead();
+ }
+
+ // Wrap over the boundary at 0x7FFFFFFFFFFFFFFF
+ // Note that the behavior of a signed overflow is technically undefined.
+ void checkHalfWrap() {
+ fifo_counter_t counter = INT64_MAX - 10;
+ mFifoBuffer.setWriteCounter(counter);
+ mFifoBuffer.setReadCounter(counter);
+ ASSERT_GT(mFifoBuffer.getWriteCounter(), 0);
+ checkWrappingWriteRead();
+ ASSERT_LT(mFifoBuffer.getWriteCounter(), 0); // did we wrap past INT64_MAX?
+ }
+
+ // Wrap over the boundary at 0xFFFFFFFFFFFFFFFF
+ void checkFullWrap() {
+ fifo_counter_t counter = -10;
+ mFifoBuffer.setWriteCounter(counter);
+ mFifoBuffer.setReadCounter(counter);
+ ASSERT_LT(mFifoBuffer.getWriteCounter(), 0);
+ writeMultipleDataFrames(20);
+ ASSERT_GT(mFifoBuffer.getWriteCounter(), 0); // did we wrap past zero?
+ verifyStorageIntegrity();
+ }
+
+ FifoBuffer mFifoBuffer;
+ fifo_frames_t mNextWriteIndex = 0;
+ fifo_frames_t mNextVerifyIndex = 0;
+ fifo_frames_t mThreshold;
+
+ fifo_counter_t mReadIndex = 0;
+ fifo_counter_t mWriteIndex = 0;
+ int16_t mVeryBigArray[kBigArraySize]; // Use the middle of this array for the FIFO.
+ int16_t *mFifoStorage = &mVeryBigArray[kFifoDataOffset]; // Start here for storage.
+ int16_t mData[kBigArraySize]{};
+};
+
+TEST(test_fifo_buffer, fifo_write_read) {
+ constexpr int capacity = 51; // arbitrary
+ TestFifoBuffer tester(capacity);
+ tester.checkMisc();
+ tester.checkWriteRead();
+}
+
+TEST(test_fifo_buffer, fifo_wrapping_write_read) {
+ constexpr int capacity = 59; // arbitrary, a little bigger this time
+ TestFifoBuffer tester(capacity);
+ tester.checkWrappingWriteRead();
+}
+
+TEST(test_fifo_buffer, fifo_read_write_small_large) {
+ constexpr int capacity = 51; // arbitrary
+ TestFifoBuffer tester(capacity);
+ tester.checkWriteReadSmallLarge();
+}
+
+TEST(test_fifo_buffer, fifo_random_read_write) {
+ constexpr int capacity = 51; // arbitrary
+ TestFifoBuffer tester(capacity);
+ tester.checkRandomWriteRead();
+}
+
+TEST(test_fifo_buffer, fifo_random_threshold) {
+ constexpr int capacity = 67; // arbitrary
+ constexpr int threshold = 37; // arbitrary
+ TestFifoBuffer tester(capacity, threshold);
+ tester.checkRandomWriteRead();
+}
+
+TEST(test_fifo_buffer, fifo_negative_counters) {
+ constexpr int capacity = 49; // arbitrary
+ TestFifoBuffer tester(capacity);
+ tester.checkNegativeCounters();
+}
+
+TEST(test_fifo_buffer, fifo_half_wrap) {
+ constexpr int capacity = 57; // arbitrary
+ TestFifoBuffer tester(capacity);
+ tester.checkHalfWrap();
+}
+
+TEST(test_fifo_buffer, fifo_full_wrap) {
+ constexpr int capacity = 57; // arbitrary
+ TestFifoBuffer tester(capacity);
+ tester.checkFullWrap();
+}
diff --git a/media/libaaudio/tests/test_handle_tracker.cpp b/media/libaaudio/tests/test_handle_tracker.cpp
deleted file mode 100644
index c4db47a..0000000
--- a/media/libaaudio/tests/test_handle_tracker.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Unit tests for AAudio Handle Tracker
-
-#include <stdlib.h>
-#include <math.h>
-
-#include <gtest/gtest.h>
-
-#include <aaudio/AAudio.h>
-#include "utility/HandleTracker.h"
-
-// Test adding one address.
-TEST(test_handle_tracker, aaudio_handle_tracker) {
- const int MAX_HANDLES = 4;
- HandleTracker tracker(MAX_HANDLES);
- handle_tracker_type_t type = 3; // arbitrary generic type
- int data; // something that has an address we can use
- handle_tracker_address_t found;
-
- // repeat the test several times to see if it breaks
- const int SEVERAL = 5; // arbitrary
- for (int i = 0; i < SEVERAL; i++) {
- // should fail to find a bogus handle
- found = tracker.get(type, 0); // bad handle
- EXPECT_EQ(nullptr, found);
-
- // create a valid handle and use it to lookup the object again
- aaudio_handle_t dataHandle = tracker.put(type, &data);
- ASSERT_TRUE(dataHandle > 0);
- found = tracker.get(type, dataHandle);
- EXPECT_EQ(&data, found);
- found = tracker.get(type, 0); // bad handle
- EXPECT_EQ(nullptr, found);
-
- // wrong type
- found = tracker.get(type+1, dataHandle);
- EXPECT_EQ(nullptr, found);
-
- // remove from storage
- found = tracker.remove(type, dataHandle);
- EXPECT_EQ(&data, found);
- // should fail the second time
- found = tracker.remove(type, dataHandle);
- EXPECT_EQ(nullptr, found);
- }
-}
-
-// Test filling the tracker.
-TEST(test_handle_tracker, aaudio_full_up) {
- const int MAX_HANDLES = 5;
- HandleTracker tracker(MAX_HANDLES);
- handle_tracker_type_t type = 4; // arbitrary generic type
- int data[MAX_HANDLES];
- aaudio_handle_t handles[MAX_HANDLES];
- handle_tracker_address_t found;
-
- // repeat the test several times to see if it breaks
- const int SEVERAL = 5; // arbitrary
- for (int i = 0; i < SEVERAL; i++) {
- for (int i = 0; i < MAX_HANDLES; i++) {
- // add a handle
- handles[i] = tracker.put(type, &data[i]);
- ASSERT_TRUE(handles[i] > 0);
- found = tracker.get(type, handles[i]);
- EXPECT_EQ(&data[i], found);
- }
-
- // Now that it is full, try to add one more.
- aaudio_handle_t handle = tracker.put(type, &data[0]);
- EXPECT_TRUE(handle < 0);
-
- for (int i = 0; i < MAX_HANDLES; i++) {
- // look up each handle
- found = tracker.get(type, handles[i]);
- EXPECT_EQ(&data[i], found);
- }
-
- // remove one from storage
- found = tracker.remove(type, handles[2]);
- EXPECT_EQ(&data[2], found);
- // now try to look up the same handle and fail
- found = tracker.get(type, handles[2]);
- EXPECT_EQ(nullptr, found);
-
- // add that same one back
- handle = tracker.put(type, &data[2]);
- ASSERT_TRUE(handle > 0);
- found = tracker.get(type, handle);
- EXPECT_EQ(&data[2], found);
- // now use a stale handle again with a valid index and fail
- found = tracker.get(type, handles[2]);
- EXPECT_EQ(nullptr, found);
-
- // remove them all
- handles[2] = handle;
- for (int i = 0; i < MAX_HANDLES; i++) {
- // look up each handle
- found = tracker.remove(type, handles[i]);
- EXPECT_EQ(&data[i], found);
- }
- }
-}
diff --git a/media/libaaudio/tests/test_timestamps.cpp b/media/libaaudio/tests/test_timestamps.cpp
new file mode 100644
index 0000000..fb363e7
--- /dev/null
+++ b/media/libaaudio/tests/test_timestamps.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+// Play silence and recover from dead servers or disconnected devices.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
+#include "utils/AAudioExampleUtils.h"
+#include "../examples/utils/AAudioExampleUtils.h"
+
+// Arbitrary period for glitches, once per second at 48000 Hz.
+#define FORCED_UNDERRUN_PERIOD_FRAMES 48000
+// How long to sleep in a callback to cause an intentional glitch. For testing.
+#define FORCED_UNDERRUN_SLEEP_MICROS (10 * 1000)
+
+#define MAX_TIMESTAMPS 1000
+
+#define DEFAULT_TIMEOUT_NANOS ((int64_t)1000000000)
+
+#define NUM_SECONDS 1
+#define NUM_LOOPS 4
+
+typedef struct TimestampInfo {
+ int64_t framesTotal;
+ int64_t appPosition; // frames
+ int64_t appNanoseconds;
+ int64_t timestampPosition; // frames
+ int64_t timestampNanos;
+ aaudio_result_t result;
+} TimestampInfo;
+
+typedef struct TimestampCallbackData_s {
+ TimestampInfo timestamps[MAX_TIMESTAMPS];
+ int64_t framesTotal = 0;
+ int64_t nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
+ int32_t timestampCount = 0; // in timestamps
+ bool forceUnderruns = false;
+} TimestampCallbackData_t;
+
+// Callback function that fills the audio output buffer.
+aaudio_data_callback_result_t timestampDataCallbackProc(
+ AAudioStream *stream,
+ void *userData,
+ void *audioData __unused,
+ int32_t numFrames
+) {
+
+ // should not happen but just in case...
+ if (userData == nullptr) {
+ printf("ERROR - SimplePlayerDataCallbackProc needs userData\n");
+ return AAUDIO_CALLBACK_RESULT_STOP;
+ }
+ TimestampCallbackData_t *timestampData = (TimestampCallbackData_t *) userData;
+
+ aaudio_direction_t direction = AAudioStream_getDirection(stream);
+ if (direction == AAUDIO_DIRECTION_INPUT) {
+ timestampData->framesTotal += numFrames;
+ }
+
+ if (timestampData->forceUnderruns) {
+ if (timestampData->framesTotal > timestampData->nextFrameToGlitch) {
+ usleep(FORCED_UNDERRUN_SLEEP_MICROS);
+ printf("Simulate glitch at %lld\n", (long long) timestampData->framesTotal);
+ timestampData->nextFrameToGlitch += FORCED_UNDERRUN_PERIOD_FRAMES;
+ }
+ }
+
+ if (timestampData->timestampCount < MAX_TIMESTAMPS) {
+ TimestampInfo *timestamp = ×tampData->timestamps[timestampData->timestampCount];
+ timestamp->result = AAudioStream_getTimestamp(stream,
+ CLOCK_MONOTONIC,
+ ×tamp->timestampPosition,
+ ×tamp->timestampNanos);
+ timestamp->framesTotal = timestampData->framesTotal;
+ timestamp->appPosition = (direction == AAUDIO_DIRECTION_OUTPUT)
+ ? AAudioStream_getFramesWritten(stream)
+ : AAudioStream_getFramesRead(stream);
+ timestamp->appNanoseconds = getNanoseconds();
+ timestampData->timestampCount++;
+ }
+
+ if (direction == AAUDIO_DIRECTION_OUTPUT) {
+ timestampData->framesTotal += numFrames;
+ }
+ return AAUDIO_CALLBACK_RESULT_CONTINUE;
+}
+
+static TimestampCallbackData_t sTimestampData;
+
+static aaudio_result_t testTimeStamps(aaudio_policy_t mmapPolicy,
+ aaudio_sharing_mode_t sharingMode,
+ aaudio_performance_mode_t performanceMode,
+ aaudio_direction_t direction) {
+ aaudio_result_t result = AAUDIO_OK;
+
+ int32_t framesPerBurst = 0;
+ float *buffer = nullptr;
+
+ int32_t actualChannelCount = 0;
+ int32_t actualSampleRate = 0;
+ int32_t originalBufferSize = 0;
+ int32_t requestedBufferSize = 0;
+ int32_t finalBufferSize = 0;
+ aaudio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_FLOAT;
+ aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
+ aaudio_sharing_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
+
+ AAudioStreamBuilder *aaudioBuilder = nullptr;
+ AAudioStream *aaudioStream = nullptr;
+
+ memset(&sTimestampData, 0, sizeof(sTimestampData));
+
+ printf("------------ testTimeStamps(policy = %d, sharing = %s, perf = %s, dir = %s) -----------\n",
+ mmapPolicy,
+ getSharingModeText(sharingMode),
+ getPerformanceModeText(performanceMode),
+ getDirectionText(direction));
+
+ AAudio_setMMapPolicy(mmapPolicy);
+
+ // Use an AAudioStreamBuilder to contain requested parameters.
+ result = AAudio_createStreamBuilder(&aaudioBuilder);
+ if (result != AAUDIO_OK) {
+ printf("AAudio_createStreamBuilder returned %s",
+ AAudio_convertResultToText(result));
+ goto finish;
+ }
+
+ // Request stream properties.
+ AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_I16);
+ AAudioStreamBuilder_setSharingMode(aaudioBuilder, sharingMode);
+ AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, performanceMode);
+ AAudioStreamBuilder_setDirection(aaudioBuilder, direction);
+ AAudioStreamBuilder_setDataCallback(aaudioBuilder, timestampDataCallbackProc, &sTimestampData);
+
+ // Create an AAudioStream using the Builder.
+ result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
+ if (result != AAUDIO_OK) {
+ printf("AAudioStreamBuilder_openStream returned %s",
+ AAudio_convertResultToText(result));
+ goto finish;
+ }
+
+ // Check to see what kind of stream we actually got.
+ actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
+ actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
+ actualDataFormat = AAudioStream_getFormat(aaudioStream);
+
+ actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
+ if (actualSharingMode != sharingMode) {
+ printf("did not get expected sharingMode, got %3d, skipping test\n",
+ actualSharingMode);
+ result = AAUDIO_OK;
+ goto finish;
+ }
+ actualPerformanceMode = AAudioStream_getPerformanceMode(aaudioStream);
+ if (actualPerformanceMode != performanceMode) {
+ printf("did not get expected performanceMode, got %3d, skipping test\n",
+ actualPerformanceMode);
+ result = AAUDIO_OK;
+ goto finish;
+ }
+
+ printf(" chans = %3d, rate = %6d format = %d\n",
+ actualChannelCount, actualSampleRate, actualDataFormat);
+ printf(" Is MMAP used? %s\n", AAudioStream_isMMapUsed(aaudioStream)
+ ? "yes" : "no");
+
+ // This is the number of frames that are read in one chunk by a DMA controller
+ // or a DSP or a mixer.
+ framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
+ printf(" framesPerBurst = %3d\n", framesPerBurst);
+
+ originalBufferSize = AAudioStream_getBufferSizeInFrames(aaudioStream);
+ requestedBufferSize = 4 * framesPerBurst;
+ finalBufferSize = AAudioStream_setBufferSizeInFrames(aaudioStream, requestedBufferSize);
+
+ printf(" BufferSize: original = %4d, requested = %4d, final = %4d\n",
+ originalBufferSize, requestedBufferSize, finalBufferSize);
+
+ {
+ int64_t position;
+ int64_t nanoseconds;
+ result = AAudioStream_getTimestamp(aaudioStream, CLOCK_MONOTONIC, &position, &nanoseconds);
+ printf("before start, AAudioStream_getTimestamp() returns %s\n",
+ AAudio_convertResultToText(result));
+ }
+
+ for (int runs = 0; runs < NUM_LOOPS; runs++) {
+ printf("------------------ loop #%d\n", runs);
+
+ int64_t temp = sTimestampData.framesTotal;
+ memset(&sTimestampData, 0, sizeof(sTimestampData));
+ sTimestampData.framesTotal = temp;
+
+ sTimestampData.forceUnderruns = false;
+
+ result = AAudioStream_requestStart(aaudioStream);
+ if (result != AAUDIO_OK) {
+ printf("AAudioStream_requestStart returned %s",
+ AAudio_convertResultToText(result));
+ goto finish;
+ }
+
+ for (int second = 0; second < NUM_SECONDS; second++) {
+ // Give AAudio callback time to run in the background.
+ sleep(1);
+
+ // Periodically print the progress so we know it hasn't died.
+ printf("framesWritten = %d, XRuns = %d\n",
+ (int) AAudioStream_getFramesWritten(aaudioStream),
+ (int) AAudioStream_getXRunCount(aaudioStream)
+ );
+ }
+
+ result = AAudioStream_requestStop(aaudioStream);
+ if (result != AAUDIO_OK) {
+ printf("AAudioStream_requestStop returned %s\n",
+ AAudio_convertResultToText(result));
+ }
+
+ printf("timestampCount = %d\n", sTimestampData.timestampCount);
+ int printed = 0;
+ for (int i = 0; i < sTimestampData.timestampCount; i++) {
+ TimestampInfo *timestamp = &sTimestampData.timestamps[i];
+ bool posChanged = (timestamp->timestampPosition != (timestamp - 1)->timestampPosition);
+ bool timeChanged = (timestamp->timestampNanos != (timestamp - 1)->timestampNanos);
+ if ((printed < 20) && ((i < 10) || posChanged || timeChanged)) {
+ printf(" %3d : frames %8lld, xferd %8lld", i,
+ (long long) timestamp->framesTotal,
+ (long long) timestamp->appPosition);
+ if (timestamp->result != AAUDIO_OK) {
+ printf(", result = %s\n", AAudio_convertResultToText(timestamp->result));
+ } else {
+ bool negative = timestamp->timestampPosition < 0;
+ bool retro = (i > 0 && (timestamp->timestampPosition <
+ (timestamp - 1)->timestampPosition));
+ const char *message = negative ? " <=NEGATIVE!"
+ : (retro ? " <= RETROGRADE!" : "");
+
+ double latency = calculateLatencyMillis(timestamp->timestampPosition,
+ timestamp->timestampNanos,
+ timestamp->appPosition,
+ timestamp->appNanoseconds,
+ actualSampleRate);
+ printf(", STAMP: pos = %8lld, nanos = %8lld, lat = %7.1f msec %s\n",
+ (long long) timestamp->timestampPosition,
+ (long long) timestamp->timestampNanos,
+ latency,
+ message);
+ }
+ printed++;
+ }
+ }
+
+ // Avoid race conditions in AudioFlinger.
+ // There is normally a delay between a real user stopping and restarting a stream.
+ sleep(1);
+ }
+
+finish:
+ if (aaudioStream != nullptr) {
+ AAudioStream_close(aaudioStream);
+ }
+ AAudioStreamBuilder_delete(aaudioBuilder);
+ printf("result = %d = %s\n", result, AAudio_convertResultToText(result));
+
+ return result;
+}
+
+int main(int argc, char **argv) {
+ (void) argc;
+ (void *) argv;
+
+ aaudio_result_t result = AAUDIO_OK;
+
+ // Make printf print immediately so that debug info is not stuck
+ // in a buffer if we hang or crash.
+ setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+ printf("Test Timestamps V0.1.3\n");
+
+ // Legacy
+ aaudio_policy_t policy = AAUDIO_POLICY_NEVER;
+ result = testTimeStamps(policy,
+ AAUDIO_SHARING_MODE_SHARED,
+ AAUDIO_PERFORMANCE_MODE_NONE,
+ AAUDIO_DIRECTION_INPUT);
+ result = testTimeStamps(policy,
+ AAUDIO_SHARING_MODE_SHARED,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_DIRECTION_INPUT);
+ result = testTimeStamps(policy,
+ AAUDIO_SHARING_MODE_SHARED,
+ AAUDIO_PERFORMANCE_MODE_NONE,
+ AAUDIO_DIRECTION_OUTPUT);
+ result = testTimeStamps(policy,
+ AAUDIO_SHARING_MODE_SHARED,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_DIRECTION_OUTPUT);
+
+ // MMAP
+ policy = AAUDIO_POLICY_ALWAYS;
+ result = testTimeStamps(policy,
+ AAUDIO_SHARING_MODE_EXCLUSIVE,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_DIRECTION_INPUT);
+ result = testTimeStamps(policy,
+ AAUDIO_SHARING_MODE_EXCLUSIVE,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_DIRECTION_OUTPUT);
+ result = testTimeStamps(policy,
+ AAUDIO_SHARING_MODE_SHARED,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_DIRECTION_INPUT);
+ result = testTimeStamps(policy,
+ AAUDIO_SHARING_MODE_SHARED,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_DIRECTION_OUTPUT);
+
+ return (result == AAUDIO_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index a5f9ab6..b1cb0e7 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -135,7 +135,11 @@
&mStatus, &mId, &enabled);
if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
- ALOGE("set(): AudioFlinger could not create effect, status: %d", mStatus);
+ char typeBuffer[64], uuidBuffer[64];
+ guidToString(type, typeBuffer, sizeof(typeBuffer));
+ guidToString(uuid, uuidBuffer, sizeof(uuidBuffer));
+ ALOGE("set(): AudioFlinger could not create effect %s / %s, status: %d",
+ typeBuffer, uuidBuffer, mStatus);
if (iEffect == 0) {
mStatus = NO_INIT;
}
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 611cde7..ba4acc6 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -120,7 +120,7 @@
}
// No lock here: worst case we remove a NULL callback which will be a nop
if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
- AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+ AudioSystem::removeAudioDeviceCallback(this, mInput);
}
IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
mAudioRecord.clear();
@@ -274,7 +274,7 @@
mStatus = NO_ERROR;
mUserData = user;
// TODO: add audio hardware input latency here
- mLatency = (1000 * mFrameCount) / mSampleRate;
+ mLatency = (1000LL * mFrameCount) / mSampleRate;
mMarkerPosition = 0;
mMarkerReached = false;
mNewPosition = 0;
@@ -499,19 +499,26 @@
return mSelectedDeviceId;
}
+// must be called with mLock held
+void AudioRecord::updateRoutedDeviceId_l()
+{
+ // if the record is inactive, do not update actual device as the input stream maybe routed
+ // from a device not relevant to this client because of other active use cases.
+ if (!mActive) {
+ return;
+ }
+ if (mInput != AUDIO_IO_HANDLE_NONE) {
+ audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
+ if (deviceId != AUDIO_PORT_HANDLE_NONE) {
+ mRoutedDeviceId = deviceId;
+ }
+ }
+}
+
audio_port_handle_t AudioRecord::getRoutedDeviceId() {
AutoMutex lock(mLock);
- if (mInput == AUDIO_IO_HANDLE_NONE) {
- return AUDIO_PORT_HANDLE_NONE;
- }
- // if the input stream does not have an active audio patch, use either the device initially
- // selected by audio policy manager or the last routed device
- audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
- if (deviceId == AUDIO_PORT_HANDLE_NONE) {
- deviceId = mRoutedDeviceId;
- }
- mRoutedDeviceId = deviceId;
- return deviceId;
+ updateRoutedDeviceId_l();
+ return mRoutedDeviceId;
}
// -------------------------------------------------------------------------
@@ -537,9 +544,6 @@
return NO_INIT;
}
- if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
- AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
- }
audio_io_handle_t input;
// mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
@@ -744,6 +748,15 @@
}
mNotificationFramesAct = (uint32_t) notificationFrames;
+
+ //mInput != input includes the case where mInput == AUDIO_IO_HANDLE_NONE for first creation
+ if (mDeviceCallback != 0 && mInput != input) {
+ if (mInput != AUDIO_IO_HANDLE_NONE) {
+ AudioSystem::removeAudioDeviceCallback(this, mInput);
+ }
+ AudioSystem::addAudioDeviceCallback(this, input);
+ }
+
// We retain a copy of the I/O handle, but don't own the reference
mInput = input;
mRefreshRemaining = true;
@@ -763,10 +776,6 @@
mDeathNotifier = new DeathNotifier(this);
IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
- if (mDeviceCallback != 0) {
- AudioSystem::addAudioDeviceCallback(mDeviceCallback, mInput);
- }
-
return NO_ERROR;
// End of retry loop.
@@ -1238,7 +1247,7 @@
return BAD_VALUE;
}
AutoMutex lock(mLock);
- if (mDeviceCallback == callback) {
+ if (mDeviceCallback.unsafe_get() == callback.get()) {
ALOGW("%s adding same callback!", __FUNCTION__);
return INVALID_OPERATION;
}
@@ -1246,9 +1255,9 @@
if (mInput != AUDIO_IO_HANDLE_NONE) {
if (mDeviceCallback != 0) {
ALOGW("%s callback already present!", __FUNCTION__);
- AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+ AudioSystem::removeAudioDeviceCallback(this, mInput);
}
- status = AudioSystem::addAudioDeviceCallback(callback, mInput);
+ status = AudioSystem::addAudioDeviceCallback(this, mInput);
}
mDeviceCallback = callback;
return status;
@@ -1262,17 +1271,38 @@
return BAD_VALUE;
}
AutoMutex lock(mLock);
- if (mDeviceCallback != callback) {
+ if (mDeviceCallback.unsafe_get() != callback.get()) {
ALOGW("%s removing different callback!", __FUNCTION__);
return INVALID_OPERATION;
}
+ mDeviceCallback.clear();
if (mInput != AUDIO_IO_HANDLE_NONE) {
- AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+ AudioSystem::removeAudioDeviceCallback(this, mInput);
}
- mDeviceCallback = 0;
return NO_ERROR;
}
+void AudioRecord::onAudioDeviceUpdate(audio_io_handle_t audioIo,
+ audio_port_handle_t deviceId)
+{
+ sp<AudioSystem::AudioDeviceCallback> callback;
+ {
+ AutoMutex lock(mLock);
+ if (audioIo != mInput) {
+ return;
+ }
+ callback = mDeviceCallback.promote();
+ // only update device if the record is active as route changes due to other use cases are
+ // irrelevant for this client
+ if (mActive) {
+ mRoutedDeviceId = deviceId;
+ }
+ }
+ if (callback.get() != nullptr) {
+ callback->onAudioDeviceUpdate(mInput, mRoutedDeviceId);
+ }
+}
+
// =========================================================================
void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 2f710bd..cdc75ac 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -493,14 +493,16 @@
if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;
audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
- Vector < sp<AudioDeviceCallback> > callbacks;
+ Vector < wp<AudioDeviceCallback> > callbacks;
{
Mutex::Autolock _l(mLock);
switch (event) {
case AUDIO_OUTPUT_OPENED:
- case AUDIO_INPUT_OPENED: {
+ case AUDIO_OUTPUT_REGISTERED:
+ case AUDIO_INPUT_OPENED:
+ case AUDIO_INPUT_REGISTERED: {
sp<AudioIoDescriptor> oldDesc = getIoDescriptor_l(ioDesc->mIoHandle);
if (oldDesc == 0) {
mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
@@ -511,13 +513,19 @@
if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
deviceId = ioDesc->getDeviceId();
- ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
- if (ioIndex >= 0) {
- callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+ if (event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED) {
+ ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
+ if (ioIndex >= 0) {
+ callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+ }
}
}
- ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x "
- "frameCount %zu deviceId %d", event == AUDIO_OUTPUT_OPENED ? "output" : "input",
+ ALOGV("ioConfigChanged() new %s %s %d samplingRate %u, format %#x channel mask %#x "
+ "frameCount %zu deviceId %d",
+ event == AUDIO_OUTPUT_OPENED || event == AUDIO_OUTPUT_REGISTERED ?
+ "output" : "input",
+ event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED ?
+ "opened" : "registered",
ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask,
ioDesc->mFrameCount, ioDesc->getDeviceId());
} break;
@@ -563,9 +571,23 @@
} break;
}
}
+ bool callbackRemoved = false;
// callbacks.size() != 0 => ioDesc->mIoHandle and deviceId are valid
- for (size_t i = 0; i < callbacks.size(); i++) {
- callbacks[i]->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
+ for (size_t i = 0; i < callbacks.size(); ) {
+ sp<AudioDeviceCallback> callback = callbacks[i].promote();
+ if (callback.get() != nullptr) {
+ callback->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
+ i++;
+ } else {
+ callbacks.removeAt(i);
+ callbackRemoved = true;
+ }
+ }
+ // clean up callback list while we are here if some clients have disappeared without
+ // unregistering their callback
+ if (callbackRemoved) {
+ Mutex::Autolock _l(mLock);
+ mAudioDeviceCallbacks.replaceValueFor(ioDesc->mIoHandle, callbacks);
}
}
@@ -618,17 +640,17 @@
}
status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
- const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+ const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
Mutex::Autolock _l(mLock);
- Vector < sp<AudioDeviceCallback> > callbacks;
+ Vector < wp<AudioDeviceCallback> > callbacks;
ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
if (ioIndex >= 0) {
callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
}
for (size_t cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
- if (callbacks[cbIndex] == callback) {
+ if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
return INVALID_OPERATION;
}
}
@@ -639,18 +661,18 @@
}
status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
- const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+ const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
Mutex::Autolock _l(mLock);
ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
if (ioIndex < 0) {
return INVALID_OPERATION;
}
- Vector < sp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+ Vector < wp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
size_t cbIndex;
for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
- if (callbacks[cbIndex] == callback) {
+ if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
break;
}
}
@@ -1128,7 +1150,7 @@
}
status_t AudioSystem::addAudioDeviceCallback(
- const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+ const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
const sp<AudioFlingerClient> afc = getAudioFlingerClient();
if (afc == 0) {
@@ -1145,7 +1167,7 @@
}
status_t AudioSystem::removeAudioDeviceCallback(
- const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+ const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
const sp<AudioFlingerClient> afc = getAudioFlingerClient();
if (afc == 0) {
@@ -1297,7 +1319,7 @@
}
void AudioSystem::AudioPolicyServiceClient::onRecordingConfigurationUpdate(
- int event, audio_session_t session, audio_source_t source,
+ int event, const record_client_info_t *clientInfo,
const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
audio_patch_handle_t patchHandle) {
record_config_callback cb = NULL;
@@ -1307,7 +1329,7 @@
}
if (cb != NULL) {
- cb(event, session, source, clientConfig, deviceConfig, patchHandle);
+ cb(event, clientInfo, clientConfig, deviceConfig, patchHandle);
}
}
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index b0b01db..3529d2c 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -22,6 +22,7 @@
#include <math.h>
#include <sys/resource.h>
+#include <audio_utils/clock.h>
#include <audio_utils/primitives.h>
#include <binder/IPCThreadState.h>
#include <media/AudioTrack.h>
@@ -62,9 +63,12 @@
return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000;
}
-static inline nsecs_t convertTimespecToNs(const struct timespec &tv)
-{
- return tv.tv_sec * (long long)NANOS_PER_SECOND + tv.tv_nsec;
+// TODO move to audio_utils.
+static inline struct timespec convertNsToTimespec(int64_t ns) {
+ struct timespec tv;
+ tv.tv_sec = static_cast<time_t>(ns / NANOS_PER_SECOND);
+ tv.tv_nsec = static_cast<long>(ns % NANOS_PER_SECOND);
+ return tv;
}
// current monotonic time in microseconds.
@@ -272,7 +276,7 @@
}
// No lock here: worst case we remove a NULL callback which will be a nop
if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
- AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+ AudioSystem::removeAudioDeviceCallback(this, mOutput);
}
IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
mAudioTrack.clear();
@@ -543,7 +547,8 @@
mUpdatePeriod = 0;
mPosition = 0;
mReleased = 0;
- mStartUs = 0;
+ mStartNs = 0;
+ mStartFromZeroUs = 0;
AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
mSequence = 1;
mObservedSequence = mSequence;
@@ -591,6 +596,7 @@
mStartEts.clear();
}
}
+ mStartNs = systemTime(); // save this for timestamp adjustment after starting.
if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) {
// reset current position as seen by client to 0
mPosition = 0;
@@ -609,7 +615,8 @@
+ mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER]),
(long long)mStartEts.mFlushed,
(long long)mFramesWritten);
- mFramesWrittenServerOffset = -mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER];
+ // mStartEts is already adjusted by mFramesWrittenServerOffset, so we delta adjust.
+ mFramesWrittenServerOffset -= mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER];
}
mFramesWritten = 0;
mProxy->clearTimestamp(); // need new server push for valid timestamp
@@ -619,7 +626,7 @@
// since the flush is asynchronous and stop may not fully drain.
// We save the time when the track is started to later verify whether
// the counters are realistic (i.e. start from zero after this time).
- mStartUs = getNowUs();
+ mStartFromZeroUs = mStartNs / 1000;
// force refresh of remaining frames by processAudioBuffer() as last
// write before stop could be partial.
@@ -1222,19 +1229,26 @@
return mSelectedDeviceId;
}
+// must be called with mLock held
+void AudioTrack::updateRoutedDeviceId_l()
+{
+ // if the track is inactive, do not update actual device as the output stream maybe routed
+ // to a device not relevant to this client because of other active use cases.
+ if (mState != STATE_ACTIVE) {
+ return;
+ }
+ if (mOutput != AUDIO_IO_HANDLE_NONE) {
+ audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
+ if (deviceId != AUDIO_PORT_HANDLE_NONE) {
+ mRoutedDeviceId = deviceId;
+ }
+ }
+}
+
audio_port_handle_t AudioTrack::getRoutedDeviceId() {
AutoMutex lock(mLock);
- if (mOutput == AUDIO_IO_HANDLE_NONE) {
- return AUDIO_PORT_HANDLE_NONE;
- }
- // if the output stream does not have an active audio patch, use either the device initially
- // selected by audio policy manager or the last routed device
- audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
- if (deviceId == AUDIO_PORT_HANDLE_NONE) {
- deviceId = mRoutedDeviceId;
- }
- mRoutedDeviceId = deviceId;
- return deviceId;
+ updateRoutedDeviceId_l();
+ return mRoutedDeviceId;
}
status_t AudioTrack::attachAuxEffect(int effectId)
@@ -1272,7 +1286,7 @@
ALOGW("getLatency(%d) failed status %d", mOutput, status);
} else {
// FIXME don't believe this lie
- mLatency = mAfLatency + (1000 * mFrameCount) / mSampleRate;
+ mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;
}
}
@@ -1298,12 +1312,10 @@
return NO_INIT;
}
- if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
- AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
- }
audio_io_handle_t output;
audio_stream_type_t streamType = mStreamType;
audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL;
+ bool callbackAdded = false;
// mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
// After fast request is denied, we will request again if IAudioTrack is re-created.
@@ -1508,12 +1520,14 @@
sp<IMemory> iMem = track->getCblk();
if (iMem == 0) {
ALOGE("Could not get control block");
- return NO_INIT;
+ status = NO_INIT;
+ goto release;
}
void *iMemPointer = iMem->pointer();
if (iMemPointer == NULL) {
ALOGE("Could not get control block pointer");
- return NO_INIT;
+ status = NO_INIT;
+ goto release;
}
// invariant that mAudioTrack != 0 is true only after set() returns successfully
if (mAudioTrack != 0) {
@@ -1575,6 +1589,15 @@
}
}
+ //mOutput != output includes the case where mOutput == AUDIO_IO_HANDLE_NONE for first creation
+ if (mDeviceCallback != 0 && mOutput != output) {
+ if (mOutput != AUDIO_IO_HANDLE_NONE) {
+ AudioSystem::removeAudioDeviceCallback(this, mOutput);
+ }
+ AudioSystem::addAudioDeviceCallback(this, output);
+ callbackAdded = true;
+ }
+
// We retain a copy of the I/O handle, but don't own the reference
mOutput = output;
mRefreshRemaining = true;
@@ -1590,7 +1613,8 @@
buffers = mSharedBuffer->pointer();
if (buffers == NULL) {
ALOGE("Could not get buffer pointer");
- return NO_INIT;
+ status = NO_INIT;
+ goto release;
}
}
@@ -1635,15 +1659,15 @@
mDeathNotifier = new DeathNotifier(this);
IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this);
- if (mDeviceCallback != 0) {
- AudioSystem::addAudioDeviceCallback(mDeviceCallback, mOutput);
- }
-
return NO_ERROR;
}
release:
AudioSystem::releaseOutput(output, streamType, mSessionId);
+ if (callbackAdded) {
+ // note: mOutput is always valid is callbackAdded is true
+ AudioSystem::removeAudioDeviceCallback(this, mOutput);
+ }
if (status == NO_ERROR) {
status = NO_INIT;
}
@@ -2090,7 +2114,14 @@
// Convert frame units to time units
nsecs_t ns = NS_WHENEVER;
if (minFrames != (uint32_t) ~0) {
- ns = framesToNanoseconds(minFrames, sampleRate, speed) + kWaitPeriodNs;
+ // AudioFlinger consumption of client data may be irregular when coming out of device
+ // standby since the kernel buffers require filling. This is throttled to no more than 2x
+ // the expected rate in the MixerThread. Hence, we reduce the estimated time to wait by one
+ // half (but no more than half a second) to improve callback accuracy during these temporary
+ // data surges.
+ const nsecs_t estimatedNs = framesToNanoseconds(minFrames, sampleRate, speed);
+ constexpr nsecs_t maxThrottleCompensationNs = 500000000LL;
+ ns = estimatedNs - min(estimatedNs / 2, maxThrottleCompensationNs) + kWaitPeriodNs;
ns -= (timeAfterCallbacks - timeBeforeCallbacks); // account for callback time
// TODO: Should we warn if the callback time is too long?
if (ns < 0) ns = 0;
@@ -2563,7 +2594,7 @@
// We update the timestamp time even when paused.
if (mState == STATE_PAUSED /* not needed: STATE_PAUSED_STOPPING */) {
const int64_t now = systemTime();
- const int64_t at = convertTimespecToNs(timestamp.mTime);
+ const int64_t at = audio_utils_ns_from_timespec(×tamp.mTime);
const int64_t lag =
(ets.mTimeNs[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK] < 0 ||
ets.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK] < 0)
@@ -2575,8 +2606,7 @@
if (at < limit) {
ALOGV("timestamp pause lag:%lld adjusting from %lld to %lld",
(long long)lag, (long long)at, (long long)limit);
- timestamp.mTime.tv_sec = limit / NANOS_PER_SECOND;
- timestamp.mTime.tv_nsec = limit % NANOS_PER_SECOND; // compiler opt.
+ timestamp.mTime = convertNsToTimespec(limit);
}
}
mPreviousLocation = location;
@@ -2619,18 +2649,18 @@
// the previous song under gapless playback.
// However, we sometimes see zero timestamps, then a glitch of
// the previous song's position, and then correct timestamps afterwards.
- if (mStartUs != 0 && mSampleRate != 0) {
+ if (mStartFromZeroUs != 0 && mSampleRate != 0) {
static const int kTimeJitterUs = 100000; // 100 ms
static const int k1SecUs = 1000000;
const int64_t timeNow = getNowUs();
- if (timeNow < mStartUs + k1SecUs) { // within first second of starting
+ if (timeNow < mStartFromZeroUs + k1SecUs) { // within first second of starting
const int64_t timestampTimeUs = convertTimespecToUs(timestamp.mTime);
- if (timestampTimeUs < mStartUs) {
+ if (timestampTimeUs < mStartFromZeroUs) {
return WOULD_BLOCK; // stale timestamp time, occurs before start.
}
- const int64_t deltaTimeUs = timestampTimeUs - mStartUs;
+ const int64_t deltaTimeUs = timestampTimeUs - mStartFromZeroUs;
const int64_t deltaPositionByUs = (double)timestamp.mPosition * 1000000
/ ((double)mSampleRate * mPlaybackRate.mSpeed);
@@ -2653,10 +2683,10 @@
return WOULD_BLOCK;
}
if (deltaPositionByUs != 0) {
- mStartUs = 0; // don't check again, we got valid nonzero position.
+ mStartFromZeroUs = 0; // don't check again, we got valid nonzero position.
}
} else {
- mStartUs = 0; // don't check again, start time expired.
+ mStartFromZeroUs = 0; // don't check again, start time expired.
}
mTimestampStartupGlitchReported = false;
}
@@ -2694,13 +2724,33 @@
// Prevent retrograde motion in timestamp.
// This is sometimes caused by erratic reports of the available space in the ALSA drivers.
if (status == NO_ERROR) {
+ // previousTimestampValid is set to false when starting after a stop or flush.
if (previousTimestampValid) {
- const int64_t previousTimeNanos = convertTimespecToNs(mPreviousTimestamp.mTime);
- const int64_t currentTimeNanos = convertTimespecToNs(timestamp.mTime);
+ const int64_t previousTimeNanos =
+ audio_utils_ns_from_timespec(&mPreviousTimestamp.mTime);
+ int64_t currentTimeNanos = audio_utils_ns_from_timespec(×tamp.mTime);
+
+ // Fix stale time when checking timestamp right after start().
+ //
+ // For offload compatibility, use a default lag value here.
+ // Any time discrepancy between this update and the pause timestamp is handled
+ // by the retrograde check afterwards.
+ const int64_t lagNs = int64_t(mAfLatency * 1000000LL);
+ const int64_t limitNs = mStartNs - lagNs;
+ if (currentTimeNanos < limitNs) {
+ ALOGD("correcting timestamp time for pause, "
+ "currentTimeNanos: %lld < limitNs: %lld < mStartNs: %lld",
+ (long long)currentTimeNanos, (long long)limitNs, (long long)mStartNs);
+ timestamp.mTime = convertNsToTimespec(limitNs);
+ currentTimeNanos = limitNs;
+ }
+
+ // retrograde check
if (currentTimeNanos < previousTimeNanos) {
ALOGW("retrograde timestamp time corrected, %lld < %lld",
(long long)currentTimeNanos, (long long)previousTimeNanos);
timestamp.mTime = mPreviousTimestamp.mTime;
+ // currentTimeNanos not used below.
}
// Looking at signed delta will work even when the timestamps
@@ -2726,7 +2776,7 @@
#if 0
// Uncomment this to verify audio timestamp rate.
const int64_t deltaTime =
- convertTimespecToNs(timestamp.mTime) - previousTimeNanos;
+ audio_utils_ns_from_timespec(×tamp.mTime) - previousTimeNanos;
if (deltaTime != 0) {
const int64_t computedSampleRate =
deltaPosition * (long long)NANOS_PER_SECOND / deltaTime;
@@ -2818,7 +2868,7 @@
return BAD_VALUE;
}
AutoMutex lock(mLock);
- if (mDeviceCallback == callback) {
+ if (mDeviceCallback.unsafe_get() == callback.get()) {
ALOGW("%s adding same callback!", __FUNCTION__);
return INVALID_OPERATION;
}
@@ -2826,9 +2876,9 @@
if (mOutput != AUDIO_IO_HANDLE_NONE) {
if (mDeviceCallback != 0) {
ALOGW("%s callback already present!", __FUNCTION__);
- AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+ AudioSystem::removeAudioDeviceCallback(this, mOutput);
}
- status = AudioSystem::addAudioDeviceCallback(callback, mOutput);
+ status = AudioSystem::addAudioDeviceCallback(this, mOutput);
}
mDeviceCallback = callback;
return status;
@@ -2842,17 +2892,39 @@
return BAD_VALUE;
}
AutoMutex lock(mLock);
- if (mDeviceCallback != callback) {
+ if (mDeviceCallback.unsafe_get() != callback.get()) {
ALOGW("%s removing different callback!", __FUNCTION__);
return INVALID_OPERATION;
}
+ mDeviceCallback.clear();
if (mOutput != AUDIO_IO_HANDLE_NONE) {
- AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+ AudioSystem::removeAudioDeviceCallback(this, mOutput);
}
- mDeviceCallback = 0;
return NO_ERROR;
}
+
+void AudioTrack::onAudioDeviceUpdate(audio_io_handle_t audioIo,
+ audio_port_handle_t deviceId)
+{
+ sp<AudioSystem::AudioDeviceCallback> callback;
+ {
+ AutoMutex lock(mLock);
+ if (audioIo != mOutput) {
+ return;
+ }
+ callback = mDeviceCallback.promote();
+ // only update device if the track is active as route changes due to other use cases are
+ // irrelevant for this client
+ if (mState == STATE_ACTIVE) {
+ mRoutedDeviceId = deviceId;
+ }
+ }
+ if (callback.get() != nullptr) {
+ callback->onAudioDeviceUpdate(mOutput, mRoutedDeviceId);
+ }
+}
+
status_t AudioTrack::pendingDuration(int32_t *msec, ExtendedTimestamp::Location location)
{
if (msec == nullptr ||
@@ -2910,7 +2982,7 @@
case STATE_STOPPED:
if (isOffloadedOrDirect_l()) {
// check if we have started in the past to return true.
- return mStartUs > 0;
+ return mStartFromZeroUs > 0;
}
// A normal audio track may still be draining, so
// check if stream has ended. This covers fasttrack position
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index 08c37f8..7bf4f99 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -36,7 +36,7 @@
// a value between "other" + 1 and "other" + INT32_MAX, the choice of
// which needs to be the "least recently used" sequence value for "self".
// In general, this means (new_self) returned is max(self, other) + 1.
-
+__attribute__((no_sanitize("integer")))
static uint32_t incrementSequence(uint32_t self, uint32_t other) {
int32_t diff = (int32_t) self - (int32_t) other;
if (diff >= 0 && diff < INT32_MAX) {
@@ -393,6 +393,7 @@
// ---------------------------------------------------------------------------
+__attribute__((no_sanitize("integer")))
void AudioTrackClientProxy::flush()
{
// This works for mFrameCountP2 <= 2^30
@@ -840,6 +841,25 @@
return filled;
}
+__attribute__((no_sanitize("integer")))
+size_t AudioTrackServerProxy::framesReadySafe() const
+{
+ if (mIsShutdown) {
+ return 0;
+ }
+ const audio_track_cblk_t* cblk = mCblk;
+ const int32_t flush = android_atomic_acquire_load(&cblk->u.mStreaming.mFlush);
+ if (flush != mFlush) {
+ return mFrameCount;
+ }
+ const int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
+ const ssize_t filled = rear - cblk->u.mStreaming.mFront;
+ if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
+ return 0; // error condition, silently return 0.
+ }
+ return filled;
+}
+
bool AudioTrackServerProxy::setStreamEndDone() {
audio_track_cblk_t* cblk = mCblk;
bool old =
@@ -851,6 +871,7 @@
return old;
}
+__attribute__((no_sanitize("integer")))
void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
{
audio_track_cblk_t* cblk = mCblk;
@@ -908,6 +929,11 @@
return mFramesReadySafe;
}
+size_t StaticAudioTrackServerProxy::framesReadySafe() const
+{
+ return mFramesReadySafe;
+}
+
status_t StaticAudioTrackServerProxy::updateStateWithLoop(
StaticAudioTrackState *localState, const StaticAudioTrackState &update) const
{
@@ -1001,6 +1027,7 @@
return (ssize_t) mState.mPosition;
}
+__attribute__((no_sanitize("integer")))
status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
{
if (mIsShutdown) {
@@ -1047,6 +1074,7 @@
return NO_ERROR;
}
+__attribute__((no_sanitize("integer")))
void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
{
size_t stepCount = buffer->mFrameCount;
diff --git a/media/libaudioclient/IAudioPolicyServiceClient.cpp b/media/libaudioclient/IAudioPolicyServiceClient.cpp
index 98a0521..ad7f1de 100644
--- a/media/libaudioclient/IAudioPolicyServiceClient.cpp
+++ b/media/libaudioclient/IAudioPolicyServiceClient.cpp
@@ -48,6 +48,18 @@
data.writeInt32((int32_t) config->format);
}
+inline void readRecordClientInfoFromParcel(const Parcel& data, record_client_info_t *clientInfo) {
+ clientInfo->uid = (uid_t) data.readUint32();
+ clientInfo->session = (audio_session_t) data.readInt32();
+ clientInfo->source = (audio_source_t) data.readInt32();
+}
+
+inline void writeRecordClientInfoFromParcel(Parcel& data, const record_client_info_t *clientInfo) {
+ data.writeUint32((uint32_t) clientInfo->uid);
+ data.writeInt32((int32_t) clientInfo->session);
+ data.writeInt32((int32_t) clientInfo->source);
+}
+
// ----------------------------------------------------------------------
class BpAudioPolicyServiceClient : public BpInterface<IAudioPolicyServiceClient>
{
@@ -80,14 +92,13 @@
remote()->transact(MIX_STATE_UPDATE, data, &reply, IBinder::FLAG_ONEWAY);
}
- void onRecordingConfigurationUpdate(int event, audio_session_t session,
- audio_source_t source, const audio_config_base_t *clientConfig,
+ void onRecordingConfigurationUpdate(int event, const record_client_info_t *clientInfo,
+ const audio_config_base_t *clientConfig,
const audio_config_base_t *deviceConfig, audio_patch_handle_t patchHandle) {
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyServiceClient::getInterfaceDescriptor());
data.writeInt32(event);
- data.writeInt32(session);
- data.writeInt32(source);
+ writeRecordClientInfoFromParcel(data, clientInfo);
writeAudioConfigBaseToParcel(data, clientConfig);
writeAudioConfigBaseToParcel(data, deviceConfig);
data.writeInt32(patchHandle);
@@ -123,14 +134,14 @@
case RECORDING_CONFIGURATION_UPDATE: {
CHECK_INTERFACE(IAudioPolicyServiceClient, data, reply);
int event = (int) data.readInt32();
- audio_session_t session = (audio_session_t) data.readInt32();
- audio_source_t source = (audio_source_t) data.readInt32();
+ record_client_info_t clientInfo;
audio_config_base_t clientConfig;
audio_config_base_t deviceConfig;
+ readRecordClientInfoFromParcel(data, &clientInfo);
readAudioConfigBaseFromParcel(data, &clientConfig);
readAudioConfigBaseFromParcel(data, &deviceConfig);
audio_patch_handle_t patchHandle = (audio_patch_handle_t) data.readInt32();
- onRecordingConfigurationUpdate(event, session, source, &clientConfig, &deviceConfig,
+ onRecordingConfigurationUpdate(event, &clientInfo, &clientConfig, &deviceConfig,
patchHandle);
return NO_ERROR;
} break;
diff --git a/media/libaudioclient/OWNERS b/media/libaudioclient/OWNERS
new file mode 100644
index 0000000..482b9fb
--- /dev/null
+++ b/media/libaudioclient/OWNERS
@@ -0,0 +1,3 @@
+gkasten@google.com
+jmtrivi@google.com
+mnaganov@google.com
diff --git a/media/libaudioclient/include/media/AudioIoDescriptor.h b/media/libaudioclient/include/media/AudioIoDescriptor.h
index fed86c9..859f1a9 100644
--- a/media/libaudioclient/include/media/AudioIoDescriptor.h
+++ b/media/libaudioclient/include/media/AudioIoDescriptor.h
@@ -20,9 +20,11 @@
namespace android {
enum audio_io_config_event {
+ AUDIO_OUTPUT_REGISTERED,
AUDIO_OUTPUT_OPENED,
AUDIO_OUTPUT_CLOSED,
AUDIO_OUTPUT_CONFIG_CHANGED,
+ AUDIO_INPUT_REGISTERED,
AUDIO_INPUT_OPENED,
AUDIO_INPUT_CLOSED,
AUDIO_INPUT_CONFIG_CHANGED,
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index e6a5efb..dd72170 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -33,7 +33,7 @@
// ----------------------------------------------------------------------------
-class AudioRecord : public RefBase
+class AudioRecord : public AudioSystem::AudioDeviceCallback
{
public:
@@ -424,7 +424,12 @@
/* Returns the ID of the audio device actually used by the input to which this AudioRecord
* is attached.
- * A value of AUDIO_PORT_HANDLE_NONE indicates the AudioRecord is not attached to any input.
+ * The device ID is relevant only if the AudioRecord is active.
+ * When the AudioRecord is inactive, the device ID returned can be either:
+ * - AUDIO_PORT_HANDLE_NONE if the AudioRecord is not attached to any output.
+ * - The device ID used before paused or stopped.
+ * - The device ID selected by audio policy manager of setOutputDevice() if the AudioRecord
+ * has not been started yet.
*
* Parameters:
* none.
@@ -454,6 +459,10 @@
status_t removeAudioDeviceCallback(
const sp<AudioSystem::AudioDeviceCallback>& callback);
+ // AudioSystem::AudioDeviceCallback> virtuals
+ virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+ audio_port_handle_t deviceId);
+
private:
/* If nonContig is non-NULL, it is an output parameter that will be set to the number of
* additional non-contiguous frames that are predicted to be available immediately,
@@ -561,6 +570,8 @@
// FIXME enum is faster than strcmp() for parameter 'from'
status_t restoreRecord_l(const char *from);
+ void updateRoutedDeviceId_l();
+
sp<AudioRecordThread> mAudioRecordThread;
mutable Mutex mLock;
@@ -665,7 +676,7 @@
audio_port_handle_t mRoutedDeviceId; // Device actually selected by audio policy manager:
// May not match the app selection depending on other
// activity and connected devices
- sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+ wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
audio_port_handle_t mPortId; // unique ID allocated by audio policy
};
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 2e39d23..5a81d83 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -33,7 +33,7 @@
typedef void (*audio_error_callback)(status_t err);
typedef void (*dynamic_policy_callback)(int event, String8 regId, int val);
-typedef void (*record_config_callback)(int event, audio_session_t session, int source,
+typedef void (*record_config_callback)(int event, const record_client_info_t *clientInfo,
const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
audio_patch_handle_t patchHandle);
@@ -370,9 +370,9 @@
audio_port_handle_t deviceId) = 0;
};
- static status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+ static status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
audio_io_handle_t audioIo);
- static status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+ static status_t removeAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
audio_io_handle_t audioIo);
static audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
@@ -403,9 +403,9 @@
const sp<AudioIoDescriptor>& ioDesc);
- status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+ status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
audio_io_handle_t audioIo);
- status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+ status_t removeAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
audio_io_handle_t audioIo);
audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
@@ -413,7 +413,7 @@
private:
Mutex mLock;
DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> > mIoDescriptors;
- DefaultKeyedVector<audio_io_handle_t, Vector < sp<AudioDeviceCallback> > >
+ DefaultKeyedVector<audio_io_handle_t, Vector < wp<AudioDeviceCallback> > >
mAudioDeviceCallbacks;
// cached values for recording getInputBufferSize() queries
size_t mInBuffSize; // zero indicates cache is invalid
@@ -440,8 +440,9 @@
virtual void onAudioPortListUpdate();
virtual void onAudioPatchListUpdate();
virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
- virtual void onRecordingConfigurationUpdate(int event, audio_session_t session,
- audio_source_t source, const audio_config_base_t *clientConfig,
+ virtual void onRecordingConfigurationUpdate(int event,
+ const record_client_info_t *clientInfo,
+ const audio_config_base_t *clientConfig,
const audio_config_base_t *deviceConfig, audio_patch_handle_t patchHandle);
private:
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index b168fc9..47d87e9 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -35,7 +35,7 @@
// ----------------------------------------------------------------------------
-class AudioTrack : public RefBase
+class AudioTrack : public AudioSystem::AudioDeviceCallback
{
public:
@@ -605,7 +605,11 @@
/* Returns the ID of the audio device actually used by the output to which this AudioTrack is
* attached.
- * A value of AUDIO_PORT_HANDLE_NONE indicates the audio track is not attached to any output.
+ * When the AudioTrack is inactive, the device ID returned can be either:
+ * - AUDIO_PORT_HANDLE_NONE if the AudioTrack is not attached to any output.
+ * - The device ID used before paused or stopped.
+ * - The device ID selected by audio policy manager of setOutputDevice() if the AudioTrack
+ * has not been started yet.
*
* Parameters:
* none.
@@ -845,6 +849,12 @@
status_t removeAudioDeviceCallback(
const sp<AudioSystem::AudioDeviceCallback>& callback);
+ // AudioSystem::AudioDeviceCallback> virtuals
+ virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+ audio_port_handle_t deviceId);
+
+
+
/* Obtain the pending duration in milliseconds for playback of pure PCM
* (mixable without embedded timing) data remaining in AudioTrack.
*
@@ -974,6 +984,8 @@
void restartIfDisabled();
+ void updateRoutedDeviceId_l();
+
// Next 4 fields may be changed if IAudioTrack is re-created, but always != 0
sp<IAudioTrack> mAudioTrack;
sp<IMemory> mCblkMemory;
@@ -1085,8 +1097,10 @@
// reset by stop() but continues monotonically
// after new IAudioTrack to restore mPosition,
// and could be easily widened to uint64_t
- int64_t mStartUs; // the start time after flush or stop.
+ int64_t mStartFromZeroUs; // the start time after flush or stop,
+ // when position should be 0.
// only used for offloaded and direct tracks.
+ int64_t mStartNs; // the time when start() is called.
ExtendedTimestamp mStartEts; // Extended timestamp at start for normal
// AudioTracks.
AudioTimestamp mStartTs; // Timestamp at start for offloaded or direct
@@ -1163,7 +1177,7 @@
uid_t mClientUid;
pid_t mClientPid;
- sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+ wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
audio_port_handle_t mPortId; // unique ID allocated by audio policy
};
diff --git a/media/libaudioclient/include/media/IAudioPolicyServiceClient.h b/media/libaudioclient/include/media/IAudioPolicyServiceClient.h
index d94ad00..e0d2495 100644
--- a/media/libaudioclient/include/media/IAudioPolicyServiceClient.h
+++ b/media/libaudioclient/include/media/IAudioPolicyServiceClient.h
@@ -26,6 +26,16 @@
// ----------------------------------------------------------------------------
+struct record_client_info {
+ uid_t uid;
+ audio_session_t session;
+ audio_source_t source;
+};
+
+typedef struct record_client_info record_client_info_t;
+
+// ----------------------------------------------------------------------------
+
class IAudioPolicyServiceClient : public IInterface
{
public:
@@ -38,8 +48,8 @@
// Notifies a change in the mixing state of a specific mix in a dynamic audio policy
virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
// Notifies a change of audio recording configuration
- virtual void onRecordingConfigurationUpdate(int event, audio_session_t session,
- audio_source_t source,
+ virtual void onRecordingConfigurationUpdate(int event,
+ const record_client_info_t *clientInfo,
const audio_config_base_t *clientConfig,
const audio_config_base_t *deviceConfig,
audio_patch_handle_t patchHandle) = 0;
diff --git a/media/libaudiohal/Android.mk b/media/libaudiohal/Android.mk
index e592169..827908e 100644
--- a/media/libaudiohal/Android.mk
+++ b/media/libaudiohal/Android.mk
@@ -3,6 +3,7 @@
include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := \
+ libaudioutils \
libcutils \
liblog \
libutils \
diff --git a/media/libaudiohal/DeviceHalHidl.cpp b/media/libaudiohal/DeviceHalHidl.cpp
index 71fbd98..49ef991 100644
--- a/media/libaudiohal/DeviceHalHidl.cpp
+++ b/media/libaudiohal/DeviceHalHidl.cpp
@@ -98,7 +98,8 @@
} // namespace
DeviceHalHidl::DeviceHalHidl(const sp<IDevice>& device)
- : ConversionHelperHidl("Device"), mDevice(device) {
+ : ConversionHelperHidl("Device"), mDevice(device),
+ mPrimaryDevice(IPrimaryDevice::castFrom(device)) {
}
DeviceHalHidl::~DeviceHalHidl() {
@@ -120,24 +121,21 @@
status_t DeviceHalHidl::setVoiceVolume(float volume) {
if (mDevice == 0) return NO_INIT;
- sp<IPrimaryDevice> primaryDev = IPrimaryDevice::castFrom(mDevice);
- if (primaryDev == 0) return INVALID_OPERATION;
- return processReturn("setVoiceVolume", primaryDev->setVoiceVolume(volume));
+ if (mPrimaryDevice == 0) return INVALID_OPERATION;
+ return processReturn("setVoiceVolume", mPrimaryDevice->setVoiceVolume(volume));
}
status_t DeviceHalHidl::setMasterVolume(float volume) {
if (mDevice == 0) return NO_INIT;
- sp<IPrimaryDevice> primaryDev = IPrimaryDevice::castFrom(mDevice);
- if (primaryDev == 0) return INVALID_OPERATION;
- return processReturn("setMasterVolume", primaryDev->setMasterVolume(volume));
+ if (mPrimaryDevice == 0) return INVALID_OPERATION;
+ return processReturn("setMasterVolume", mPrimaryDevice->setMasterVolume(volume));
}
status_t DeviceHalHidl::getMasterVolume(float *volume) {
if (mDevice == 0) return NO_INIT;
- sp<IPrimaryDevice> primaryDev = IPrimaryDevice::castFrom(mDevice);
- if (primaryDev == 0) return INVALID_OPERATION;
+ if (mPrimaryDevice == 0) return INVALID_OPERATION;
Result retval;
- Return<void> ret = primaryDev->getMasterVolume(
+ Return<void> ret = mPrimaryDevice->getMasterVolume(
[&](Result r, float v) {
retval = r;
if (retval == Result::OK) {
@@ -149,9 +147,8 @@
status_t DeviceHalHidl::setMode(audio_mode_t mode) {
if (mDevice == 0) return NO_INIT;
- sp<IPrimaryDevice> primaryDev = IPrimaryDevice::castFrom(mDevice);
- if (primaryDev == 0) return INVALID_OPERATION;
- return processReturn("setMode", primaryDev->setMode(AudioMode(mode)));
+ if (mPrimaryDevice == 0) return INVALID_OPERATION;
+ return processReturn("setMode", mPrimaryDevice->setMode(AudioMode(mode)));
}
status_t DeviceHalHidl::setMicMute(bool state) {
diff --git a/media/libaudiohal/DeviceHalHidl.h b/media/libaudiohal/DeviceHalHidl.h
index 9da02a4..8651b51 100644
--- a/media/libaudiohal/DeviceHalHidl.h
+++ b/media/libaudiohal/DeviceHalHidl.h
@@ -18,11 +18,13 @@
#define ANDROID_HARDWARE_DEVICE_HAL_HIDL_H
#include <android/hardware/audio/2.0/IDevice.h>
+#include <android/hardware/audio/2.0/IPrimaryDevice.h>
#include <media/audiohal/DeviceHalInterface.h>
#include "ConversionHelperHidl.h"
using ::android::hardware::audio::V2_0::IDevice;
+using ::android::hardware::audio::V2_0::IPrimaryDevice;
using ::android::hardware::Return;
namespace android {
@@ -110,6 +112,7 @@
private:
friend class DevicesFactoryHalHidl;
sp<IDevice> mDevice;
+ sp<IPrimaryDevice> mPrimaryDevice; // Null if it's not a primary device.
// Can not be constructed directly by clients.
explicit DeviceHalHidl(const sp<IDevice>& device);
diff --git a/media/libaudiohal/EffectHalHidl.cpp b/media/libaudiohal/EffectHalHidl.cpp
index b49b975..61fb6bab 100644
--- a/media/libaudiohal/EffectHalHidl.cpp
+++ b/media/libaudiohal/EffectHalHidl.cpp
@@ -40,7 +40,7 @@
namespace android {
EffectHalHidl::EffectHalHidl(const sp<IEffect>& effect, uint64_t effectId)
- : mEffect(effect), mEffectId(effectId), mBuffersChanged(true) {
+ : mEffect(effect), mEffectId(effectId), mBuffersChanged(true), mEfGroup(nullptr) {
}
EffectHalHidl::~EffectHalHidl() {
@@ -49,6 +49,9 @@
mEffect.clear();
hardware::IPCThreadState::self()->flushCommands();
}
+ if (mEfGroup) {
+ EventFlag::deleteEventFlag(&mEfGroup);
+ }
}
// static
diff --git a/media/libaudiohal/OWNERS b/media/libaudiohal/OWNERS
new file mode 100644
index 0000000..1456ab6
--- /dev/null
+++ b/media/libaudiohal/OWNERS
@@ -0,0 +1,2 @@
+krocard@google.com
+mnaganov@google.com
diff --git a/media/libaudiohal/StreamHalHidl.cpp b/media/libaudiohal/StreamHalHidl.cpp
index 42785d5..0cafa36 100644
--- a/media/libaudiohal/StreamHalHidl.cpp
+++ b/media/libaudiohal/StreamHalHidl.cpp
@@ -47,7 +47,20 @@
StreamHalHidl::StreamHalHidl(IStream *stream)
: ConversionHelperHidl("Stream"),
mStream(stream),
- mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT) {
+ mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
+ mCachedBufferSize(0){
+
+ // Instrument audio signal power logging.
+ // Note: This assumes channel mask, format, and sample rate do not change after creation.
+ if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) {
+ // Obtain audio properties (see StreamHalHidl::getAudioProperties() below).
+ Return<void> ret = mStream->getAudioProperties(
+ [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
+ mStreamPowerLog.init(sr,
+ static_cast<audio_channel_mask_t>(m),
+ static_cast<audio_format_t>(f));
+ });
+ }
}
StreamHalHidl::~StreamHalHidl() {
@@ -61,7 +74,11 @@
status_t StreamHalHidl::getBufferSize(size_t *size) {
if (!mStream) return NO_INIT;
- return processReturn("getBufferSize", mStream->getBufferSize(), size);
+ status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
+ if (status == OK) {
+ mCachedBufferSize = *size;
+ }
+ return status;
}
status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
@@ -135,6 +152,7 @@
hidlHandle->data[0] = fd;
Return<void> ret = mStream->debugDump(hidlHandle);
native_handle_delete(hidlHandle);
+ mStreamPowerLog.dump(fd);
return processReturn("dump", ret);
}
@@ -189,6 +207,14 @@
return OK;
}
+status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
+ if (mCachedBufferSize != 0) {
+ *size = mCachedBufferSize;
+ return OK;
+ }
+ return getBufferSize(size);
+}
+
bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
return true;
@@ -307,11 +333,22 @@
}
status_t status;
- if (!mDataMQ && (status = prepareForWriting(bytes)) != OK) {
- return status;
+ if (!mDataMQ) {
+ // In case if playback starts close to the end of a compressed track, the bytes
+ // that need to be written is less than the actual buffer size. Need to use
+ // full buffer size for the MQ since otherwise after seeking back to the middle
+ // data will be truncated.
+ size_t bufferSize;
+ if ((status = getCachedBufferSize(&bufferSize)) != OK) {
+ return status;
+ }
+ if (bytes > bufferSize) bufferSize = bytes;
+ if ((status = prepareForWriting(bufferSize)) != OK) {
+ return status;
+ }
}
- return callWriterThread(
+ status = callWriterThread(
WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
[&] (const WriteStatus& writeStatus) {
*written = writeStatus.reply.written;
@@ -320,6 +357,8 @@
"hal reports more bytes written than asked for: %lld > %lld",
(long long)*written, (long long)bytes);
});
+ mStreamPowerLog.log(buffer, *written);
+ return status;
}
status_t StreamOutHalHidl::callWriterThread(
@@ -580,7 +619,7 @@
ReadParameters params;
params.command = ReadCommand::READ;
params.params.read = bytes;
- return callReaderThread(params, "read",
+ status = callReaderThread(params, "read",
[&](const ReadStatus& readStatus) {
const size_t availToRead = mDataMQ->availableToRead();
if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
@@ -591,6 +630,8 @@
(int32_t)availToRead, (int32_t)readStatus.reply.read);
*read = readStatus.reply.read;
});
+ mStreamPowerLog.log(buffer, *read);
+ return status;
}
status_t StreamInHalHidl::callReaderThread(
diff --git a/media/libaudiohal/StreamHalHidl.h b/media/libaudiohal/StreamHalHidl.h
index a7df276..d4ab943 100644
--- a/media/libaudiohal/StreamHalHidl.h
+++ b/media/libaudiohal/StreamHalHidl.h
@@ -27,6 +27,7 @@
#include <media/audiohal/StreamHalInterface.h>
#include "ConversionHelperHidl.h"
+#include "StreamPowerLog.h"
using ::android::hardware::audio::V2_0::IStream;
using ::android::hardware::audio::V2_0::IStreamIn;
@@ -101,12 +102,18 @@
// The destructor automatically closes the stream.
virtual ~StreamHalHidl();
+ status_t getCachedBufferSize(size_t *size);
+
bool requestHalThreadPriority(pid_t threadPid, pid_t threadId);
+ // mStreamPowerLog is used for audio signal power logging.
+ StreamPowerLog mStreamPowerLog;
+
private:
const int HAL_THREAD_PRIORITY_DEFAULT = -1;
IStream *mStream;
int mHalThreadPriority;
+ size_t mCachedBufferSize;
};
class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl {
diff --git a/media/libaudiohal/StreamHalLocal.cpp b/media/libaudiohal/StreamHalLocal.cpp
index 05800a0..dc17f5c 100644
--- a/media/libaudiohal/StreamHalLocal.cpp
+++ b/media/libaudiohal/StreamHalLocal.cpp
@@ -27,7 +27,15 @@
namespace android {
StreamHalLocal::StreamHalLocal(audio_stream_t *stream, sp<DeviceHalLocal> device)
- : mDevice(device), mStream(stream) {
+ : mDevice(device),
+ mStream(stream) {
+ // Instrument audio signal power logging.
+ // Note: This assumes channel mask, format, and sample rate do not change after creation.
+ if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) {
+ mStreamPowerLog.init(mStream->get_sample_rate(mStream),
+ mStream->get_channels(mStream),
+ mStream->get_format(mStream));
+ }
}
StreamHalLocal::~StreamHalLocal() {
@@ -95,7 +103,9 @@
}
status_t StreamHalLocal::dump(int fd) {
- return mStream->dump(mStream, fd);
+ status_t status = mStream->dump(mStream, fd);
+ mStreamPowerLog.dump(fd);
+ return status;
}
status_t StreamHalLocal::setHalThreadPriority(int) {
@@ -133,6 +143,7 @@
ssize_t writeResult = mStream->write(mStream, buffer, bytes);
if (writeResult > 0) {
*written = writeResult;
+ mStreamPowerLog.log(buffer, *written);
return OK;
} else {
*written = 0;
@@ -266,6 +277,7 @@
ssize_t readResult = mStream->read(mStream, buffer, bytes);
if (readResult > 0) {
*read = readResult;
+ mStreamPowerLog.log( buffer, *read);
return OK;
} else {
*read = 0;
diff --git a/media/libaudiohal/StreamHalLocal.h b/media/libaudiohal/StreamHalLocal.h
index 8c96c1f..c7136df 100644
--- a/media/libaudiohal/StreamHalLocal.h
+++ b/media/libaudiohal/StreamHalLocal.h
@@ -18,6 +18,7 @@
#define ANDROID_HARDWARE_STREAM_HAL_LOCAL_H
#include <media/audiohal/StreamHalInterface.h>
+#include "StreamPowerLog.h"
namespace android {
@@ -83,6 +84,9 @@
sp<DeviceHalLocal> mDevice;
+ // mStreamPowerLog is used for audio signal power logging.
+ StreamPowerLog mStreamPowerLog;
+
private:
audio_stream_t *mStream;
};
diff --git a/media/libaudiohal/StreamPowerLog.h b/media/libaudiohal/StreamPowerLog.h
new file mode 100644
index 0000000..a78b1aa
--- /dev/null
+++ b/media/libaudiohal/StreamPowerLog.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 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_HARDWARE_STREAM_POWER_LOG_H
+#define ANDROID_HARDWARE_STREAM_POWER_LOG_H
+
+#include <audio_utils/clock.h>
+#include <audio_utils/PowerLog.h>
+#include <cutils/properties.h>
+#include <system/audio.h>
+
+namespace android {
+
+class StreamPowerLog {
+public:
+ StreamPowerLog() :
+ mIsUserDebugOrEngBuild(is_userdebug_or_eng_build()),
+ mPowerLog(nullptr),
+ mFrameSize(0) {
+ // use init() to set up the power log.
+ }
+
+ ~StreamPowerLog() {
+ power_log_destroy(mPowerLog); // OK for null mPowerLog
+ mPowerLog = nullptr;
+ }
+
+ // A one-time initialization (do not call twice) before using StreamPowerLog.
+ void init(uint32_t sampleRate, audio_channel_mask_t channelMask, audio_format_t format) {
+ if (mPowerLog == nullptr) {
+ // Note: A way to get channel count for both input and output channel masks
+ // but does not check validity of the channel mask.
+ const uint32_t channelCount = popcount(audio_channel_mask_get_bits(channelMask));
+ mFrameSize = channelCount * audio_bytes_per_sample(format);
+ if (mFrameSize > 0) {
+ const size_t kPowerLogFramesPerEntry =
+ (long long)sampleRate * kPowerLogSamplingIntervalMs / 1000;
+ mPowerLog = power_log_create(
+ sampleRate,
+ channelCount,
+ format,
+ kPowerLogEntries,
+ kPowerLogFramesPerEntry);
+ }
+ }
+ // mPowerLog may be NULL (not the right build, format not accepted, etc.).
+ }
+
+ // Dump the power log to fd.
+ void dump(int fd) const {
+ // OK for null mPowerLog
+ (void)power_log_dump(
+ mPowerLog, fd, " " /* prefix */, kPowerLogLines, 0 /* limit_ns */);
+ }
+
+ // Log the audio data contained in buffer.
+ void log(const void *buffer, size_t sizeInBytes) const {
+ if (mPowerLog != nullptr) { // mFrameSize is always nonzero if mPowerLog exists.
+ power_log_log(
+ mPowerLog, buffer, sizeInBytes / mFrameSize, audio_utils_get_real_time_ns());
+ }
+ }
+
+ bool isUserDebugOrEngBuild() const {
+ return mIsUserDebugOrEngBuild;
+ }
+
+private:
+
+ static inline bool is_userdebug_or_eng_build() {
+ char value[PROPERTY_VALUE_MAX];
+ (void)property_get("ro.build.type", value, "unknown"); // ignore actual length
+ return strcmp(value, "userdebug") == 0 || strcmp(value, "eng") == 0;
+ }
+
+ // Audio signal power log configuration.
+ static const size_t kPowerLogLines = 40;
+ static const size_t kPowerLogSamplingIntervalMs = 50;
+ static const size_t kPowerLogEntries = (1 /* minutes */ * 60 /* seconds */ * 1000 /* msec */
+ / kPowerLogSamplingIntervalMs);
+
+ const bool mIsUserDebugOrEngBuild;
+ power_log_t *mPowerLog;
+ size_t mFrameSize;
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_STREAM_POWER_LOG_H
diff --git a/media/libaudiohal/include/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
similarity index 100%
rename from media/libaudiohal/include/DeviceHalInterface.h
rename to media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
diff --git a/media/libaudiohal/include/DevicesFactoryHalInterface.h b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
similarity index 100%
rename from media/libaudiohal/include/DevicesFactoryHalInterface.h
rename to media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
diff --git a/media/libaudiohal/include/EffectBufferHalInterface.h b/media/libaudiohal/include/media/audiohal/EffectBufferHalInterface.h
similarity index 100%
rename from media/libaudiohal/include/EffectBufferHalInterface.h
rename to media/libaudiohal/include/media/audiohal/EffectBufferHalInterface.h
diff --git a/media/libaudiohal/include/EffectHalInterface.h b/media/libaudiohal/include/media/audiohal/EffectHalInterface.h
similarity index 100%
rename from media/libaudiohal/include/EffectHalInterface.h
rename to media/libaudiohal/include/media/audiohal/EffectHalInterface.h
diff --git a/media/libaudiohal/include/EffectsFactoryHalInterface.h b/media/libaudiohal/include/media/audiohal/EffectsFactoryHalInterface.h
similarity index 100%
rename from media/libaudiohal/include/EffectsFactoryHalInterface.h
rename to media/libaudiohal/include/media/audiohal/EffectsFactoryHalInterface.h
diff --git a/media/libaudiohal/include/StreamHalInterface.h b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
similarity index 100%
rename from media/libaudiohal/include/StreamHalInterface.h
rename to media/libaudiohal/include/media/audiohal/StreamHalInterface.h
diff --git a/media/libaudiohal/include/hidl/HalDeathHandler.h b/media/libaudiohal/include/media/audiohal/hidl/HalDeathHandler.h
similarity index 100%
rename from media/libaudiohal/include/hidl/HalDeathHandler.h
rename to media/libaudiohal/include/media/audiohal/hidl/HalDeathHandler.h
diff --git a/media/libaudioprocessing/include/AudioResampler.h b/media/libaudioprocessing/include/media/AudioResampler.h
similarity index 100%
rename from media/libaudioprocessing/include/AudioResampler.h
rename to media/libaudioprocessing/include/media/AudioResampler.h
diff --git a/media/libaudioprocessing/include/AudioResamplerPublic.h b/media/libaudioprocessing/include/media/AudioResamplerPublic.h
similarity index 100%
rename from media/libaudioprocessing/include/AudioResamplerPublic.h
rename to media/libaudioprocessing/include/media/AudioResamplerPublic.h
diff --git a/media/libeffects/Android.bp b/media/libeffects/Android.bp
index ccaa2b4..0dd3f17 100644
--- a/media/libeffects/Android.bp
+++ b/media/libeffects/Android.bp
@@ -1 +1 @@
-subdirs = ["factory"]
+subdirs = ["factory", "config"]
diff --git a/media/libeffects/OWNERS b/media/libeffects/OWNERS
new file mode 100644
index 0000000..7e3de13
--- /dev/null
+++ b/media/libeffects/OWNERS
@@ -0,0 +1,3 @@
+krocard@google.com
+mnaganov@google.com
+rago@google.com
diff --git a/media/libeffects/config/Android.bp b/media/libeffects/config/Android.bp
new file mode 100644
index 0000000..4398a91
--- /dev/null
+++ b/media/libeffects/config/Android.bp
@@ -0,0 +1,17 @@
+// Effect configuration
+cc_library_shared {
+ name: "libeffectsconfig",
+ vendor_available: true,
+
+ srcs: ["src/EffectsConfig.cpp"],
+
+ shared_libs: [
+ "liblog",
+ "libtinyxml2",
+ ],
+
+ header_libs: ["libaudio_system_headers"],
+ export_header_lib_headers: ["libaudio_system_headers"],
+
+ export_include_dirs: ["include"],
+}
diff --git a/media/libeffects/config/include/media/EffectsConfig.h b/media/libeffects/config/include/media/EffectsConfig.h
new file mode 100644
index 0000000..811730c
--- /dev/null
+++ b/media/libeffects/config/include/media/EffectsConfig.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 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_MEDIA_EFFECTSCONFIG_H
+#define ANDROID_MEDIA_EFFECTSCONFIG_H
+
+/** @file Parses audio effects configuration file to C and C++ structure.
+ * @see audio_effects_conf_V2_0.xsd for documentation on each structure
+ */
+
+#include <system/audio_effect.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace effectsConfig {
+
+/** Default path of effect configuration file. */
+constexpr char DEFAULT_PATH[] = "/vendor/etc/audio_effects.xml";
+
+/** Directories where the effect libraries will be search for. */
+constexpr const char* LD_EFFECT_LIBRARY_PATH[] =
+#ifdef __LP64__
+ {"/odm/lib64/soundfx", "/vendor/lib64/soundfx", "/system/lib64/soundfx"};
+#else
+ {"/odm/lib/soundfx", "/vendor/lib/soundfx", "/system/lib/soundfx"};
+#endif
+
+struct Library {
+ std::string name;
+ std::string path;
+};
+using Libraries = std::vector<Library>;
+
+struct EffectImpl {
+ Library* library; //< Only valid as long as the associated library vector is unmodified
+ effect_uuid_t uuid;
+};
+
+struct Effect : public EffectImpl {
+ std::string name;
+ bool isProxy;
+ EffectImpl libSw; //< Only valid if isProxy
+ EffectImpl libHw; //< Only valid if isProxy
+};
+
+using Effects = std::vector<Effect>;
+
+template <class Type>
+struct Stream {
+ Type type;
+ std::vector<std::reference_wrapper<Effect>> effects;
+};
+using OutputStream = Stream<audio_stream_type_t>;
+using InputStream = Stream<audio_source_t>;
+
+/** Parsed configuration.
+ * Intended to be a transient structure only used for deserialization.
+ * Note: Everything is copied in the configuration from the xml dom.
+ * If copies needed to be avoided due to performance issue,
+ * consider keeping a private handle on the xml dom and replace all strings by dom pointers.
+ * Or even better, use SAX parsing to avoid the allocations all together.
+ */
+struct Config {
+ float version;
+ Libraries libraries;
+ Effects effects;
+ std::vector<OutputStream> postprocess;
+ std::vector<InputStream> preprocess;
+};
+
+/** Result of `parse(const char*)` */
+struct ParsingResult {
+ /** Parsed config, nullptr if the xml lib could not load the file */
+ std::unique_ptr<Config> parsedConfig;
+ size_t nbSkippedElement; //< Number of skipped invalid library, effect or processing chain
+};
+
+/** Parses the provided effect configuration.
+ * Parsing do not stop of first invalid element, but continues to the next.
+ * @see ParsingResult::nbSkippedElement
+ */
+ParsingResult parse(const char* path = DEFAULT_PATH);
+
+} // namespace effectsConfig
+} // namespace android
+#endif // ANDROID_MEDIA_EFFECTSCONFIG_H
diff --git a/media/libeffects/config/src/EffectsConfig.cpp b/media/libeffects/config/src/EffectsConfig.cpp
new file mode 100644
index 0000000..97462f8
--- /dev/null
+++ b/media/libeffects/config/src/EffectsConfig.cpp
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2017 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_TAG "EffectsConfig"
+
+#include <algorithm>
+#include <cstdint>
+#include <functional>
+#include <string>
+
+#include <tinyxml2.h>
+#include <log/log.h>
+
+#include <media/EffectsConfig.h>
+
+using namespace tinyxml2;
+
+namespace android {
+namespace effectsConfig {
+
+/** All functions except `parse(const char*)` are static. */
+namespace {
+
+/** @return all `node`s children that are elements and match the tag if provided. */
+std::vector<std::reference_wrapper<const XMLElement>> getChildren(const XMLNode& node,
+ const char* childTag = nullptr) {
+ std::vector<std::reference_wrapper<const XMLElement>> children;
+ for (auto* child = node.FirstChildElement(childTag); child != nullptr;
+ child = child->NextSiblingElement(childTag)) {
+ children.emplace_back(*child);
+ }
+ return children;
+}
+
+/** @return xml dump of the provided element.
+ * By not providing a printer, it is implicitly created in the caller context.
+ * In such case the return pointer has the same lifetime as the expression containing dump().
+ */
+const char* dump(const XMLElement& element, XMLPrinter&& printer = {}) {
+ element.Accept(&printer);
+ return printer.CStr();
+}
+
+
+bool stringToUuid(const char *str, effect_uuid_t *uuid)
+{
+ uint32_t tmp[10];
+
+ if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+ tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
+ return false;
+ }
+ uuid->timeLow = (uint32_t)tmp[0];
+ uuid->timeMid = (uint16_t)tmp[1];
+ uuid->timeHiAndVersion = (uint16_t)tmp[2];
+ uuid->clockSeq = (uint16_t)tmp[3];
+ uuid->node[0] = (uint8_t)tmp[4];
+ uuid->node[1] = (uint8_t)tmp[5];
+ uuid->node[2] = (uint8_t)tmp[6];
+ uuid->node[3] = (uint8_t)tmp[7];
+ uuid->node[4] = (uint8_t)tmp[8];
+ uuid->node[5] = (uint8_t)tmp[9];
+
+ return true;
+}
+
+/** Map the enum and string representation of a string type.
+ * Intended to be specialized for each enum to deserialize.
+ * The general template is disabled.
+ */
+template <class Enum>
+constexpr std::enable_if<false, Enum> STREAM_NAME_MAP;
+
+/** All output stream types which support effects.
+ * This need to be kept in sink with the xsd streamOutputType.
+ */
+template <>
+constexpr std::pair<audio_stream_type_t, const char*> STREAM_NAME_MAP<audio_stream_type_t>[] = {
+ {AUDIO_STREAM_VOICE_CALL, "voice_call"},
+ {AUDIO_STREAM_SYSTEM, "system"},
+ {AUDIO_STREAM_RING, "ring"},
+ {AUDIO_STREAM_MUSIC, "music"},
+ {AUDIO_STREAM_ALARM, "alarm"},
+ {AUDIO_STREAM_NOTIFICATION, "notification"},
+ {AUDIO_STREAM_BLUETOOTH_SCO, "bluetooth_sco"},
+ {AUDIO_STREAM_ENFORCED_AUDIBLE, "enforced_audible"},
+ {AUDIO_STREAM_DTMF, "dtmf"},
+ {AUDIO_STREAM_TTS, "tts"},
+};
+
+/** All input stream types which support effects.
+ * This need to be kept in sink with the xsd streamOutputType.
+ */
+template <>
+constexpr std::pair<audio_source_t, const char*> STREAM_NAME_MAP<audio_source_t>[] = {
+ {AUDIO_SOURCE_MIC, "mic"},
+ {AUDIO_SOURCE_VOICE_UPLINK, "voice_uplink"},
+ {AUDIO_SOURCE_VOICE_DOWNLINK, "voice_downlink"},
+ {AUDIO_SOURCE_VOICE_CALL, "voice_call"},
+ {AUDIO_SOURCE_CAMCORDER, "camcorder"},
+ {AUDIO_SOURCE_VOICE_RECOGNITION, "voice_recognition"},
+ {AUDIO_SOURCE_VOICE_COMMUNICATION, "voice_communication"},
+ {AUDIO_SOURCE_UNPROCESSED, "unprocessed"},
+};
+
+/** Find the stream type enum corresponding to the stream type name or return false */
+template <class Type>
+bool stringToStreamType(const char *streamName, Type* type)
+{
+ for (auto& streamNamePair : STREAM_NAME_MAP<Type>) {
+ if (strcmp(streamNamePair.second, streamName) == 0) {
+ *type = streamNamePair.first;
+ return true;
+ }
+ }
+ return false;
+}
+
+/** Parse a library xml note and push the result in libraries or return false on failure. */
+bool parseLibrary(const XMLElement& xmlLibrary, Libraries* libraries) {
+ const char* name = xmlLibrary.Attribute("name");
+ const char* path = xmlLibrary.Attribute("path");
+ if (name == nullptr || path == nullptr) {
+ ALOGE("library must have a name and a path: %s", dump(xmlLibrary));
+ return false;
+ }
+ libraries->push_back({name, path});
+ return true;
+}
+
+/** Find an element in a collection by its name.
+ * @return nullptr if not found, the ellements address if found.
+ */
+template <class T>
+T* findByName(const char* name, std::vector<T>& collection) {
+ auto it = find_if(begin(collection), end(collection),
+ [name] (auto& item) { return item.name == name; });
+ return it != end(collection) ? &*it : nullptr;
+}
+
+/** Parse an effect from an xml element describing it.
+ * @return true and pushes the effect in effects on success,
+ * false on failure. */
+bool parseEffect(const XMLElement& xmlEffect, Libraries& libraries, Effects* effects) {
+ Effect effect{};
+
+ const char* name = xmlEffect.Attribute("name");
+ if (name == nullptr) {
+ ALOGE("%s must have a name: %s", xmlEffect.Value(), dump(xmlEffect));
+ return false;
+ }
+ effect.name = name;
+
+ // Function to parse effect.library and effect.uuid from xml
+ auto parseImpl = [&libraries](const XMLElement& xmlImpl, EffectImpl& effect) {
+ // Retrieve library name and uuid from xml
+ const char* libraryName = xmlImpl.Attribute("library");
+ const char* uuid = xmlImpl.Attribute("uuid");
+ if (libraryName == nullptr || uuid == nullptr) {
+ ALOGE("effect must have a library name and a uuid: %s", dump(xmlImpl));
+ return false;
+ }
+
+ // Convert library name to a pointer to the previously loaded library
+ auto* library = findByName(libraryName, libraries);
+ if (library == nullptr) {
+ ALOGE("Could not find library referenced in: %s", dump(xmlImpl));
+ return false;
+ }
+ effect.library = library;
+
+ if (!stringToUuid(uuid, &effect.uuid)) {
+ ALOGE("Invalid uuid in: %s", dump(xmlImpl));
+ return false;
+ }
+ return true;
+ };
+
+ if (!parseImpl(xmlEffect, effect)) {
+ return false;
+ }
+
+ // Handle proxy effects
+ effect.isProxy = false;
+ if (std::strcmp(xmlEffect.Name(), "effectProxy") == 0) {
+ effect.isProxy = true;
+
+ // Function to parse libhw and libsw
+ auto parseProxy = [&xmlEffect, &parseImpl](const char* tag, EffectImpl& proxyLib) {
+ auto* xmlProxyLib = xmlEffect.FirstChildElement(tag);
+ if (xmlProxyLib == nullptr) {
+ ALOGE("effectProxy must contain a <%s>: %s", tag, dump(*xmlProxyLib));
+ return false;
+ }
+ return parseImpl(*xmlProxyLib, proxyLib);
+ };
+ if (!parseProxy("libhw", effect.libHw) || !parseProxy("libsw", effect.libSw)) {
+ return false;
+ }
+ }
+
+ effects->push_back(std::move(effect));
+ return true;
+}
+
+/** Parse an stream from an xml element describing it.
+ * @return true and pushes the stream in streams on success,
+ * false on failure. */
+template <class Stream>
+bool parseStream(const XMLElement& xmlStream, Effects& effects, std::vector<Stream>* streams) {
+ const char* streamType = xmlStream.Attribute("type");
+ if (streamType == nullptr) {
+ ALOGE("stream must have a type: %s", dump(xmlStream));
+ return false;
+ }
+ Stream stream;
+ if (!stringToStreamType(streamType, &stream.type)) {
+ ALOGE("Invalid stream type %s: %s", streamType, dump(xmlStream));
+ return false;
+ }
+
+ for (auto& xmlApply : getChildren(xmlStream, "apply")) {
+ const char* effectName = xmlApply.get().Attribute("effect");
+ if (effectName == nullptr) {
+ ALOGE("stream/apply must have reference an effect: %s", dump(xmlApply));
+ return false;
+ }
+ auto* effect = findByName(effectName, effects);
+ if (effect == nullptr) {
+ ALOGE("Could not find effect referenced in: %s", dump(xmlApply));
+ return false;
+ }
+ stream.effects.emplace_back(*effect);
+ }
+ streams->push_back(std::move(stream));
+ return true;
+}
+
+}; // namespace
+
+ParsingResult parse(const char* path) {
+ XMLDocument doc;
+ doc.LoadFile(path);
+ if (doc.Error()) {
+ ALOGE("Failed to parse %s: Tinyxml2 error (%d): %s %s", path,
+ doc.ErrorID(), doc.GetErrorStr1(), doc.GetErrorStr2());
+ return {nullptr, 0};
+ }
+
+ auto config = std::make_unique<Config>();
+ size_t nbSkippedElements = 0;
+ auto registerFailure = [&nbSkippedElements](bool result) {
+ nbSkippedElements += result ? 0 : 1;
+ };
+ for (auto& xmlConfig : getChildren(doc, "audio_effects_conf")) {
+
+ // Parse library
+ for (auto& xmlLibraries : getChildren(xmlConfig, "libraries")) {
+ for (auto& xmlLibrary : getChildren(xmlLibraries, "library")) {
+ registerFailure(parseLibrary(xmlLibrary, &config->libraries));
+ }
+ }
+
+ // Parse effects
+ for (auto& xmlEffects : getChildren(xmlConfig, "effects")) {
+ for (auto& xmlEffect : getChildren(xmlEffects)) {
+ registerFailure(parseEffect(xmlEffect, config->libraries, &config->effects));
+ }
+ }
+
+ // Parse pre processing chains
+ for (auto& xmlPreprocess : getChildren(xmlConfig, "preprocess")) {
+ for (auto& xmlStream : getChildren(xmlPreprocess, "stream")) {
+ registerFailure(parseStream(xmlStream, config->effects, &config->preprocess));
+ }
+ }
+
+ // Parse post processing chains
+ for (auto& xmlPostprocess : getChildren(xmlConfig, "postprocess")) {
+ for (auto& xmlStream : getChildren(xmlPostprocess, "stream")) {
+ registerFailure(parseStream(xmlStream, config->effects, &config->postprocess));
+ }
+ }
+ }
+ return {std::move(config), nbSkippedElements};
+}
+
+} // namespace effectsConfig
+} // namespace android
diff --git a/media/libeffects/downmix/Android.mk b/media/libeffects/downmix/Android.mk
index 73f6ef5..a5fbf14 100644
--- a/media/libeffects/downmix/Android.mk
+++ b/media/libeffects/downmix/Android.mk
@@ -20,6 +20,7 @@
$(call include-path-for, audio-effects) \
$(call include-path-for, audio-utils)
+#-DBUILD_FLOAT
LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_CFLAGS += -Wall -Werror
diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c
index 7c685ec..b4a1d77 100644
--- a/media/libeffects/downmix/EffectDownmix.c
+++ b/media/libeffects/downmix/EffectDownmix.c
@@ -33,6 +33,10 @@
#define MINUS_3_DB_IN_Q19_12 2896 // -3dB = 0.707 * 2^12 = 2896
+#ifdef BUILD_FLOAT
+#define MINUS_3_DB_IN_FLOAT 0.70710678f // -3dB = 0.70710678f
+#endif
+
// subset of possible audio_channel_mask_t values, and AUDIO_CHANNEL_OUT_* renamed to CHANNEL_MASK_*
typedef enum {
CHANNEL_MASK_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD_BACK,
@@ -82,8 +86,19 @@
// number of effects in this library
const int kNbEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
-
-
+#ifdef BUILD_FLOAT
+static LVM_FLOAT clamp_float(LVM_FLOAT a) {
+ if (a > 1.0f) {
+ return 1.0f;
+ }
+ else if (a < -1.0f) {
+ return -1.0f;
+ }
+ else {
+ return a;
+ }
+}
+#endif
/*----------------------------------------------------------------------------
* Test code
*--------------------------------------------------------------------------*/
@@ -286,7 +301,7 @@
return -EINVAL;
}
-
+#ifndef BUILD_FLOAT
/*--- Effect Control Interface Implementation ---*/
static int Downmix_Process(effect_handle_t self,
@@ -385,7 +400,108 @@
return 0;
}
+#else /*BUILD_FLOAT*/
+/*--- Effect Control Interface Implementation ---*/
+static int Downmix_Process(effect_handle_t self,
+ audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) {
+
+ downmix_object_t *pDownmixer;
+ LVM_FLOAT *pSrc, *pDst;
+ downmix_module_t *pDwmModule = (downmix_module_t *)self;
+
+ if (pDwmModule == NULL) {
+ return -EINVAL;
+ }
+
+ if (inBuffer == NULL || inBuffer->raw == NULL ||
+ outBuffer == NULL || outBuffer->raw == NULL ||
+ inBuffer->frameCount != outBuffer->frameCount) {
+ return -EINVAL;
+ }
+
+ pDownmixer = (downmix_object_t*) &pDwmModule->context;
+
+ if (pDownmixer->state == DOWNMIX_STATE_UNINITIALIZED) {
+ ALOGE("Downmix_Process error: trying to use an uninitialized downmixer");
+ return -EINVAL;
+ } else if (pDownmixer->state == DOWNMIX_STATE_INITIALIZED) {
+ ALOGE("Downmix_Process error: trying to use a non-configured downmixer");
+ return -ENODATA;
+ }
+
+ pSrc = (LVM_FLOAT *) inBuffer->s16;
+ pDst = (LVM_FLOAT *) outBuffer->s16;
+ size_t numFrames = outBuffer->frameCount;
+
+ const bool accumulate =
+ (pDwmModule->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
+ const uint32_t downmixInputChannelMask = pDwmModule->config.inputCfg.channels;
+
+ switch(pDownmixer->type) {
+
+ case DOWNMIX_TYPE_STRIP:
+ if (accumulate) {
+ while (numFrames) {
+ pDst[0] = clamp_float(pDst[0] + pSrc[0]);
+ pDst[1] = clamp_float(pDst[1] + pSrc[1]);
+ pSrc += pDownmixer->input_channel_count;
+ pDst += 2;
+ numFrames--;
+ }
+ } else {
+ while (numFrames) {
+ pDst[0] = pSrc[0];
+ pDst[1] = pSrc[1];
+ pSrc += pDownmixer->input_channel_count;
+ pDst += 2;
+ numFrames--;
+ }
+ }
+ break;
+
+ case DOWNMIX_TYPE_FOLD:
+#ifdef DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER
+ // bypass the optimized downmix routines for the common formats
+ if (!Downmix_foldGeneric(
+ downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
+ ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported",
+ downmixInputChannelMask);
+ return -EINVAL;
+ }
+ break;
+#endif
+ // optimize for the common formats
+ switch((downmix_input_channel_mask_t)downmixInputChannelMask) {
+ case CHANNEL_MASK_QUAD_BACK:
+ case CHANNEL_MASK_QUAD_SIDE:
+ Downmix_foldFromQuad(pSrc, pDst, numFrames, accumulate);
+ break;
+ case CHANNEL_MASK_5POINT1_BACK:
+ case CHANNEL_MASK_5POINT1_SIDE:
+ Downmix_foldFrom5Point1(pSrc, pDst, numFrames, accumulate);
+ break;
+ case CHANNEL_MASK_7POINT1:
+ Downmix_foldFrom7Point1(pSrc, pDst, numFrames, accumulate);
+ break;
+ default:
+ if (!Downmix_foldGeneric(
+ downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
+ ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported",
+ downmixInputChannelMask);
+ return -EINVAL;
+ }
+ break;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#endif
static int Downmix_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
void *pCmdData, uint32_t *replySize, void *pReplyData) {
@@ -822,6 +938,7 @@
*
*----------------------------------------------------------------------------
*/
+#ifndef BUILD_FLOAT
void Downmix_foldFromQuad(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
// sample at index 0 is FL
// sample at index 1 is FR
@@ -849,7 +966,35 @@
}
}
}
-
+#else
+void Downmix_foldFromQuad(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
+ // sample at index 0 is FL
+ // sample at index 1 is FR
+ // sample at index 2 is RL
+ // sample at index 3 is RR
+ if (accumulate) {
+ while (numFrames) {
+ // FL + RL
+ pDst[0] = clamp_float(pDst[0] + ((pSrc[0] + pSrc[2]) / 2.0f));
+ // FR + RR
+ pDst[1] = clamp_float(pDst[1] + ((pSrc[1] + pSrc[3]) / 2.0f));
+ pSrc += 4;
+ pDst += 2;
+ numFrames--;
+ }
+ } else { // same code as above but without adding and clamping pDst[i] to itself
+ while (numFrames) {
+ // FL + RL
+ pDst[0] = clamp_float((pSrc[0] + pSrc[2]) / 2.0f);
+ // FR + RR
+ pDst[1] = clamp_float((pSrc[1] + pSrc[3]) / 2.0f);
+ pSrc += 4;
+ pDst += 2;
+ numFrames--;
+ }
+ }
+}
+#endif
/*----------------------------------------------------------------------------
* Downmix_foldFrom5Point1()
@@ -868,6 +1013,7 @@
*
*----------------------------------------------------------------------------
*/
+#ifndef BUILD_FLOAT
void Downmix_foldFrom5Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
int32_t lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
// sample at index 0 is FL
@@ -912,7 +1058,52 @@
}
}
}
-
+#else
+void Downmix_foldFrom5Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
+ LVM_FLOAT lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
+ // sample at index 0 is FL
+ // sample at index 1 is FR
+ // sample at index 2 is FC
+ // sample at index 3 is LFE
+ // sample at index 4 is RL
+ // sample at index 5 is RR
+ // code is mostly duplicated between the two values of accumulate to avoid repeating the test
+ // for every sample
+ if (accumulate) {
+ while (numFrames) {
+ // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
+ centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT)
+ + (pSrc[3] * MINUS_3_DB_IN_FLOAT);
+ // FL + centerPlusLfeContrib + RL
+ lt = pSrc[0] + centerPlusLfeContrib + pSrc[4];
+ // FR + centerPlusLfeContrib + RR
+ rt = pSrc[1] + centerPlusLfeContrib + pSrc[5];
+ // accumulate in destination
+ pDst[0] = clamp_float(pDst[0] + (lt / 2.0f));
+ pDst[1] = clamp_float(pDst[1] + (rt / 2.0f));
+ pSrc += 6;
+ pDst += 2;
+ numFrames--;
+ }
+ } else { // same code as above but without adding and clamping pDst[i] to itself
+ while (numFrames) {
+ // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
+ centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT)
+ + (pSrc[3] * MINUS_3_DB_IN_FLOAT);
+ // FL + centerPlusLfeContrib + RL
+ lt = pSrc[0] + centerPlusLfeContrib + pSrc[4];
+ // FR + centerPlusLfeContrib + RR
+ rt = pSrc[1] + centerPlusLfeContrib + pSrc[5];
+ // store in destination
+ pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above
+ pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above
+ pSrc += 6;
+ pDst += 2;
+ numFrames--;
+ }
+ }
+}
+#endif
/*----------------------------------------------------------------------------
* Downmix_foldFrom7Point1()
@@ -931,6 +1122,7 @@
*
*----------------------------------------------------------------------------
*/
+#ifndef BUILD_FLOAT
void Downmix_foldFrom7Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
int32_t lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
// sample at index 0 is FL
@@ -977,8 +1169,54 @@
}
}
}
-
-
+#else
+void Downmix_foldFrom7Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
+ LVM_FLOAT lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
+ // sample at index 0 is FL
+ // sample at index 1 is FR
+ // sample at index 2 is FC
+ // sample at index 3 is LFE
+ // sample at index 4 is RL
+ // sample at index 5 is RR
+ // sample at index 6 is SL
+ // sample at index 7 is SR
+ // code is mostly duplicated between the two values of accumulate to avoid repeating the test
+ // for every sample
+ if (accumulate) {
+ while (numFrames) {
+ // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
+ centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12)
+ + (pSrc[3] * MINUS_3_DB_IN_Q19_12);
+ // FL + centerPlusLfeContrib + SL + RL
+ lt = pSrc[0] + centerPlusLfeContrib + pSrc[6] + pSrc[4];
+ // FR + centerPlusLfeContrib + SR + RR
+ rt = pSrc[1] + centerPlusLfeContrib + pSrc[7] + pSrc[5];
+ //accumulate in destination
+ pDst[0] = clamp_float(pDst[0] + (lt / 2.0f));
+ pDst[1] = clamp_float(pDst[1] + (rt / 2.0f));
+ pSrc += 8;
+ pDst += 2;
+ numFrames--;
+ }
+ } else { // same code as above but without adding and clamping pDst[i] to itself
+ while (numFrames) {
+ // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
+ centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT)
+ + (pSrc[3] * MINUS_3_DB_IN_FLOAT);
+ // FL + centerPlusLfeContrib + SL + RL
+ lt = pSrc[0] + centerPlusLfeContrib + pSrc[6] + pSrc[4];
+ // FR + centerPlusLfeContrib + SR + RR
+ rt = pSrc[1] + centerPlusLfeContrib + pSrc[7] + pSrc[5];
+ // store in destination
+ pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above
+ pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above
+ pSrc += 8;
+ pDst += 2;
+ numFrames--;
+ }
+ }
+}
+#endif
/*----------------------------------------------------------------------------
* Downmix_foldGeneric()
*----------------------------------------------------------------------------
@@ -1005,6 +1243,7 @@
*
*----------------------------------------------------------------------------
*/
+#ifndef BUILD_FLOAT
bool Downmix_foldGeneric(
uint32_t mask, int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
@@ -1096,3 +1335,96 @@
}
return true;
}
+#else
+bool Downmix_foldGeneric(
+ uint32_t mask, LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
+
+ if (!Downmix_validChannelMask(mask)) {
+ return false;
+ }
+
+ const bool hasSides = (mask & kSides) != 0;
+ const bool hasBacks = (mask & kBacks) != 0;
+
+ const int numChan = audio_channel_count_from_out_mask(mask);
+ const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER);
+ const bool hasLFE =
+ ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY);
+ const bool hasBC = ((mask & AUDIO_CHANNEL_OUT_BACK_CENTER) == AUDIO_CHANNEL_OUT_BACK_CENTER);
+ // compute at what index each channel is: samples will be in the following order:
+ // FL FR FC LFE BL BR BC SL SR
+ // when a channel is not present, its index is set to the same as the index of the preceding
+ // channel
+ const int indexFC = hasFC ? 2 : 1; // front center
+ const int indexLFE = hasLFE ? indexFC + 1 : indexFC; // low frequency
+ const int indexBL = hasBacks ? indexLFE + 1 : indexLFE; // back left
+ const int indexBR = hasBacks ? indexBL + 1 : indexBL; // back right
+ const int indexBC = hasBC ? indexBR + 1 : indexBR; // back center
+ const int indexSL = hasSides ? indexBC + 1 : indexBC; // side left
+ const int indexSR = hasSides ? indexSL + 1 : indexSL; // side right
+
+ LVM_FLOAT lt, rt, centersLfeContrib;
+ // code is mostly duplicated between the two values of accumulate to avoid repeating the test
+ // for every sample
+ if (accumulate) {
+ while (numFrames) {
+ // compute contribution of FC, BC and LFE
+ centersLfeContrib = 0;
+ if (hasFC) { centersLfeContrib += pSrc[indexFC]; }
+ if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
+ if (hasBC) { centersLfeContrib += pSrc[indexBC]; }
+ centersLfeContrib *= MINUS_3_DB_IN_FLOAT;
+ // always has FL/FR
+ lt = pSrc[0];
+ rt = pSrc[1];
+ // mix in sides and backs
+ if (hasSides) {
+ lt += pSrc[indexSL];
+ rt += pSrc[indexSR];
+ }
+ if (hasBacks) {
+ lt += pSrc[indexBL];
+ rt += pSrc[indexBR];
+ }
+ lt += centersLfeContrib;
+ rt += centersLfeContrib;
+ // accumulate in destination
+ pDst[0] = clamp_float(pDst[0] + (lt / 2.0f));
+ pDst[1] = clamp_float(pDst[1] + (rt / 2.0f));
+ pSrc += numChan;
+ pDst += 2;
+ numFrames--;
+ }
+ } else {
+ while (numFrames) {
+ // compute contribution of FC, BC and LFE
+ centersLfeContrib = 0;
+ if (hasFC) { centersLfeContrib += pSrc[indexFC]; }
+ if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
+ if (hasBC) { centersLfeContrib += pSrc[indexBC]; }
+ centersLfeContrib *= MINUS_3_DB_IN_FLOAT;
+ // always has FL/FR
+ lt = pSrc[0];
+ rt = pSrc[1];
+ // mix in sides and backs
+ if (hasSides) {
+ lt += pSrc[indexSL];
+ rt += pSrc[indexSR];
+ }
+ if (hasBacks) {
+ lt += pSrc[indexBL];
+ rt += pSrc[indexBR];
+ }
+ lt += centersLfeContrib;
+ rt += centersLfeContrib;
+ // store in destination
+ pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above
+ pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above
+ pSrc += numChan;
+ pDst += 2;
+ numFrames--;
+ }
+ }
+ return true;
+}
+#endif
\ No newline at end of file
diff --git a/media/libeffects/downmix/EffectDownmix.h b/media/libeffects/downmix/EffectDownmix.h
index 2399abd..c1be0f2 100644
--- a/media/libeffects/downmix/EffectDownmix.h
+++ b/media/libeffects/downmix/EffectDownmix.h
@@ -27,7 +27,9 @@
*/
#define DOWNMIX_OUTPUT_CHANNELS AUDIO_CHANNEL_OUT_STEREO
-
+#ifdef BUILD_FLOAT
+#define LVM_FLOAT float
+#endif
typedef enum {
DOWNMIX_STATE_UNINITIALIZED,
DOWNMIX_STATE_INITIALIZED,
@@ -95,11 +97,18 @@
int Downmix_Reset(downmix_object_t *pDownmixer, bool init);
int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue);
int Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue);
-
+#ifdef BUILD_FLOAT
+void Downmix_foldFromQuad(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
+void Downmix_foldFrom5Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
+void Downmix_foldFrom7Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
+bool Downmix_foldGeneric(
+ uint32_t mask, LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
+#else
void Downmix_foldFromQuad(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate);
void Downmix_foldFrom5Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate);
void Downmix_foldFrom7Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate);
bool Downmix_foldGeneric(
uint32_t mask, int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate);
+#endif
#endif /*ANDROID_EFFECTDOWNMIX_H_*/
diff --git a/media/libeffects/factory/Android.bp b/media/libeffects/factory/Android.bp
index 16680bd..ddbfdd8 100644
--- a/media/libeffects/factory/Android.bp
+++ b/media/libeffects/factory/Android.bp
@@ -10,18 +10,47 @@
cc_library_shared {
name: "libeffects",
vendor: true,
- srcs: ["EffectsFactory.c"],
+ srcs: [
+ "EffectsFactory.c",
+ "EffectsConfigLoader.c",
+ "EffectsFactoryState.c",
+ "EffectsXmlConfigLoader.cpp",
+ ],
shared_libs: [
"libcutils",
"liblog",
"libdl",
+ "libeffectsconfig",
],
-
- include_dirs: ["system/media/audio_effects/include"],
+ cflags: ["-fvisibility=hidden"],
local_include_dirs:["include/media"],
- header_libs: ["libeffects_headers"],
+ header_libs: [
+ "libaudioeffects",
+ "libeffects_headers",
+ ],
export_header_lib_headers: ["libeffects_headers"],
}
+
+cc_binary {
+ name: "dumpEffectConfigFile",
+ vendor: true,
+ srcs: ["test/DumpConfig.cpp"],
+
+ compile_multilib: "32",
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+
+
+ shared_libs: [
+ "libeffectsconfig",
+ "libeffects",
+ ],
+ local_include_dirs:[".", "include"],
+}
diff --git a/media/libeffects/factory/EffectsConfigLoader.c b/media/libeffects/factory/EffectsConfigLoader.c
new file mode 100644
index 0000000..fcef36f
--- /dev/null
+++ b/media/libeffects/factory/EffectsConfigLoader.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2017 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_TAG "EffectsFactoryConfigLoader"
+//#define LOG_NDEBUG 0
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <cutils/config_utils.h>
+#include <cutils/misc.h>
+#include <log/log.h>
+
+#include <system/audio_effects/audio_effects_conf.h>
+
+#include "EffectsConfigLoader.h"
+#include "EffectsFactoryState.h"
+
+/////////////////////////////////////////////////
+// Local functions prototypes
+/////////////////////////////////////////////////
+
+static int loadEffectConfigFile(const char *path);
+static int loadLibraries(cnode *root);
+static int loadLibrary(cnode *root, const char *name);
+static int loadEffects(cnode *root);
+static int loadEffect(cnode *node);
+// To get and add the effect pointed by the passed node to the gSubEffectList
+static int addSubEffect(cnode *root);
+static lib_entry_t *getLibrary(const char *path);
+
+static lib_entry_t *gCachedLibrary; // last library accessed by getLibrary()
+
+int EffectLoadEffectConfig()
+{
+ if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
+ return loadEffectConfigFile(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
+ } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
+ return loadEffectConfigFile(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
+ }
+ return 0;
+}
+
+int loadEffectConfigFile(const char *path)
+{
+ cnode *root;
+ char *data;
+
+ data = load_file(path, NULL);
+ if (data == NULL) {
+ return -ENODEV;
+ }
+ root = config_node("", "");
+ config_load(root, data);
+ loadLibraries(root);
+ loadEffects(root);
+ config_free(root);
+ free(root);
+ free(data);
+
+ return 0;
+}
+
+int loadLibraries(cnode *root)
+{
+ cnode *node;
+
+ node = config_find(root, LIBRARIES_TAG);
+ if (node == NULL) {
+ return -ENOENT;
+ }
+ node = node->first_child;
+ while (node) {
+ loadLibrary(node, node->name);
+ node = node->next;
+ }
+ return 0;
+}
+
+#ifdef __LP64__
+// audio_effects.conf always specifies 32 bit lib path: convert to 64 bit path if needed
+static const char *kLibraryPathRoot[] =
+ {"/odm/lib64/soundfx", "/vendor/lib64/soundfx", "/system/lib64/soundfx"};
+#else
+static const char *kLibraryPathRoot[] =
+ {"/odm/lib/soundfx", "/vendor/lib/soundfx", "/system/lib/soundfx"};
+#endif
+
+static const int kLibraryPathRootSize =
+ (sizeof(kLibraryPathRoot) / sizeof(kLibraryPathRoot[0]));
+
+// Checks if the library path passed as lib_path_in can be opened and if not
+// tries in standard effect library directories with just the library name and returns correct path
+// in lib_path_out
+int checkLibraryPath(const char *lib_path_in, char *lib_path_out) {
+ char *str;
+ const char *lib_name;
+ size_t len;
+
+ if (lib_path_in == NULL || lib_path_out == NULL) {
+ return -EINVAL;
+ }
+
+ strlcpy(lib_path_out, lib_path_in, PATH_MAX);
+
+ // Try exact path first
+ str = strstr(lib_path_out, "/lib/soundfx/");
+ if (str == NULL) {
+ return -EINVAL;
+ }
+
+ // Extract library name from input path
+ len = str - lib_path_out;
+ lib_name = lib_path_in + len + strlen("/lib/soundfx/");
+
+ // Then try with library name and standard path names in order of preference
+ for (int i = 0; i < kLibraryPathRootSize; i++) {
+ char path[PATH_MAX];
+
+ snprintf(path,
+ PATH_MAX,
+ "%s/%s",
+ kLibraryPathRoot[i],
+ lib_name);
+ if (F_OK == access(path, 0)) {
+ strcpy(lib_path_out, path);
+ ALOGW_IF(strncmp(lib_path_out, lib_path_in, PATH_MAX) != 0,
+ "checkLibraryPath() corrected library path %s to %s", lib_path_in, lib_path_out);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+
+
+int loadLibrary(cnode *root, const char *name)
+{
+ cnode *node;
+ void *hdl = NULL;
+ audio_effect_library_t *desc;
+ list_elem_t *e;
+ lib_entry_t *l;
+ char path[PATH_MAX];
+
+ node = config_find(root, PATH_TAG);
+ if (node == NULL) {
+ return -EINVAL;
+ }
+
+ if (checkLibraryPath((const char *)node->value, path) != 0) {
+ ALOGW("loadLibrary() could not find library %s", path);
+ goto error;
+ }
+
+ hdl = dlopen(path, RTLD_NOW);
+ if (hdl == NULL) {
+ ALOGW("loadLibrary() failed to open %s", path);
+ goto error;
+ }
+
+ desc = (audio_effect_library_t *)dlsym(hdl, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
+ if (desc == NULL) {
+ ALOGW("loadLibrary() could not find symbol %s", AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
+ goto error;
+ }
+
+ if (AUDIO_EFFECT_LIBRARY_TAG != desc->tag) {
+ ALOGW("getLibrary() bad tag %08x in lib info struct", desc->tag);
+ goto error;
+ }
+
+ if (EFFECT_API_VERSION_MAJOR(desc->version) !=
+ EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION)) {
+ ALOGW("loadLibrary() bad lib version %08x", desc->version);
+ goto error;
+ }
+
+ // add entry for library in gLibraryList
+ l = malloc(sizeof(lib_entry_t));
+ l->name = strndup(name, PATH_MAX);
+ l->path = strndup(path, PATH_MAX);
+ l->handle = hdl;
+ l->desc = desc;
+ l->effects = NULL;
+ pthread_mutex_init(&l->lock, NULL);
+
+ e = malloc(sizeof(list_elem_t));
+ e->object = l;
+ pthread_mutex_lock(&gLibLock);
+ e->next = gLibraryList;
+ gLibraryList = e;
+ pthread_mutex_unlock(&gLibLock);
+ ALOGV("getLibrary() linked library %p for path %s", l, path);
+
+ return 0;
+
+error:
+ if (hdl != NULL) {
+ dlclose(hdl);
+ }
+ //add entry for library errors in gLibraryFailedList
+ lib_failed_entry_t *fl = malloc(sizeof(lib_failed_entry_t));
+ fl->name = strndup(name, PATH_MAX);
+ fl->path = strndup(path, PATH_MAX);
+
+ list_elem_t *fe = malloc(sizeof(list_elem_t));
+ fe->object = fl;
+ fe->next = gLibraryFailedList;
+ gLibraryFailedList = fe;
+ ALOGV("getLibrary() linked error in library %p for path %s", fl, path);
+
+ return -EINVAL;
+}
+
+// This will find the library and UUID tags of the sub effect pointed by the
+// node, gets the effect descriptor and lib_entry_t and adds the subeffect -
+// sub_entry_t to the gSubEffectList
+int addSubEffect(cnode *root)
+{
+ ALOGV("addSubEffect");
+ cnode *node;
+ effect_uuid_t uuid;
+ effect_descriptor_t *d;
+ lib_entry_t *l;
+ list_elem_t *e;
+ node = config_find(root, LIBRARY_TAG);
+ if (node == NULL) {
+ return -EINVAL;
+ }
+ l = getLibrary(node->value);
+ if (l == NULL) {
+ ALOGW("addSubEffect() could not get library %s", node->value);
+ return -EINVAL;
+ }
+ node = config_find(root, UUID_TAG);
+ if (node == NULL) {
+ return -EINVAL;
+ }
+ if (stringToUuid(node->value, &uuid) != 0) {
+ ALOGW("addSubEffect() invalid uuid %s", node->value);
+ return -EINVAL;
+ }
+ d = malloc(sizeof(effect_descriptor_t));
+ if (l->desc->get_descriptor(&uuid, d) != 0) {
+ char s[40];
+ uuidToString(&uuid, s, 40);
+ ALOGW("Error querying effect %s on lib %s", s, l->name);
+ free(d);
+ return -EINVAL;
+ }
+#if (LOG_NDEBUG==0)
+ char s[512];
+ dumpEffectDescriptor(d, s, sizeof(s), 0 /* indent */);
+ ALOGV("addSubEffect() read descriptor %p:%s",d, s);
+#endif
+ if (EFFECT_API_VERSION_MAJOR(d->apiVersion) !=
+ EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) {
+ ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name);
+ free(d);
+ return -EINVAL;
+ }
+ sub_effect_entry_t *sub_effect = malloc(sizeof(sub_effect_entry_t));
+ sub_effect->object = d;
+ // lib_entry_t is stored since the sub effects are not linked to the library
+ sub_effect->lib = l;
+ e = malloc(sizeof(list_elem_t));
+ e->object = sub_effect;
+ e->next = gSubEffectList->sub_elem;
+ gSubEffectList->sub_elem = e;
+ ALOGV("addSubEffect end");
+ return 0;
+}
+
+int loadEffects(cnode *root)
+{
+ cnode *node;
+
+ node = config_find(root, EFFECTS_TAG);
+ if (node == NULL) {
+ return -ENOENT;
+ }
+ node = node->first_child;
+ while (node) {
+ loadEffect(node);
+ node = node->next;
+ }
+ return 0;
+}
+
+int loadEffect(cnode *root)
+{
+ cnode *node;
+ effect_uuid_t uuid;
+ lib_entry_t *l;
+ effect_descriptor_t *d;
+ list_elem_t *e;
+
+ node = config_find(root, LIBRARY_TAG);
+ if (node == NULL) {
+ return -EINVAL;
+ }
+
+ l = getLibrary(node->value);
+ if (l == NULL) {
+ ALOGW("loadEffect() could not get library %s", node->value);
+ return -EINVAL;
+ }
+
+ node = config_find(root, UUID_TAG);
+ if (node == NULL) {
+ return -EINVAL;
+ }
+ if (stringToUuid(node->value, &uuid) != 0) {
+ ALOGW("loadEffect() invalid uuid %s", node->value);
+ return -EINVAL;
+ }
+ lib_entry_t *tmp;
+ bool skip = false;
+ if (findEffect(NULL, &uuid, &tmp, NULL) == 0) {
+ ALOGW("skipping duplicate uuid %s %s", node->value,
+ node->next ? "and its sub-effects" : "");
+ skip = true;
+ }
+
+ d = malloc(sizeof(effect_descriptor_t));
+ if (l->desc->get_descriptor(&uuid, d) != 0) {
+ char s[40];
+ uuidToString(&uuid, s, 40);
+ ALOGW("Error querying effect %s on lib %s", s, l->name);
+ free(d);
+ return -EINVAL;
+ }
+#if (LOG_NDEBUG==0)
+ char s[512];
+ dumpEffectDescriptor(d, s, sizeof(s), 0 /* indent */);
+ ALOGV("loadEffect() read descriptor %p:%s",d, s);
+#endif
+ if (EFFECT_API_VERSION_MAJOR(d->apiVersion) !=
+ EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) {
+ ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name);
+ free(d);
+ return -EINVAL;
+ }
+ e = malloc(sizeof(list_elem_t));
+ e->object = d;
+ if (skip) {
+ e->next = gSkippedEffects;
+ gSkippedEffects = e;
+ return -EINVAL;
+ } else {
+ e->next = l->effects;
+ l->effects = e;
+ }
+
+ // After the UUID node in the config_tree, if node->next is valid,
+ // that would be sub effect node.
+ // Find the sub effects and add them to the gSubEffectList
+ node = node->next;
+ int count = 2;
+ bool hwSubefx = false, swSubefx = false;
+ list_sub_elem_t *sube = NULL;
+ if (node != NULL) {
+ ALOGV("Adding the effect to gEffectSubList as there are sub effects");
+ sube = malloc(sizeof(list_sub_elem_t));
+ sube->object = d;
+ sube->sub_elem = NULL;
+ sube->next = gSubEffectList;
+ gSubEffectList = sube;
+ }
+ while (node != NULL && count) {
+ if (addSubEffect(node)) {
+ ALOGW("loadEffect() could not add subEffect %s", node->value);
+ // Change the gSubEffectList to point to older list;
+ gSubEffectList = sube->next;
+ free(sube->sub_elem);// Free an already added sub effect
+ sube->sub_elem = NULL;
+ free(sube);
+ return -ENOENT;
+ }
+ sub_effect_entry_t *subEntry = (sub_effect_entry_t*)gSubEffectList->sub_elem->object;
+ effect_descriptor_t *subEffectDesc = (effect_descriptor_t*)(subEntry->object);
+ // Since we return a dummy descriptor for the proxy during
+ // get_descriptor call,we replace it with the correspoding
+ // sw effect descriptor, but with Proxy UUID
+ // check for Sw desc
+ if (!((subEffectDesc->flags & EFFECT_FLAG_HW_ACC_MASK) ==
+ EFFECT_FLAG_HW_ACC_TUNNEL)) {
+ swSubefx = true;
+ *d = *subEffectDesc;
+ d->uuid = uuid;
+ ALOGV("loadEffect() Changed the Proxy desc");
+ } else
+ hwSubefx = true;
+ count--;
+ node = node->next;
+ }
+ // 1 HW and 1 SW sub effect found. Set the offload flag in the Proxy desc
+ if (hwSubefx && swSubefx) {
+ d->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED;
+ }
+ return 0;
+}
+
+lib_entry_t *getLibrary(const char *name)
+{
+ list_elem_t *e;
+
+ if (gCachedLibrary &&
+ !strncmp(gCachedLibrary->name, name, PATH_MAX)) {
+ return gCachedLibrary;
+ }
+
+ e = gLibraryList;
+ while (e) {
+ lib_entry_t *l = (lib_entry_t *)e->object;
+ if (!strcmp(l->name, name)) {
+ gCachedLibrary = l;
+ return l;
+ }
+ e = e->next;
+ }
+
+ return NULL;
+}
diff --git a/media/libeffects/factory/EffectsConfigLoader.h b/media/libeffects/factory/EffectsConfigLoader.h
new file mode 100644
index 0000000..3f82609
--- /dev/null
+++ b/media/libeffects/factory/EffectsConfigLoader.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 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_EFFECTSCONFIGLOADER_H
+#define ANDROID_EFFECTSCONFIGLOADER_H
+
+#include <cutils/compiler.h>
+#include "EffectsFactoryState.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** Parses the platform effect configuration
+ * and stores its content in the global EffectFactoryState. */
+ANDROID_API
+int EffectLoadEffectConfig();
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // ANDROID_EFFECTSCONFIGLOADER_H
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index 37c0bb7..cd0e765 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -17,65 +17,46 @@
#define LOG_TAG "EffectsFactory"
//#define LOG_NDEBUG 0
-#include "EffectsFactory.h"
-
-#include <dlfcn.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <cutils/config_utils.h>
-#include <cutils/misc.h>
#include <cutils/properties.h>
#include <log/log.h>
-#include <system/audio_effects/audio_effects_conf.h>
+#include <media/EffectsFactoryApi.h>
+
+#include "EffectsConfigLoader.h"
+#include "EffectsFactoryState.h"
+#include "EffectsXmlConfigLoader.h"
+
+#include "EffectsFactory.h"
static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
-static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
-static list_elem_t *gSkippedEffects; // list of effects skipped because of duplicate uuid
-// list of effect_descriptor and list of sub effects : all currently loaded
-// It does not contain effects without sub effects.
-static list_sub_elem_t *gSubEffectList;
-static pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER; // controls access to gLibraryList
static uint32_t gNumEffects; // total number number of effects
static list_elem_t *gCurLib; // current library in enumeration process
static list_elem_t *gCurEffect; // current effect in enumeration process
static uint32_t gCurEffectIdx; // current effect index in enumeration process
-static lib_entry_t *gCachedLibrary; // last library accessed by getLibrary()
+/** Number of elements skipped during the effects configuration loading.
+ * -1 if the config loader failed
+ * -2 if config load was skipped
+ */
+static ssize_t gConfigNbElemSkipped = -2;
static int gInitDone; // true is global initialization has been preformed
static int gCanQueryEffect; // indicates that call to EffectQueryEffect() is valid, i.e. that the list of effects
// was not modified since last call to EffectQueryNumberEffects()
-
-static list_elem_t *gLibraryFailedList; //list of lib_failed_entry_t: libraries failed to load
-
/////////////////////////////////////////////////
// Local functions prototypes
/////////////////////////////////////////////////
static int init();
-static int loadEffectConfigFile(const char *path);
-static int loadLibraries(cnode *root);
-static int loadLibrary(cnode *root, const char *name);
-static int loadEffects(cnode *root);
-static int loadEffect(cnode *node);
-// To get and add the effect pointed by the passed node to the gSubEffectList
-static int addSubEffect(cnode *root);
-static lib_entry_t *getLibrary(const char *path);
static void resetEffectEnumeration();
static uint32_t updateNumEffects();
-static int findEffect(const effect_uuid_t *type,
- const effect_uuid_t *uuid,
- lib_entry_t **lib,
- effect_descriptor_t **desc);
// To search a subeffect in the gSubEffectList
static int findSubEffect(const effect_uuid_t *uuid,
lib_entry_t **lib,
effect_descriptor_t **desc);
-static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len, int indent);
-static int stringToUuid(const char *str, effect_uuid_t *uuid);
-static int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen);
/////////////////////////////////////////////////
// Effect Control Interface functions
@@ -461,10 +442,12 @@
if (ignoreFxConfFiles) {
ALOGI("Audio effects in configuration files will be ignored");
} else {
- if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
- loadEffectConfigFile(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
- } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
- loadEffectConfigFile(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
+ gConfigNbElemSkipped = EffectLoadXmlEffectConfig(NULL);
+ if (gConfigNbElemSkipped < 0) {
+ ALOGW("Failed to load XML effect configuration, fallback to .conf");
+ EffectLoadEffectConfig();
+ } else if (gConfigNbElemSkipped > 0) {
+ ALOGE("Effect config is partially invalid, skipped %zd elements", gConfigNbElemSkipped);
}
}
@@ -474,367 +457,6 @@
return 0;
}
-int loadEffectConfigFile(const char *path)
-{
- cnode *root;
- char *data;
-
- data = load_file(path, NULL);
- if (data == NULL) {
- return -ENODEV;
- }
- root = config_node("", "");
- config_load(root, data);
- loadLibraries(root);
- loadEffects(root);
- config_free(root);
- free(root);
- free(data);
-
- return 0;
-}
-
-int loadLibraries(cnode *root)
-{
- cnode *node;
-
- node = config_find(root, LIBRARIES_TAG);
- if (node == NULL) {
- return -ENOENT;
- }
- node = node->first_child;
- while (node) {
- loadLibrary(node, node->name);
- node = node->next;
- }
- return 0;
-}
-
-#ifdef __LP64__
-// audio_effects.conf always specifies 32 bit lib path: convert to 64 bit path if needed
-static const char *kLibraryPathRoot[] =
- {"/odm/lib64/soundfx", "/vendor/lib64/soundfx", "/system/lib64/soundfx"};
-#else
-static const char *kLibraryPathRoot[] =
- {"/odm/lib/soundfx", "/vendor/lib/soundfx", "/system/lib/soundfx"};
-#endif
-
-static const int kLibraryPathRootSize =
- (sizeof(kLibraryPathRoot) / sizeof(kLibraryPathRoot[0]));
-
-// Checks if the library path passed as lib_path_in can be opened and if not
-// tries in standard effect library directories with just the library name and returns correct path
-// in lib_path_out
-int checkLibraryPath(const char *lib_path_in, char *lib_path_out) {
- char *str;
- const char *lib_name;
- size_t len;
-
- if (lib_path_in == NULL || lib_path_out == NULL) {
- return -EINVAL;
- }
-
- strlcpy(lib_path_out, lib_path_in, PATH_MAX);
-
- // Try exact path first
- str = strstr(lib_path_out, "/lib/soundfx/");
- if (str == NULL) {
- return -EINVAL;
- }
-
- // Extract library name from input path
- len = str - lib_path_out;
- lib_name = lib_path_in + len + strlen("/lib/soundfx/");
-
- // Then try with library name and standard path names in order of preference
- for (int i = 0; i < kLibraryPathRootSize; i++) {
- char path[PATH_MAX];
-
- snprintf(path,
- PATH_MAX,
- "%s/%s",
- kLibraryPathRoot[i],
- lib_name);
- if (F_OK == access(path, 0)) {
- strcpy(lib_path_out, path);
- ALOGW_IF(strncmp(lib_path_out, lib_path_in, PATH_MAX) != 0,
- "checkLibraryPath() corrected library path %s to %s", lib_path_in, lib_path_out);
- return 0;
- }
- }
- return -EINVAL;
-}
-
-
-
-int loadLibrary(cnode *root, const char *name)
-{
- cnode *node;
- void *hdl = NULL;
- audio_effect_library_t *desc;
- list_elem_t *e;
- lib_entry_t *l;
- char path[PATH_MAX];
-
- node = config_find(root, PATH_TAG);
- if (node == NULL) {
- return -EINVAL;
- }
-
- if (checkLibraryPath((const char *)node->value, path) != 0) {
- ALOGW("loadLibrary() could not find library %s", path);
- goto error;
- }
-
- hdl = dlopen(path, RTLD_NOW);
- if (hdl == NULL) {
- ALOGW("loadLibrary() failed to open %s", path);
- goto error;
- }
-
- desc = (audio_effect_library_t *)dlsym(hdl, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
- if (desc == NULL) {
- ALOGW("loadLibrary() could not find symbol %s", AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
- goto error;
- }
-
- if (AUDIO_EFFECT_LIBRARY_TAG != desc->tag) {
- ALOGW("getLibrary() bad tag %08x in lib info struct", desc->tag);
- goto error;
- }
-
- if (EFFECT_API_VERSION_MAJOR(desc->version) !=
- EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION)) {
- ALOGW("loadLibrary() bad lib version %08x", desc->version);
- goto error;
- }
-
- // add entry for library in gLibraryList
- l = malloc(sizeof(lib_entry_t));
- l->name = strndup(name, PATH_MAX);
- l->path = strndup(path, PATH_MAX);
- l->handle = hdl;
- l->desc = desc;
- l->effects = NULL;
- pthread_mutex_init(&l->lock, NULL);
-
- e = malloc(sizeof(list_elem_t));
- e->object = l;
- pthread_mutex_lock(&gLibLock);
- e->next = gLibraryList;
- gLibraryList = e;
- pthread_mutex_unlock(&gLibLock);
- ALOGV("getLibrary() linked library %p for path %s", l, path);
-
- return 0;
-
-error:
- if (hdl != NULL) {
- dlclose(hdl);
- }
- //add entry for library errors in gLibraryFailedList
- lib_failed_entry_t *fl = malloc(sizeof(lib_failed_entry_t));
- fl->name = strndup(name, PATH_MAX);
- fl->path = strndup(path, PATH_MAX);
-
- list_elem_t *fe = malloc(sizeof(list_elem_t));
- fe->object = fl;
- fe->next = gLibraryFailedList;
- gLibraryFailedList = fe;
- ALOGV("getLibrary() linked error in library %p for path %s", fl, path);
-
- return -EINVAL;
-}
-
-// This will find the library and UUID tags of the sub effect pointed by the
-// node, gets the effect descriptor and lib_entry_t and adds the subeffect -
-// sub_entry_t to the gSubEffectList
-int addSubEffect(cnode *root)
-{
- ALOGV("addSubEffect");
- cnode *node;
- effect_uuid_t uuid;
- effect_descriptor_t *d;
- lib_entry_t *l;
- list_elem_t *e;
- node = config_find(root, LIBRARY_TAG);
- if (node == NULL) {
- return -EINVAL;
- }
- l = getLibrary(node->value);
- if (l == NULL) {
- ALOGW("addSubEffect() could not get library %s", node->value);
- return -EINVAL;
- }
- node = config_find(root, UUID_TAG);
- if (node == NULL) {
- return -EINVAL;
- }
- if (stringToUuid(node->value, &uuid) != 0) {
- ALOGW("addSubEffect() invalid uuid %s", node->value);
- return -EINVAL;
- }
- d = malloc(sizeof(effect_descriptor_t));
- if (l->desc->get_descriptor(&uuid, d) != 0) {
- char s[40];
- uuidToString(&uuid, s, 40);
- ALOGW("Error querying effect %s on lib %s", s, l->name);
- free(d);
- return -EINVAL;
- }
-#if (LOG_NDEBUG==0)
- char s[512];
- dumpEffectDescriptor(d, s, sizeof(s), 0 /* indent */);
- ALOGV("addSubEffect() read descriptor %p:%s",d, s);
-#endif
- if (EFFECT_API_VERSION_MAJOR(d->apiVersion) !=
- EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) {
- ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name);
- free(d);
- return -EINVAL;
- }
- sub_effect_entry_t *sub_effect = malloc(sizeof(sub_effect_entry_t));
- sub_effect->object = d;
- // lib_entry_t is stored since the sub effects are not linked to the library
- sub_effect->lib = l;
- e = malloc(sizeof(list_elem_t));
- e->object = sub_effect;
- e->next = gSubEffectList->sub_elem;
- gSubEffectList->sub_elem = e;
- ALOGV("addSubEffect end");
- return 0;
-}
-
-int loadEffects(cnode *root)
-{
- cnode *node;
-
- node = config_find(root, EFFECTS_TAG);
- if (node == NULL) {
- return -ENOENT;
- }
- node = node->first_child;
- while (node) {
- loadEffect(node);
- node = node->next;
- }
- return 0;
-}
-
-int loadEffect(cnode *root)
-{
- cnode *node;
- effect_uuid_t uuid;
- lib_entry_t *l;
- effect_descriptor_t *d;
- list_elem_t *e;
-
- node = config_find(root, LIBRARY_TAG);
- if (node == NULL) {
- return -EINVAL;
- }
-
- l = getLibrary(node->value);
- if (l == NULL) {
- ALOGW("loadEffect() could not get library %s", node->value);
- return -EINVAL;
- }
-
- node = config_find(root, UUID_TAG);
- if (node == NULL) {
- return -EINVAL;
- }
- if (stringToUuid(node->value, &uuid) != 0) {
- ALOGW("loadEffect() invalid uuid %s", node->value);
- return -EINVAL;
- }
- lib_entry_t *tmp;
- bool skip = false;
- if (findEffect(NULL, &uuid, &tmp, NULL) == 0) {
- ALOGW("skipping duplicate uuid %s %s", node->value,
- node->next ? "and its sub-effects" : "");
- skip = true;
- }
-
- d = malloc(sizeof(effect_descriptor_t));
- if (l->desc->get_descriptor(&uuid, d) != 0) {
- char s[40];
- uuidToString(&uuid, s, 40);
- ALOGW("Error querying effect %s on lib %s", s, l->name);
- free(d);
- return -EINVAL;
- }
-#if (LOG_NDEBUG==0)
- char s[512];
- dumpEffectDescriptor(d, s, sizeof(s), 0 /* indent */);
- ALOGV("loadEffect() read descriptor %p:%s",d, s);
-#endif
- if (EFFECT_API_VERSION_MAJOR(d->apiVersion) !=
- EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) {
- ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name);
- free(d);
- return -EINVAL;
- }
- e = malloc(sizeof(list_elem_t));
- e->object = d;
- if (skip) {
- e->next = gSkippedEffects;
- gSkippedEffects = e;
- return -EINVAL;
- } else {
- e->next = l->effects;
- l->effects = e;
- }
-
- // After the UUID node in the config_tree, if node->next is valid,
- // that would be sub effect node.
- // Find the sub effects and add them to the gSubEffectList
- node = node->next;
- int count = 2;
- bool hwSubefx = false, swSubefx = false;
- list_sub_elem_t *sube = NULL;
- if (node != NULL) {
- ALOGV("Adding the effect to gEffectSubList as there are sub effects");
- sube = malloc(sizeof(list_sub_elem_t));
- sube->object = d;
- sube->sub_elem = NULL;
- sube->next = gSubEffectList;
- gSubEffectList = sube;
- }
- while (node != NULL && count) {
- if (addSubEffect(node)) {
- ALOGW("loadEffect() could not add subEffect %s", node->value);
- // Change the gSubEffectList to point to older list;
- gSubEffectList = sube->next;
- free(sube->sub_elem);// Free an already added sub effect
- sube->sub_elem = NULL;
- free(sube);
- return -ENOENT;
- }
- sub_effect_entry_t *subEntry = (sub_effect_entry_t*)gSubEffectList->sub_elem->object;
- effect_descriptor_t *subEffectDesc = (effect_descriptor_t*)(subEntry->object);
- // Since we return a dummy descriptor for the proxy during
- // get_descriptor call,we replace it with the correspoding
- // sw effect descriptor, but with Proxy UUID
- // check for Sw desc
- if (!((subEffectDesc->flags & EFFECT_FLAG_HW_ACC_MASK) ==
- EFFECT_FLAG_HW_ACC_TUNNEL)) {
- swSubefx = true;
- *d = *subEffectDesc;
- d->uuid = uuid;
- ALOGV("loadEffect() Changed the Proxy desc");
- } else
- hwSubefx = true;
- count--;
- node = node->next;
- }
- // 1 HW and 1 SW sub effect found. Set the offload flag in the Proxy desc
- if (hwSubefx && swSubefx) {
- d->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED;
- }
- return 0;
-}
-
// Searches the sub effect matching to the specified uuid
// in the gSubEffectList. It gets the lib_entry_t for
// the matched sub_effect . Used in EffectCreate of sub effects
@@ -881,29 +503,6 @@
return ret;
}
-lib_entry_t *getLibrary(const char *name)
-{
- list_elem_t *e;
-
- if (gCachedLibrary &&
- !strncmp(gCachedLibrary->name, name, PATH_MAX)) {
- return gCachedLibrary;
- }
-
- e = gLibraryList;
- while (e) {
- lib_entry_t *l = (lib_entry_t *)e->object;
- if (!strcmp(l->name, name)) {
- gCachedLibrary = l;
- return l;
- }
- e = e->next;
- }
-
- return NULL;
-}
-
-
void resetEffectEnumeration()
{
gCurLib = gLibraryList;
@@ -935,114 +534,6 @@
return cnt;
}
-int findEffect(const effect_uuid_t *type,
- const effect_uuid_t *uuid,
- lib_entry_t **lib,
- effect_descriptor_t **desc)
-{
- list_elem_t *e = gLibraryList;
- lib_entry_t *l = NULL;
- effect_descriptor_t *d = NULL;
- int found = 0;
- int ret = 0;
-
- while (e && !found) {
- l = (lib_entry_t *)e->object;
- list_elem_t *efx = l->effects;
- while (efx) {
- d = (effect_descriptor_t *)efx->object;
- if (type != NULL && memcmp(&d->type, type, sizeof(effect_uuid_t)) == 0) {
- found = 1;
- break;
- }
- if (uuid != NULL && memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
- found = 1;
- break;
- }
- efx = efx->next;
- }
- e = e->next;
- }
- if (!found) {
- ALOGV("findEffect() effect not found");
- ret = -ENOENT;
- } else {
- ALOGV("findEffect() found effect: %s in lib %s", d->name, l->name);
- *lib = l;
- if (desc) {
- *desc = d;
- }
- }
-
- return ret;
-}
-
-void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len, int indent) {
- char s[256];
- char ss[256];
- char idt[indent + 1];
-
- memset(idt, ' ', indent);
- idt[indent] = 0;
-
- str[0] = 0;
-
- snprintf(s, sizeof(s), "%s%s / %s\n", idt, desc->name, desc->implementor);
- strlcat(str, s, len);
-
- uuidToString(&desc->uuid, s, sizeof(s));
- snprintf(ss, sizeof(ss), "%s UUID: %s\n", idt, s);
- strlcat(str, ss, len);
-
- uuidToString(&desc->type, s, sizeof(s));
- snprintf(ss, sizeof(ss), "%s TYPE: %s\n", idt, s);
- strlcat(str, ss, len);
-
- sprintf(s, "%s apiVersion: %08X\n%s flags: %08X\n", idt,
- desc->apiVersion, idt, desc->flags);
- strlcat(str, s, len);
-}
-
-int stringToUuid(const char *str, effect_uuid_t *uuid)
-{
- int tmp[10];
-
- if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
- tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
- return -EINVAL;
- }
- uuid->timeLow = (uint32_t)tmp[0];
- uuid->timeMid = (uint16_t)tmp[1];
- uuid->timeHiAndVersion = (uint16_t)tmp[2];
- uuid->clockSeq = (uint16_t)tmp[3];
- uuid->node[0] = (uint8_t)tmp[4];
- uuid->node[1] = (uint8_t)tmp[5];
- uuid->node[2] = (uint8_t)tmp[6];
- uuid->node[3] = (uint8_t)tmp[7];
- uuid->node[4] = (uint8_t)tmp[8];
- uuid->node[5] = (uint8_t)tmp[9];
-
- return 0;
-}
-
-int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen)
-{
-
- snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
- uuid->timeLow,
- uuid->timeMid,
- uuid->timeHiAndVersion,
- uuid->clockSeq,
- uuid->node[0],
- uuid->node[1],
- uuid->node[2],
- uuid->node[3],
- uuid->node[4],
- uuid->node[5]);
-
- return 0;
-}
-
int EffectDumpEffects(int fd) {
char s[512];
@@ -1092,6 +583,20 @@
e = e->next;
}
}
+ switch (gConfigNbElemSkipped) {
+ case -2:
+ dprintf(fd, "Effect configuration loading skipped.\n");
+ break;
+ case -1:
+ dprintf(fd, "XML effect configuration failed to load.\n");
+ break;
+ case 0:
+ dprintf(fd, "XML effect configuration loaded successfully.\n");
+ break;
+ default:
+ dprintf(fd, "XML effect configuration partially loaded, skipped %zd elements.\n",
+ gConfigNbElemSkipped);
+ }
return ret;
}
diff --git a/media/libeffects/factory/EffectsFactory.h b/media/libeffects/factory/EffectsFactory.h
index 72e0931..29dbc9c 100644
--- a/media/libeffects/factory/EffectsFactory.h
+++ b/media/libeffects/factory/EffectsFactory.h
@@ -20,7 +20,7 @@
#include <dirent.h>
#include <pthread.h>
-#include <android/log.h>
+#include <cutils/compiler.h>
#include <hardware/audio_effect.h>
#if __cplusplus
@@ -96,6 +96,7 @@
// *pDescriptor: updated with the sub effect descriptors.
//
////////////////////////////////////////////////////////////////////////////////
+ANDROID_API
int EffectGetSubEffects(const effect_uuid_t *pEffectUuid,
sub_effect_entry_t **pSube,
size_t size);
diff --git a/media/libeffects/factory/EffectsFactoryState.c b/media/libeffects/factory/EffectsFactoryState.c
new file mode 100644
index 0000000..b364004
--- /dev/null
+++ b/media/libeffects/factory/EffectsFactoryState.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2017 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_TAG "EffectsFactoryState"
+
+#include "EffectsFactoryState.h"
+
+#include "log/log.h"
+
+list_elem_t *gLibraryList;
+list_elem_t *gSkippedEffects;
+list_sub_elem_t *gSubEffectList;
+pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER;
+
+list_elem_t *gLibraryFailedList; //list of lib_failed_entry_t: libraries failed to load
+
+
+int findEffect(const effect_uuid_t *type,
+ const effect_uuid_t *uuid,
+ lib_entry_t **lib,
+ effect_descriptor_t **desc)
+{
+ list_elem_t *e = gLibraryList;
+ lib_entry_t *l = NULL;
+ effect_descriptor_t *d = NULL;
+ int found = 0;
+ int ret = 0;
+
+ while (e && !found) {
+ l = (lib_entry_t *)e->object;
+ list_elem_t *efx = l->effects;
+ while (efx) {
+ d = (effect_descriptor_t *)efx->object;
+ if (type != NULL && memcmp(&d->type, type, sizeof(effect_uuid_t)) == 0) {
+ found = 1;
+ break;
+ }
+ if (uuid != NULL && memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
+ found = 1;
+ break;
+ }
+ efx = efx->next;
+ }
+ e = e->next;
+ }
+ if (!found) {
+ ALOGV("findEffect() effect not found");
+ ret = -ENOENT;
+ } else {
+ ALOGV("findEffect() found effect: %s in lib %s", d->name, l->name);
+ *lib = l;
+ if (desc) {
+ *desc = d;
+ }
+ }
+
+ return ret;
+}
+
+int stringToUuid(const char *str, effect_uuid_t *uuid)
+{
+ int tmp[10];
+
+ if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+ tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
+ return -EINVAL;
+ }
+ uuid->timeLow = (uint32_t)tmp[0];
+ uuid->timeMid = (uint16_t)tmp[1];
+ uuid->timeHiAndVersion = (uint16_t)tmp[2];
+ uuid->clockSeq = (uint16_t)tmp[3];
+ uuid->node[0] = (uint8_t)tmp[4];
+ uuid->node[1] = (uint8_t)tmp[5];
+ uuid->node[2] = (uint8_t)tmp[6];
+ uuid->node[3] = (uint8_t)tmp[7];
+ uuid->node[4] = (uint8_t)tmp[8];
+ uuid->node[5] = (uint8_t)tmp[9];
+
+ return 0;
+}
+
+int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen)
+{
+
+ snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+ uuid->timeLow,
+ uuid->timeMid,
+ uuid->timeHiAndVersion,
+ uuid->clockSeq,
+ uuid->node[0],
+ uuid->node[1],
+ uuid->node[2],
+ uuid->node[3],
+ uuid->node[4],
+ uuid->node[5]);
+
+ return 0;
+}
+
+
+void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len, int indent) {
+ char s[256];
+ char ss[256];
+ char idt[indent + 1];
+
+ memset(idt, ' ', indent);
+ idt[indent] = 0;
+
+ str[0] = 0;
+
+ snprintf(s, sizeof(s), "%s%s / %s\n", idt, desc->name, desc->implementor);
+ strlcat(str, s, len);
+
+ uuidToString(&desc->uuid, s, sizeof(s));
+ snprintf(ss, sizeof(ss), "%s UUID: %s\n", idt, s);
+ strlcat(str, ss, len);
+
+ uuidToString(&desc->type, s, sizeof(s));
+ snprintf(ss, sizeof(ss), "%s TYPE: %s\n", idt, s);
+ strlcat(str, ss, len);
+
+ sprintf(s, "%s apiVersion: %08X\n%s flags: %08X\n", idt,
+ desc->apiVersion, idt, desc->flags);
+ strlcat(str, s, len);
+}
diff --git a/media/libeffects/factory/EffectsFactoryState.h b/media/libeffects/factory/EffectsFactoryState.h
new file mode 100644
index 0000000..aef945e
--- /dev/null
+++ b/media/libeffects/factory/EffectsFactoryState.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 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_EFFECTSFACTORYSTATE_H_
+#define ANDROID_EFFECTSFACTORYSTATE_H_
+
+#include "EffectsFactory.h"
+
+#if __cplusplus
+extern "C" {
+#endif
+
+/** @file Contains the state shared with configuration loader of the Effect factory.
+ * This global state should probably be refactor in a structure
+ * provided by the config loader on EffectsFactory init.
+ * This header also contains some helper functions to work on the state.
+ */
+
+extern list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
+// list of effects skipped because of duplicate uuid or invalid version
+extern list_elem_t *gSkippedEffects;
+// list of effect_descriptor and list of sub effects : all currently loaded
+// It does not contain effects without sub effects.
+extern list_sub_elem_t *gSubEffectList;
+extern pthread_mutex_t gLibLock; // controls access to gLibraryList
+
+extern list_elem_t *gLibraryFailedList; //list of lib_failed_entry_t: libraries failed to load
+
+
+
+int findEffect(const effect_uuid_t *type,
+ const effect_uuid_t *uuid,
+ lib_entry_t **lib,
+ effect_descriptor_t **desc);
+
+int stringToUuid(const char *str, effect_uuid_t *uuid);
+/** Used to log UUIDs */
+int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen);
+
+/** Used for debuging. */
+void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len, int indent);
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // ANDROID_EFFECTSFACTORYSTATE_H_
diff --git a/media/libeffects/factory/EffectsXmlConfigLoader.cpp b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
new file mode 100644
index 0000000..438b787
--- /dev/null
+++ b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2017 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_TAG "EffectsFactoryConfigLoader"
+//#define LOG_NDEBUG 0
+
+#include <dlfcn.h>
+#include <set>
+#include <stdlib.h>
+#include <string>
+
+#include <log/log.h>
+
+#include <media/EffectsConfig.h>
+
+#include "EffectsConfigLoader.h"
+#include "EffectsFactoryState.h"
+#include "EffectsXmlConfigLoader.h"
+
+namespace android {
+
+using namespace effectsConfig;
+
+/////////////////////////////////////////////////
+// Local functions
+/////////////////////////////////////////////////
+
+namespace {
+
+/** Similarly to dlopen, looks for the provided path in LD_EFFECT_LIBRARY_PATH.
+ * @return true if the library is found and set resolvedPath to its absolute path.
+ * false if not found
+ */
+bool resolveLibrary(const std::string& path, std::string* resolvedPath) {
+ for (auto* libraryDirectory : LD_EFFECT_LIBRARY_PATH) {
+ std::string candidatePath = std::string(libraryDirectory) + '/' + path;
+ if (access(candidatePath.c_str(), R_OK) == 0) {
+ *resolvedPath = std::move(candidatePath);
+ return true;
+ }
+ }
+ return false;
+}
+
+/** Loads a library given its relative path and stores the result in libEntry.
+ * @return true on success with libEntry's path, handle and desc filled
+ * false on success with libEntry's path filled with the path of the failed lib
+ * The caller MUST free the resources path (free) and handle (dlclose) if filled.
+ */
+bool loadLibrary(const char* relativePath, lib_entry_t* libEntry) noexcept {
+
+ std::string absolutePath;
+ if (!resolveLibrary(relativePath, &absolutePath)) {
+ ALOGE("Could not find library in effect directories: %s", relativePath);
+ libEntry->path = strdup(relativePath);
+ return false;
+ }
+ const char* path = absolutePath.c_str();
+ libEntry->path = strdup(path);
+
+ // Make sure the lib is closed on early return
+ std::unique_ptr<void, decltype(dlclose)*> libHandle(dlopen(path, RTLD_NOW),
+ dlclose);
+ if (libHandle == nullptr) {
+ ALOGE("Could not dlopen library %s: %s", path, dlerror());
+ return false;
+ }
+
+ auto* description = static_cast<audio_effect_library_t*>(
+ dlsym(libHandle.get(), AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR));
+ if (description == nullptr) {
+ ALOGE("Invalid effect library, failed not find symbol '%s' in %s: %s",
+ AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR, path, dlerror());
+ return false;
+ }
+
+ if (description->tag != AUDIO_EFFECT_LIBRARY_TAG) {
+ ALOGE("Bad tag %#08x in description structure, expected %#08x for library %s",
+ description->tag, AUDIO_EFFECT_LIBRARY_TAG, path);
+ return false;
+ }
+
+ uint32_t majorVersion = EFFECT_API_VERSION_MAJOR(description->version);
+ uint32_t expectedMajorVersion = EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION);
+ if (majorVersion != expectedMajorVersion) {
+ ALOGE("Unsupported major version %#08x, expected %#08x for library %s",
+ majorVersion, expectedMajorVersion, path);
+ return false;
+ }
+
+ libEntry->handle = libHandle.release();
+ libEntry->desc = description;
+ return true;
+}
+
+/** Because the structures will be destroyed by c code, using new to allocate shared structure
+ * is not possible. Provide a equivalent of unique_ptr for malloc/freed structure to make sure
+ * they are not leaked in the c++ code.
+ @{ */
+struct FreeDeleter {
+ void operator()(void* p) {
+ free(p);
+ }
+};
+/** unique_ptr for object created with malloc. */
+template <class T>
+using UniqueCPtr = std::unique_ptr<T, FreeDeleter>;
+
+/** c version of std::make_unique. Uses malloc and free. */
+template <class T>
+UniqueCPtr<T> makeUniqueC() {
+ T* ptr = new (malloc(sizeof(T))) T{}; // Use placement new to initialize the structure
+ return UniqueCPtr<T>{ptr};
+}
+
+/** @} */
+
+/** Push an not owned element in a list_elem link list with an optional lock. */
+template <class T, class ListElem>
+void listPush(T* object, ListElem** list, pthread_mutex_t* mutex = nullptr) noexcept {
+ auto listElem = makeUniqueC<ListElem>();
+ listElem->object = object;
+ if (mutex != nullptr) {
+ pthread_mutex_lock(mutex);
+ }
+ listElem->next = *list;
+ *list = listElem.release();
+ if (mutex != nullptr) {
+ pthread_mutex_unlock(mutex);
+ }
+}
+
+/** Push an owned element in a list_elem link list with an optional lock. */
+template <class T, class ListElem>
+void listPush(UniqueCPtr<T>&& object, ListElem** list, pthread_mutex_t* mutex = nullptr) noexcept {
+ listPush(object.release(), list, mutex);
+}
+
+size_t loadLibraries(const effectsConfig::Libraries& libs,
+ list_elem_t** libList, pthread_mutex_t* libListLock,
+ list_elem_t** libFailedList)
+{
+ size_t nbSkippedElement = 0;
+ for (auto& library : libs) {
+
+ // Construct a lib entry
+ auto libEntry = makeUniqueC<lib_entry_t>();
+ libEntry->name = strdup(library.name.c_str());
+ libEntry->effects = nullptr;
+ pthread_mutex_init(&libEntry->lock, nullptr);
+
+ if (!loadLibrary(library.path.c_str(), libEntry.get())) {
+ // Register library load failure
+ listPush(std::move(libEntry), libFailedList);
+ ++nbSkippedElement;
+ continue;
+ }
+ listPush(std::move(libEntry), libList, libListLock);
+ }
+ return nbSkippedElement;
+}
+
+/** Find a library with the given name in the given list. */
+lib_entry_t* findLibrary(const char* name, list_elem_t* list) {
+
+ while (list != nullptr) {
+ auto* object = static_cast<lib_entry_t*>(list->object);
+ if (strcmp(object->name, name) == 0) {
+ return object;
+ }
+ list = list->next;
+ }
+ return nullptr;
+}
+
+struct UuidStr {
+ /** Length of an uuid represented as string. @TODO: use a constant instead of 40. */
+ char buff[40];
+};
+
+/** @return a string representing the provided uuid.
+ * By not providing an output buffer, it is implicitly created in the caller context.
+ * In such case the return pointer has the same lifetime as the expression containing uuidToString()
+ */
+char* uuidToString(const effect_uuid_t& uuid, UuidStr&& str = {}) {
+ uuidToString(&uuid, str.buff, sizeof(str.buff));
+ return str.buff;
+}
+
+struct LoadEffectResult {
+ /** true if the effect is usable (aka, existing lib, desc, right version, unique uuid) */
+ bool success = false;
+ /** Set if the effect lib was found*/
+ lib_entry_t* lib = nullptr;
+ //* Set if the description was successfuly retrieved from the lib */
+ UniqueCPtr<effect_descriptor_t> effectDesc;
+};
+
+LoadEffectResult loadEffect(const EffectImpl& effect, const std::string& name,
+ list_elem_t* libList) {
+ LoadEffectResult result;
+
+ // Find the effect library
+ result.lib = findLibrary(effect.library->name.c_str(), libList);
+ if (result.lib == nullptr) {
+ ALOGE("Could not find library %s to load effect %s",
+ effect.library->name.c_str(), name.c_str());
+ return result;
+ }
+
+ result.effectDesc = makeUniqueC<effect_descriptor_t>();
+
+ // Get the effect descriptor
+ if (result.lib->desc->get_descriptor(&effect.uuid, result.effectDesc.get()) != 0) {
+ ALOGE("Error querying effect %s on lib %s",
+ uuidToString(effect.uuid), result.lib->name);
+ result.effectDesc.reset();
+ return result;
+ }
+
+ // Dump effect for debug
+#if (LOG_NDEBUG==0)
+ char s[512];
+ dumpEffectDescriptor(result.effectDesc.get(), s, sizeof(s), 0 /* indent */);
+ ALOGV("loadEffect() read descriptor %p:%s", result.effectDesc.get(), s);
+#endif
+
+ // Check effect is supported
+ uint32_t expectedMajorVersion = EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION);
+ if (EFFECT_API_VERSION_MAJOR(result.effectDesc->apiVersion) != expectedMajorVersion) {
+ ALOGE("Bad API version %#08x for effect %s in lib %s, expected major %#08x",
+ result.effectDesc->apiVersion, name.c_str(), result.lib->name, expectedMajorVersion);
+ return result;
+ }
+
+ lib_entry_t *_;
+ if (findEffect(nullptr, &effect.uuid, &_, nullptr) == 0) {
+ ALOGE("Effect %s uuid %s already exist", uuidToString(effect.uuid), name.c_str());
+ return result;
+ }
+
+ result.success = true;
+ return result;
+}
+
+size_t loadEffects(const Effects& effects, list_elem_t* libList, list_elem_t** skippedEffects,
+ list_sub_elem_t** subEffectList) {
+ size_t nbSkippedElement = 0;
+
+ for (auto& effect : effects) {
+
+ auto effectLoadResult = loadEffect(effect, effect.name, libList);
+ if (!effectLoadResult.success) {
+ if (effectLoadResult.effectDesc != nullptr) {
+ listPush(std::move(effectLoadResult.effectDesc), skippedEffects);
+ }
+ ++nbSkippedElement;
+ continue;
+ }
+
+ if (effect.isProxy) {
+ auto swEffectLoadResult = loadEffect(effect.libSw, effect.name + " libsw", libList);
+ auto hwEffectLoadResult = loadEffect(effect.libHw, effect.name + " libhw", libList);
+ if (!swEffectLoadResult.success || !hwEffectLoadResult.success) {
+ // Push the main effect in the skipped list even if only a subeffect is invalid
+ // as the main effect is not usable without its subeffects.
+ listPush(std::move(effectLoadResult.effectDesc), skippedEffects);
+ ++nbSkippedElement;
+ continue;
+ }
+ listPush(effectLoadResult.effectDesc.get(), subEffectList);
+
+ // Since we return a dummy descriptor for the proxy during
+ // get_descriptor call, we replace it with the corresponding
+ // sw effect descriptor, but keep the Proxy UUID
+ *effectLoadResult.effectDesc = *swEffectLoadResult.effectDesc;
+ effectLoadResult.effectDesc->uuid = effect.uuid;
+
+ effectLoadResult.effectDesc->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED;
+
+ auto registerSubEffect = [subEffectList](auto&& result) {
+ auto entry = makeUniqueC<sub_effect_entry_t>();
+ entry->object = result.effectDesc.release();
+ // lib_entry_t is stored since the sub effects are not linked to the library
+ entry->lib = result.lib;
+ listPush(std::move(entry), &(*subEffectList)->sub_elem);
+ };
+ registerSubEffect(std::move(swEffectLoadResult));
+ registerSubEffect(std::move(hwEffectLoadResult));
+ }
+
+ listPush(std::move(effectLoadResult.effectDesc), &effectLoadResult.lib->effects);
+ }
+ return nbSkippedElement;
+}
+
+} // namespace
+
+/////////////////////////////////////////////////
+// Interface function
+/////////////////////////////////////////////////
+
+extern "C" ssize_t EffectLoadXmlEffectConfig(const char* path)
+{
+ using effectsConfig::parse;
+ auto result = path ? parse(path) : parse();
+ if (result.parsedConfig == nullptr) {
+ ALOGE("Failed to parse XML configuration file");
+ return -1;
+ }
+ result.nbSkippedElement += loadLibraries(result.parsedConfig->libraries,
+ &gLibraryList, &gLibLock, &gLibraryFailedList) +
+ loadEffects(result.parsedConfig->effects, gLibraryList,
+ &gSkippedEffects, &gSubEffectList);
+
+ ALOGE_IF(result.nbSkippedElement != 0, "%zu errors during loading of configuration: %s",
+ result.nbSkippedElement, path ?: effectsConfig::DEFAULT_PATH);
+
+ return result.nbSkippedElement;
+}
+
+} // namespace android
diff --git a/media/libeffects/factory/EffectsXmlConfigLoader.h b/media/libeffects/factory/EffectsXmlConfigLoader.h
new file mode 100644
index 0000000..a3fe9a3
--- /dev/null
+++ b/media/libeffects/factory/EffectsXmlConfigLoader.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 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_EFFECTSXMLCONFIGLOADER_H
+#define ANDROID_EFFECTSXMLCONFIGLOADER_H
+
+#include <unistd.h>
+
+#include <cutils/compiler.h>
+
+#include "EffectsFactoryState.h"
+
+#if __cplusplus
+extern "C" {
+#endif
+
+/** Parses the platform effect xml configuration and stores its content in EffectFactoryState.
+ * @param[in] path of the configuration file or NULL to load the default one
+ * @return -1 on unrecoverable error (eg: no configuration file)
+ * 0 on success
+ * the number of invalid elements (lib & effect) skipped if the config is partially invalid
+ * @note this function is exported for test purpose only. Do not call from outside this library.
+ */
+ANDROID_API
+ssize_t EffectLoadXmlEffectConfig(const char* path);
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // ANDROID_EFFECTSXMLCONFIGLOADER_H
diff --git a/media/libeffects/factory/include/media/EffectsFactoryApi.h b/media/libeffects/factory/include/media/EffectsFactoryApi.h
index 64a3212..a5a12eb 100644
--- a/media/libeffects/factory/include/media/EffectsFactoryApi.h
+++ b/media/libeffects/factory/include/media/EffectsFactoryApi.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_EFFECTSFACTORYAPI_H_
#define ANDROID_EFFECTSFACTORYAPI_H_
+#include <cutils/compiler.h>
#include <errno.h>
#include <stdint.h>
#include <sys/types.h>
@@ -52,6 +53,7 @@
// *pNumEffects: updated with number of effects in factory
//
////////////////////////////////////////////////////////////////////////////////
+ANDROID_API
int EffectQueryNumberEffects(uint32_t *pNumEffects);
////////////////////////////////////////////////////////////////////////////////
@@ -79,6 +81,7 @@
// *pDescriptor: updated with the effect descriptor.
//
////////////////////////////////////////////////////////////////////////////////
+ANDROID_API
int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor);
////////////////////////////////////////////////////////////////////////////////
@@ -110,6 +113,7 @@
// *pHandle: updated with the effect handle.
//
////////////////////////////////////////////////////////////////////////////////
+ANDROID_API
int EffectCreate(const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t ioId,
effect_handle_t *pHandle);
@@ -130,6 +134,7 @@
// -EINVAL invalid interface handle
//
////////////////////////////////////////////////////////////////////////////////
+ANDROID_API
int EffectRelease(effect_handle_t handle);
////////////////////////////////////////////////////////////////////////////////
@@ -153,6 +158,7 @@
// *pDescriptor: updated with the effect descriptor.
//
////////////////////////////////////////////////////////////////////////////////
+ANDROID_API
int EffectGetDescriptor(const effect_uuid_t *pEffectUuid, effect_descriptor_t *pDescriptor);
////////////////////////////////////////////////////////////////////////////////
@@ -169,8 +175,10 @@
// 1 if uuid is equal to EFFECT_UUID_NULL.
//
////////////////////////////////////////////////////////////////////////////////
+ANDROID_API
int EffectIsNullUuid(const effect_uuid_t *pEffectUuid);
+ANDROID_API
int EffectDumpEffects(int fd);
#if __cplusplus
diff --git a/media/libeffects/factory/test/DumpConfig.cpp b/media/libeffects/factory/test/DumpConfig.cpp
new file mode 100644
index 0000000..0a156b4
--- /dev/null
+++ b/media/libeffects/factory/test/DumpConfig.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/EffectsFactoryApi.h>
+#include <unistd.h>
+#include "EffectsXmlConfigLoader.h"
+#include "EffectsConfigLoader.h"
+
+int main(int argc, char* argv[]) {
+ const char* path = nullptr;
+ bool legacyFormat;
+
+ if (argc == 2 && strcmp(argv[1], "--legacy") == 0) {
+ legacyFormat = true;
+ fprintf(stderr, "Dumping legacy effect config file\n");
+ } else if ((argc == 2 || argc == 3) && strcmp(argv[1], "--xml") == 0) {
+ legacyFormat = false;
+ if (argc == 3) {
+ fprintf(stderr, "Dumping XML effect config file: %s\n", path);
+ } else {
+ fprintf(stderr, "Dumping default XML effect config file.\n");
+ }
+ } else {
+ fprintf(stderr, "Invalid arguments.\n"
+ "Usage: %s [--legacy|--xml [FILE]]\n", argv[0]);
+ return 1;
+ }
+
+ if (!legacyFormat) {
+ ssize_t ret = EffectLoadXmlEffectConfig(path);
+ if (ret < 0) {
+ fprintf(stderr, "loadXmlEffectConfig failed, see logcat for detail.\n");
+ return 2;
+ }
+ if (ret > 0) {
+ fprintf(stderr, "Partially failed to load config. Skipped %zu elements, "
+ "see logcat for detail.\n", (size_t)ret);
+ }
+ }
+
+ if (legacyFormat) {
+ auto ret = EffectLoadEffectConfig();
+ if (ret < 0) {
+ fprintf(stderr, "loadEffectConfig failed, see logcat for detail.\n");
+ return 3;
+ }
+ fprintf(stderr, "legacy loadEffectConfig has probably succeed, see logcat to make sure.\n");
+ }
+
+ if (EffectDumpEffects(STDOUT_FILENO) != 0) {
+ fprintf(stderr, "Effect dump failed, see logcat for detail.\n");
+ return 4;
+ }
+}
diff --git a/media/libeffects/lvm/lib/Android.mk b/media/libeffects/lvm/lib/Android.mk
index 83e8288..941eb3e 100644
--- a/media/libeffects/lvm/lib/Android.mk
+++ b/media/libeffects/lvm/lib/Android.mk
@@ -72,19 +72,25 @@
Common/src/From2iToMono_16.c \
Common/src/Copy_16.c \
Common/src/MonoTo2I_16.c \
+ Common/src/MonoTo2I_32.c \
Common/src/LoadConst_16.c \
+ Common/src/LoadConst_32.c \
Common/src/dB_to_Lin32.c \
Common/src/Shift_Sat_v16xv16.c \
+ Common/src/Shift_Sat_v32xv32.c \
Common/src/Abs_32.c \
Common/src/Int32RShiftToInt16_Sat_32x16.c \
Common/src/From2iToMono_32.c \
Common/src/mult3s_16x16.c \
+ Common/src/Mult3s_32x16.c \
Common/src/NonLinComp_D16.c \
Common/src/DelayMix_16x16.c \
Common/src/MSTo2i_Sat_16x16.c \
Common/src/From2iToMS_16x16.c \
Common/src/Mac3s_Sat_16x16.c \
+ Common/src/Mac3s_Sat_32x16.c \
Common/src/Add2_Sat_16x16.c \
+ Common/src/Add2_Sat_32x32.c \
Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c \
Common/src/LVC_MixSoft_1St_D16C31_SAT.c \
Common/src/LVC_Mixer_VarSlope_SetTimeConstant.c \
@@ -120,7 +126,7 @@
$(LOCAL_PATH)/StereoWidening/src \
$(LOCAL_PATH)/StereoWidening/lib
-LOCAL_CFLAGS += -fvisibility=hidden
+LOCAL_CFLAGS += -fvisibility=hidden -DBUILD_FLOAT -DHIGHER_FS
LOCAL_CFLAGS += -Wall -Werror
include $(BUILD_STATIC_LIBRARY)
@@ -179,6 +185,7 @@
$(LOCAL_PATH)/Common/lib \
$(LOCAL_PATH)/Common/src
-LOCAL_CFLAGS += -fvisibility=hidden
+LOCAL_CFLAGS += -fvisibility=hidden -DBUILD_FLOAT -DHIGHER_FS
LOCAL_CFLAGS += -Wall -Werror
+
include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libeffects/lvm/lib/Bass/lib/LVDBE.h b/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
index 228977d..4c2b954 100644
--- a/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
+++ b/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
@@ -198,6 +198,10 @@
#define LVDBE_CAP_FS_32000 64
#define LVDBE_CAP_FS_44100 128
#define LVDBE_CAP_FS_48000 256
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+#define LVDBE_CAP_FS_96000 512
+#define LVDBE_CAP_FS_192000 1024
+#endif
typedef enum
{
@@ -210,6 +214,10 @@
LVDBE_FS_32000 = 6,
LVDBE_FS_44100 = 7,
LVDBE_FS_48000 = 8,
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+ LVDBE_FS_96000 = 9,
+ LVDBE_FS_192000 = 10,
+#endif
LVDBE_FS_MAX = LVM_MAXINT_32
} LVDBE_Fs_en;
@@ -450,12 +458,17 @@
/* NOTES: */
/* */
/****************************************************************************************/
-
+#ifdef BUILD_FLOAT
+LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples);
+#else
LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 *pOutData,
LVM_UINT16 NumSamples);
-
+#endif
#ifdef __cplusplus
}
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Coeffs.h b/media/libeffects/lvm/lib/Bass/src/LVDBE_Coeffs.h
index b1ebadf..f32ed30 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Coeffs.h
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Coeffs.h
@@ -19,6 +19,7 @@
#define __LVDBE_COEFFS_H__
+#ifndef BUILD_FLOAT
/************************************************************************************/
/* */
/* General */
@@ -514,5 +515,632 @@
#define MIX_TC_Fs44100 32097 /* Floating point value 0.979515 */
#define MIX_TC_Fs48000 32150 /* Floating point value 0.981150 */
+#else /*BUILD_FLOAT*/
+/************************************************************************************/
+/* */
+/* General */
+/* */
+/************************************************************************************/
+
+#define LVDBE_SCALESHIFT 10 /* As a power of 2 */
+
+
+/************************************************************************************/
+/* */
+/* High Pass Filter coefficients */
+/* */
+/************************************************************************************/
+
+ /* Coefficients for centre frequency 55Hz */
+#define HPF_Fs8000_Fc55_A0 0.958849f
+#define HPF_Fs8000_Fc55_A1 -1.917698f
+#define HPF_Fs8000_Fc55_A2 0.958849f
+#define HPF_Fs8000_Fc55_B1 -1.939001f
+#define HPF_Fs8000_Fc55_B2 0.940807f
+#define HPF_Fs11025_Fc55_A0 0.966909f
+#define HPF_Fs11025_Fc55_A1 -1.933818f
+#define HPF_Fs11025_Fc55_A2 0.966909f
+#define HPF_Fs11025_Fc55_B1 -1.955732f
+#define HPF_Fs11025_Fc55_B2 0.956690f
+#define HPF_Fs12000_Fc55_A0 0.968650f
+#define HPF_Fs12000_Fc55_A1 -1.937300f
+#define HPF_Fs12000_Fc55_A2 0.968650f
+#define HPF_Fs12000_Fc55_B1 -1.959327f
+#define HPF_Fs12000_Fc55_B2 0.960138f
+#define HPF_Fs16000_Fc55_A0 0.973588f
+#define HPF_Fs16000_Fc55_A1 -1.947176f
+#define HPF_Fs16000_Fc55_A2 0.973588f
+#define HPF_Fs16000_Fc55_B1 -1.969494f
+#define HPF_Fs16000_Fc55_B2 0.969952f
+#define HPF_Fs22050_Fc55_A0 0.977671f
+#define HPF_Fs22050_Fc55_A1 -1.955343f
+#define HPF_Fs22050_Fc55_A2 0.977671f
+#define HPF_Fs22050_Fc55_B1 -1.977863f
+#define HPF_Fs22050_Fc55_B2 0.978105f
+#define HPF_Fs24000_Fc55_A0 0.978551f
+#define HPF_Fs24000_Fc55_A1 -1.957102f
+#define HPF_Fs24000_Fc55_A2 0.978551f
+#define HPF_Fs24000_Fc55_B1 -1.979662f
+#define HPF_Fs24000_Fc55_B2 0.979866f
+#define HPF_Fs32000_Fc55_A0 0.981042f
+#define HPF_Fs32000_Fc55_A1 -1.962084f
+#define HPF_Fs32000_Fc55_A2 0.981042f
+#define HPF_Fs32000_Fc55_B1 -1.984746f
+#define HPF_Fs32000_Fc55_B2 0.984861f
+#define HPF_Fs44100_Fc55_A0 0.983097f
+#define HPF_Fs44100_Fc55_A1 -1.966194f
+#define HPF_Fs44100_Fc55_A2 0.983097f
+#define HPF_Fs44100_Fc55_B1 -1.988931f
+#define HPF_Fs44100_Fc55_B2 0.988992f
+#define HPF_Fs48000_Fc55_A0 0.983539f
+#define HPF_Fs48000_Fc55_A1 -1.967079f
+#define HPF_Fs48000_Fc55_A2 0.983539f
+#define HPF_Fs48000_Fc55_B1 -1.989831f
+#define HPF_Fs48000_Fc55_B2 0.989882f
+
+#ifdef HIGHER_FS
+#define HPF_Fs96000_Fc55_A0 0.986040f
+#define HPF_Fs96000_Fc55_A1 -1.972080f
+#define HPF_Fs96000_Fc55_A2 0.986040f
+#define HPF_Fs96000_Fc55_B1 -1.994915f
+#define HPF_Fs96000_Fc55_B2 0.994928f
+
+#define HPF_Fs192000_Fc55_A0 0.987294f
+#define HPF_Fs192000_Fc55_A1 -1.974588f
+#define HPF_Fs192000_Fc55_A2 0.987294f
+#define HPF_Fs192000_Fc55_B1 -1.997458f
+#define HPF_Fs192000_Fc55_B2 0.997461f
#endif
+
+
+ /* Coefficients for centre frequency 66Hz */
+#define HPF_Fs8000_Fc66_A0 0.953016f
+#define HPF_Fs8000_Fc66_A1 -1.906032f
+#define HPF_Fs8000_Fc66_A2 0.953016f
+#define HPF_Fs8000_Fc66_B1 -1.926810f
+#define HPF_Fs8000_Fc66_B2 0.929396f
+#define HPF_Fs11025_Fc66_A0 0.962638f
+#define HPF_Fs11025_Fc66_A1 -1.925275f
+#define HPF_Fs11025_Fc66_A2 0.962638f
+#define HPF_Fs11025_Fc66_B1 -1.946881f
+#define HPF_Fs11025_Fc66_B2 0.948256f
+#define HPF_Fs12000_Fc66_A0 0.964718f
+#define HPF_Fs12000_Fc66_A1 -1.929435f
+#define HPF_Fs12000_Fc66_A2 0.964718f
+#define HPF_Fs12000_Fc66_B1 -1.951196f
+#define HPF_Fs12000_Fc66_B2 0.952359f
+#define HPF_Fs16000_Fc66_A0 0.970622f
+#define HPF_Fs16000_Fc66_A1 -1.941244f
+#define HPF_Fs16000_Fc66_A2 0.970622f
+#define HPF_Fs16000_Fc66_B1 -1.963394f
+#define HPF_Fs16000_Fc66_B2 0.964052f
+#define HPF_Fs22050_Fc66_A0 0.975509f
+#define HPF_Fs22050_Fc66_A1 -1.951019f
+#define HPF_Fs22050_Fc66_A2 0.975509f
+#define HPF_Fs22050_Fc66_B1 -1.973436f
+#define HPF_Fs22050_Fc66_B2 0.973784f
+#define HPF_Fs24000_Fc66_A0 0.976563f
+#define HPF_Fs24000_Fc66_A1 -1.953125f
+#define HPF_Fs24000_Fc66_A2 0.976563f
+#define HPF_Fs24000_Fc66_B1 -1.975594f
+#define HPF_Fs24000_Fc66_B2 0.975889f
+#define HPF_Fs32000_Fc66_A0 0.979547f
+#define HPF_Fs32000_Fc66_A1 -1.959093f
+#define HPF_Fs32000_Fc66_A2 0.979547f
+#define HPF_Fs32000_Fc66_B1 -1.981695f
+#define HPF_Fs32000_Fc66_B2 0.981861f
+#define HPF_Fs44100_Fc66_A0 0.982010f
+#define HPF_Fs44100_Fc66_A1 -1.964019f
+#define HPF_Fs44100_Fc66_A2 0.982010f
+#define HPF_Fs44100_Fc66_B1 -1.986718f
+#define HPF_Fs44100_Fc66_B2 0.986805f
+#define HPF_Fs48000_Fc66_A0 0.982540f
+#define HPF_Fs48000_Fc66_A1 -1.965079f
+#define HPF_Fs48000_Fc66_A2 0.982540f
+#define HPF_Fs48000_Fc66_B1 -1.987797f
+#define HPF_Fs48000_Fc66_B2 0.987871f
+
+#ifdef HIGHER_FS
+#define HPF_Fs96000_Fc66_A0 0.985539f
+#define HPF_Fs96000_Fc66_A1 -1.971077f
+#define HPF_Fs96000_Fc66_A2 0.985539f
+#define HPF_Fs96000_Fc66_B1 -1.993898f
+#define HPF_Fs96000_Fc66_B2 0.993917f
+
+#define HPF_Fs192000_Fc66_A0 0.987043f
+#define HPF_Fs192000_Fc66_A1 -1.974086f
+#define HPF_Fs192000_Fc66_A2 0.987043f
+#define HPF_Fs192000_Fc66_B1 -1.996949f
+#define HPF_Fs192000_Fc66_B2 0.996954f
+#endif
+
+/* Coefficients for centre frequency 78Hz */
+#define HPF_Fs8000_Fc78_A0 0.946693f
+#define HPF_Fs8000_Fc78_A1 -1.893387f
+#define HPF_Fs8000_Fc78_A2 0.946693f
+#define HPF_Fs8000_Fc78_B1 -1.913517f
+#define HPF_Fs8000_Fc78_B2 0.917105f
+#define HPF_Fs11025_Fc78_A0 0.957999f
+#define HPF_Fs11025_Fc78_A1 -1.915998f
+#define HPF_Fs11025_Fc78_A2 0.957999f
+#define HPF_Fs11025_Fc78_B1 -1.937229f
+#define HPF_Fs11025_Fc78_B2 0.939140f
+#define HPF_Fs12000_Fc78_A0 0.960446f
+#define HPF_Fs12000_Fc78_A1 -1.920892f
+#define HPF_Fs12000_Fc78_A2 0.960446f
+#define HPF_Fs12000_Fc78_B1 -1.942326f
+#define HPF_Fs12000_Fc78_B2 0.943944f
+#define HPF_Fs16000_Fc78_A0 0.967397f
+#define HPF_Fs16000_Fc78_A1 -1.934794f
+#define HPF_Fs16000_Fc78_A2 0.967397f
+#define HPF_Fs16000_Fc78_B1 -1.956740f
+#define HPF_Fs16000_Fc78_B2 0.957656f
+#define HPF_Fs22050_Fc78_A0 0.973156f
+#define HPF_Fs22050_Fc78_A1 -1.946313f
+#define HPF_Fs22050_Fc78_A2 0.973156f
+#define HPF_Fs22050_Fc78_B1 -1.968607f
+#define HPF_Fs22050_Fc78_B2 0.969092f
+#define HPF_Fs24000_Fc78_A0 0.974398f
+#define HPF_Fs24000_Fc78_A1 -1.948797f
+#define HPF_Fs24000_Fc78_A2 0.974398f
+#define HPF_Fs24000_Fc78_B1 -1.971157f
+#define HPF_Fs24000_Fc78_B2 0.971568f
+#define HPF_Fs32000_Fc78_A0 0.977918f
+#define HPF_Fs32000_Fc78_A1 -1.955836f
+#define HPF_Fs32000_Fc78_A2 0.977918f
+#define HPF_Fs32000_Fc78_B1 -1.978367f
+#define HPF_Fs32000_Fc78_B2 0.978599f
+#define HPF_Fs44100_Fc78_A0 0.980824f
+#define HPF_Fs44100_Fc78_A1 -1.961649f
+#define HPF_Fs44100_Fc78_A2 0.980824f
+#define HPF_Fs44100_Fc78_B1 -1.984303f
+#define HPF_Fs44100_Fc78_B2 0.984425f
+#define HPF_Fs48000_Fc78_A0 0.981450f
+#define HPF_Fs48000_Fc78_A1 -1.962900f
+#define HPF_Fs48000_Fc78_A2 0.981450f
+#define HPF_Fs48000_Fc78_B1 -1.985578f
+#define HPF_Fs48000_Fc78_B2 0.985681f
+
+#ifdef HIGHER_FS
+#define HPF_Fs96000_Fc78_A0 0.984992f
+#define HPF_Fs96000_Fc78_A1 -1.969984f
+#define HPF_Fs96000_Fc78_A2 0.984992f
+#define HPF_Fs96000_Fc78_B1 -1.992789f
+#define HPF_Fs96000_Fc78_B2 0.992815f
+
+#define HPF_Fs192000_Fc78_A0 0.986769f
+#define HPF_Fs192000_Fc78_A1 -1.973539f
+#define HPF_Fs192000_Fc78_A2 0.986769f
+#define HPF_Fs192000_Fc78_B1 -1.996394f
+#define HPF_Fs192000_Fc78_B2 0.996401f
+#endif
+
+/* Coefficients for centre frequency 90Hz */
+#define HPF_Fs8000_Fc90_A0 0.940412f
+#define HPF_Fs8000_Fc90_A1 -1.880825f
+#define HPF_Fs8000_Fc90_A2 0.940412f
+#define HPF_Fs8000_Fc90_B1 -1.900231f
+#define HPF_Fs8000_Fc90_B2 0.904977f
+#define HPF_Fs11025_Fc90_A0 0.953383f
+#define HPF_Fs11025_Fc90_A1 -1.906766f
+#define HPF_Fs11025_Fc90_A2 0.953383f
+#define HPF_Fs11025_Fc90_B1 -1.927579f
+#define HPF_Fs11025_Fc90_B2 0.930111f
+#define HPF_Fs12000_Fc90_A0 0.956193f
+#define HPF_Fs12000_Fc90_A1 -1.912387f
+#define HPF_Fs12000_Fc90_A2 0.956193f
+#define HPF_Fs12000_Fc90_B1 -1.933459f
+#define HPF_Fs12000_Fc90_B2 0.935603f
+#define HPF_Fs16000_Fc90_A0 0.964183f
+#define HPF_Fs16000_Fc90_A1 -1.928365f
+#define HPF_Fs16000_Fc90_A2 0.964183f
+#define HPF_Fs16000_Fc90_B1 -1.950087f
+#define HPF_Fs16000_Fc90_B2 0.951303f
+#define HPF_Fs22050_Fc90_A0 0.970809f
+#define HPF_Fs22050_Fc90_A1 -1.941618f
+#define HPF_Fs22050_Fc90_A2 0.970809f
+#define HPF_Fs22050_Fc90_B1 -1.963778f
+#define HPF_Fs22050_Fc90_B2 0.964423f
+#define HPF_Fs24000_Fc90_A0 0.972239f
+#define HPF_Fs24000_Fc90_A1 -1.944477f
+#define HPF_Fs24000_Fc90_A2 0.972239f
+#define HPF_Fs24000_Fc90_B1 -1.966721f
+#define HPF_Fs24000_Fc90_B2 0.967266f
+#define HPF_Fs32000_Fc90_A0 0.976292f
+#define HPF_Fs32000_Fc90_A1 -1.952584f
+#define HPF_Fs32000_Fc90_A2 0.976292f
+#define HPF_Fs32000_Fc90_B1 -1.975040f
+#define HPF_Fs32000_Fc90_B2 0.975347f
+#define HPF_Fs44100_Fc90_A0 0.979641f
+#define HPF_Fs44100_Fc90_A1 -1.959282f
+#define HPF_Fs44100_Fc90_A2 0.979641f
+#define HPF_Fs44100_Fc90_B1 -1.981888f
+#define HPF_Fs44100_Fc90_B2 0.982050f
+#define HPF_Fs48000_Fc90_A0 0.980362f
+#define HPF_Fs48000_Fc90_A1 -1.960724f
+#define HPF_Fs48000_Fc90_A2 0.980362f
+#define HPF_Fs48000_Fc90_B1 -1.983359f
+#define HPF_Fs48000_Fc90_B2 0.983497f
+
+#ifdef HIGHER_FS
+#define HPF_Fs96000_Fc90_A0 0.984446f
+#define HPF_Fs96000_Fc90_A1 -1.968892f
+#define HPF_Fs96000_Fc90_A2 0.984446f
+#define HPF_Fs96000_Fc90_B1 -1.991680f
+#define HPF_Fs96000_Fc90_B2 0.991714f
+
+#define HPF_Fs192000_Fc90_A0 0.986496f
+#define HPF_Fs192000_Fc90_A1 -1.972992f
+#define HPF_Fs192000_Fc90_A2 0.986496f
+#define HPF_Fs192000_Fc90_B1 -1.995840f
+#define HPF_Fs192000_Fc90_B2 0.995848f
+#endif
+
+/************************************************************************************/
+/* */
+/* Band Pass Filter coefficients */
+/* */
+/************************************************************************************/
+
+/* Coefficients for centre frequency 55Hz */
+#define BPF_Fs8000_Fc55_A0 0.009197f
+#define BPF_Fs8000_Fc55_A1 0.000000f
+#define BPF_Fs8000_Fc55_A2 -0.009197f
+#define BPF_Fs8000_Fc55_B1 -1.979545f
+#define BPF_Fs8000_Fc55_B2 0.981393f
+#define BPF_Fs11025_Fc55_A0 0.006691f
+#define BPF_Fs11025_Fc55_A1 0.000000f
+#define BPF_Fs11025_Fc55_A2 -0.006691f
+#define BPF_Fs11025_Fc55_B1 -1.985488f
+#define BPF_Fs11025_Fc55_B2 0.986464f
+#define BPF_Fs12000_Fc55_A0 0.006150f
+#define BPF_Fs12000_Fc55_A1 0.000000f
+#define BPF_Fs12000_Fc55_A2 -0.006150f
+#define BPF_Fs12000_Fc55_B1 -1.986733f
+#define BPF_Fs12000_Fc55_B2 0.987557f
+#define BPF_Fs16000_Fc55_A0 0.004620f
+#define BPF_Fs16000_Fc55_A1 0.000000f
+#define BPF_Fs16000_Fc55_A2 -0.004620f
+#define BPF_Fs16000_Fc55_B1 -1.990189f
+#define BPF_Fs16000_Fc55_B2 0.990653f
+#define BPF_Fs22050_Fc55_A0 0.003357f
+#define BPF_Fs22050_Fc55_A1 0.000000f
+#define BPF_Fs22050_Fc55_A2 -0.003357f
+#define BPF_Fs22050_Fc55_B1 -1.992964f
+#define BPF_Fs22050_Fc55_B2 0.993209f
+#define BPF_Fs24000_Fc55_A0 0.003085f
+#define BPF_Fs24000_Fc55_A1 0.000000f
+#define BPF_Fs24000_Fc55_A2 -0.003085f
+#define BPF_Fs24000_Fc55_B1 -1.993552f
+#define BPF_Fs24000_Fc55_B2 0.993759f
+#define BPF_Fs32000_Fc55_A0 0.002315f
+#define BPF_Fs32000_Fc55_A1 0.000000f
+#define BPF_Fs32000_Fc55_A2 -0.002315f
+#define BPF_Fs32000_Fc55_B1 -1.995199f
+#define BPF_Fs32000_Fc55_B2 0.995316f
+#define BPF_Fs44100_Fc55_A0 0.001681f
+#define BPF_Fs44100_Fc55_A1 0.000000f
+#define BPF_Fs44100_Fc55_A2 -0.001681f
+#define BPF_Fs44100_Fc55_B1 -1.996537f
+#define BPF_Fs44100_Fc55_B2 0.996599f
+#define BPF_Fs48000_Fc55_A0 0.001545f
+#define BPF_Fs48000_Fc55_A1 0.000000f
+#define BPF_Fs48000_Fc55_A2 -0.001545f
+#define BPF_Fs48000_Fc55_B1 -1.996823f
+#define BPF_Fs48000_Fc55_B2 0.996875f
+
+#ifdef HIGHER_FS
+#define BPF_Fs96000_Fc55_A0 0.000762f
+#define BPF_Fs96000_Fc55_A1 0.000000f
+#define BPF_Fs96000_Fc55_A2 -0.000762f
+#define BPF_Fs96000_Fc55_B1 -1.998461f
+#define BPF_Fs96000_Fc55_B2 0.998477f
+
+#define BPF_Fs192000_Fc55_A0 0.000381f
+#define BPF_Fs192000_Fc55_A1 0.000000f
+#define BPF_Fs192000_Fc55_A2 -0.000381f
+#define BPF_Fs192000_Fc55_B1 -1.999234f
+#define BPF_Fs192000_Fc55_B2 0.999238f
+#endif
+
+/* Coefficients for centre frequency 66Hz */
+#define BPF_Fs8000_Fc66_A0 0.012648f
+#define BPF_Fs8000_Fc66_A1 0.000000f
+#define BPF_Fs8000_Fc66_A2 -0.012648f
+#define BPF_Fs8000_Fc66_B1 -1.971760f
+#define BPF_Fs8000_Fc66_B2 0.974412f
+#define BPF_Fs11025_Fc66_A0 0.009209f
+#define BPF_Fs11025_Fc66_A1 0.000000f
+#define BPF_Fs11025_Fc66_A2 -0.009209f
+#define BPF_Fs11025_Fc66_B1 -1.979966f
+#define BPF_Fs11025_Fc66_B2 0.981368f
+#define BPF_Fs12000_Fc66_A0 0.008468f
+#define BPF_Fs12000_Fc66_A1 0.000000f
+#define BPF_Fs12000_Fc66_A2 -0.008468f
+#define BPF_Fs12000_Fc66_B1 -1.981685f
+#define BPF_Fs12000_Fc66_B2 0.982869f
+#define BPF_Fs16000_Fc66_A0 0.006364f
+#define BPF_Fs16000_Fc66_A1 0.000000f
+#define BPF_Fs16000_Fc66_A2 -0.006364f
+#define BPF_Fs16000_Fc66_B1 -1.986457f
+#define BPF_Fs16000_Fc66_B2 0.987124f
+#define BPF_Fs22050_Fc66_A0 0.004626f
+#define BPF_Fs22050_Fc66_A1 0.000000f
+#define BPF_Fs22050_Fc66_A2 -0.004626f
+#define BPF_Fs22050_Fc66_B1 -1.990288f
+#define BPF_Fs22050_Fc66_B2 0.990641f
+#define BPF_Fs24000_Fc66_A0 0.004252f
+#define BPF_Fs24000_Fc66_A1 0.000000f
+#define BPF_Fs24000_Fc66_A2 -0.004252f
+#define BPF_Fs24000_Fc66_B1 -1.991100f
+#define BPF_Fs24000_Fc66_B2 0.991398f
+#define BPF_Fs32000_Fc66_A0 0.003192f
+#define BPF_Fs32000_Fc66_A1 0.000000f
+#define BPF_Fs32000_Fc66_A2 -0.003192f
+#define BPF_Fs32000_Fc66_B1 -1.993374f
+#define BPF_Fs32000_Fc66_B2 0.993541f
+#define BPF_Fs44100_Fc66_A0 0.002318f
+#define BPF_Fs44100_Fc66_A1 0.000000f
+#define BPF_Fs44100_Fc66_A2 -0.002318f
+#define BPF_Fs44100_Fc66_B1 -1.995221f
+#define BPF_Fs44100_Fc66_B2 0.995309f
+#define BPF_Fs48000_Fc66_A0 0.002131f
+#define BPF_Fs48000_Fc66_A1 0.000000f
+#define BPF_Fs48000_Fc66_A2 -0.002131f
+#define BPF_Fs48000_Fc66_B1 -1.995615f
+#define BPF_Fs48000_Fc66_B2 0.995690f
+
+#ifdef HIGHER_FS
+#define BPF_Fs96000_Fc66_A0 0.001055f
+#define BPF_Fs96000_Fc66_A1 0.000000f
+#define BPF_Fs96000_Fc66_A2 -0.001055f
+#define BPF_Fs96000_Fc66_B1 -1.997868f
+#define BPF_Fs96000_Fc66_B2 0.997891f
+
+#define BPF_Fs192000_Fc66_A0 0.000528f
+#define BPF_Fs192000_Fc66_A1 0.000000f
+#define BPF_Fs192000_Fc66_A2 -0.000528f
+#define BPF_Fs192000_Fc66_B1 -1.998939f
+#define BPF_Fs192000_Fc66_B2 0.998945f
+#endif
+
+/* Coefficients for centre frequency 78Hz */
+#define BPF_Fs8000_Fc78_A0 0.018572f
+#define BPF_Fs8000_Fc78_A1 0.000000f
+#define BPF_Fs8000_Fc78_A2 -0.018572f
+#define BPF_Fs8000_Fc78_B1 -1.958745f
+#define BPF_Fs8000_Fc78_B2 0.962427f
+#define BPF_Fs11025_Fc78_A0 0.013545f
+#define BPF_Fs11025_Fc78_A1 0.000000f
+#define BPF_Fs11025_Fc78_A2 -0.013545f
+#define BPF_Fs11025_Fc78_B1 -1.970647f
+#define BPF_Fs11025_Fc78_B2 0.972596f
+#define BPF_Fs12000_Fc78_A0 0.012458f
+#define BPF_Fs12000_Fc78_A1 0.000000f
+#define BPF_Fs12000_Fc78_A2 -0.012458f
+#define BPF_Fs12000_Fc78_B1 -1.973148f
+#define BPF_Fs12000_Fc78_B2 0.974795f
+#define BPF_Fs16000_Fc78_A0 0.009373f
+#define BPF_Fs16000_Fc78_A1 0.000000f
+#define BPF_Fs16000_Fc78_A2 -0.009373f
+#define BPF_Fs16000_Fc78_B1 -1.980108f
+#define BPF_Fs16000_Fc78_B2 0.981037f
+#define BPF_Fs22050_Fc78_A0 0.006819f
+#define BPF_Fs22050_Fc78_A1 0.000000f
+#define BPF_Fs22050_Fc78_A2 -0.006819f
+#define BPF_Fs22050_Fc78_B1 -1.985714f
+#define BPF_Fs22050_Fc78_B2 0.986204f
+#define BPF_Fs24000_Fc78_A0 0.006268f
+#define BPF_Fs24000_Fc78_A1 0.000000f
+#define BPF_Fs24000_Fc78_A2 -0.006268f
+#define BPF_Fs24000_Fc78_B1 -1.986904f
+#define BPF_Fs24000_Fc78_B2 0.987318f
+#define BPF_Fs32000_Fc78_A0 0.004709f
+#define BPF_Fs32000_Fc78_A1 0.000000f
+#define BPF_Fs32000_Fc78_A2 -0.004709f
+#define BPF_Fs32000_Fc78_B1 -1.990240f
+#define BPF_Fs32000_Fc78_B2 0.990473f
+#define BPF_Fs44100_Fc78_A0 0.003421f
+#define BPF_Fs44100_Fc78_A1 0.000000f
+#define BPF_Fs44100_Fc78_A2 -0.003421f
+#define BPF_Fs44100_Fc78_B1 -1.992955f
+#define BPF_Fs44100_Fc78_B2 0.993078f
+#define BPF_Fs48000_Fc78_A0 0.003144f
+#define BPF_Fs48000_Fc78_A1 0.000000f
+#define BPF_Fs48000_Fc78_A2 -0.003144f
+#define BPF_Fs48000_Fc78_B1 -1.993535f
+#define BPF_Fs48000_Fc78_B2 0.993639f
+
+#ifdef HIGHER_FS
+#define BPF_Fs96000_Fc78_A0 0.001555f
+#define BPF_Fs96000_Fc78_A1 0.000000f
+#define BPF_Fs96000_Fc78_A2 -0.0015555f
+#define BPF_Fs96000_Fc78_B1 -1.996860f
+#define BPF_Fs96000_Fc78_B2 0.996891f
+
+#define BPF_Fs192000_Fc78_A0 0.000778f
+#define BPF_Fs192000_Fc78_A1 0.000000f
+#define BPF_Fs192000_Fc78_A2 -0.000778f
+#define BPF_Fs192000_Fc78_B1 -1.998437f
+#define BPF_Fs192000_Fc78_B2 0.998444f
+#endif
+
+/* Coefficients for centre frequency 90Hz */
+#define BPF_Fs8000_Fc90_A0 0.022760f
+#define BPF_Fs8000_Fc90_A1 0.000000f
+#define BPF_Fs8000_Fc90_A2 -0.022760f
+#define BPF_Fs8000_Fc90_B1 -1.949073f
+#define BPF_Fs8000_Fc90_B2 0.953953f
+#define BPF_Fs11025_Fc90_A0 0.016619f
+#define BPF_Fs11025_Fc90_A1 0.000000f
+#define BPF_Fs11025_Fc90_A2 -0.016619f
+#define BPF_Fs11025_Fc90_B1 -1.963791f
+#define BPF_Fs11025_Fc90_B2 0.966377f
+#define BPF_Fs12000_Fc90_A0 0.015289f
+#define BPF_Fs12000_Fc90_A1 0.000000f
+#define BPF_Fs12000_Fc90_A2 -0.015289f
+#define BPF_Fs12000_Fc90_B1 -1.966882f
+#define BPF_Fs12000_Fc90_B2 0.969067f
+#define BPF_Fs16000_Fc90_A0 0.011511f
+#define BPF_Fs16000_Fc90_A1 0.000000f
+#define BPF_Fs16000_Fc90_A2 -0.011511f
+#define BPF_Fs16000_Fc90_B1 -1.975477f
+#define BPF_Fs16000_Fc90_B2 0.976711f
+#define BPF_Fs22050_Fc90_A0 0.008379f
+#define BPF_Fs22050_Fc90_A1 0.000000f
+#define BPF_Fs22050_Fc90_A2 -0.008379f
+#define BPF_Fs22050_Fc90_B1 -1.982395f
+#define BPF_Fs22050_Fc90_B2 0.983047f
+#define BPF_Fs24000_Fc90_A0 0.007704f
+#define BPF_Fs24000_Fc90_A1 0.000000f
+#define BPF_Fs24000_Fc90_A2 -0.007704f
+#define BPF_Fs24000_Fc90_B1 -1.983863f
+#define BPF_Fs24000_Fc90_B2 0.984414f
+#define BPF_Fs32000_Fc90_A0 0.005789f
+#define BPF_Fs32000_Fc90_A1 0.000000f
+#define BPF_Fs32000_Fc90_A2 -0.005789f
+#define BPF_Fs32000_Fc90_B1 -1.987977f
+#define BPF_Fs32000_Fc90_B2 0.988288f
+#define BPF_Fs44100_Fc90_A0 0.004207f
+#define BPF_Fs44100_Fc90_A1 0.000000f
+#define BPF_Fs44100_Fc90_A2 -0.004207f
+#define BPF_Fs44100_Fc90_B1 -1.991324f
+#define BPF_Fs44100_Fc90_B2 0.991488f
+#define BPF_Fs48000_Fc90_A0 0.003867f
+#define BPF_Fs48000_Fc90_A1 0.000000f
+#define BPF_Fs48000_Fc90_A2 -0.003867f
+#define BPF_Fs48000_Fc90_B1 -1.992038f
+#define BPF_Fs48000_Fc90_B2 0.992177f
+
+#ifdef HIGHER_FS
+#define BPF_Fs96000_Fc90_A0 0.001913f
+#define BPF_Fs96000_Fc90_A1 0.000000f
+#define BPF_Fs96000_Fc90_A2 -0.001913f
+#define BPF_Fs96000_Fc90_B1 -1.996134f
+#define BPF_Fs96000_Fc90_B2 0.996174f
+
+#define BPF_Fs192000_Fc90_A0 0.000958f
+#define BPF_Fs192000_Fc90_A1 0.000000f
+#define BPF_Fs192000_Fc90_A2 -0.000958f
+#define BPF_Fs192000_Fc90_B1 -1.998075f
+#define BPF_Fs192000_Fc90_B2 0.998085f
+#endif
+
+/************************************************************************************/
+/* */
+/* Automatic Gain Control time constants and gain settings */
+/* */
+/************************************************************************************/
+
+/* AGC Time constants */
+#define AGC_ATTACK_Fs8000 0.841395f
+#define AGC_ATTACK_Fs11025 0.882223f
+#define AGC_ATTACK_Fs12000 0.891251f
+#define AGC_ATTACK_Fs16000 0.917276f
+#define AGC_ATTACK_Fs22050 0.939267f
+#define AGC_ATTACK_Fs24000 0.944061f
+#define AGC_ATTACK_Fs32000 0.957745f
+#define AGC_ATTACK_Fs44100 0.969158f
+#define AGC_ATTACK_Fs48000 0.971628f
+
+#ifdef HIGHER_FS
+#define AGC_ATTACK_Fs96000 0.985712f
+#define AGC_ATTACK_Fs192000 0.992830f
+#endif
+
+#define DECAY_SHIFT 10
+
+#define AGC_DECAY_Fs8000 0.000042f
+#define AGC_DECAY_Fs11025 0.000030f
+#define AGC_DECAY_Fs12000 0.000028f
+#define AGC_DECAY_Fs16000 0.000021f
+#define AGC_DECAY_Fs22050 0.000015f
+#define AGC_DECAY_Fs24000 0.000014f
+#define AGC_DECAY_Fs32000 0.000010f
+#define AGC_DECAY_Fs44100 0.000008f
+#define AGC_DECAY_Fs48000 0.000007f
+
+#ifdef HIGHER_FS
+#define AGC_DECAY_FS96000 0.0000035f
+#define AGC_DECAY_FS192000 0.00000175f
+#endif
+
+/* AGC Gain settings */
+#define AGC_GAIN_SCALE 31 /* As a power of 2 */
+#define AGC_GAIN_SHIFT 4 /* As a power of 2 */
+#define AGC_TARGETLEVEL 0.988553f
+#define AGC_HPFGAIN_0dB 0.412538f
+#define AGC_GAIN_0dB 0.000000f
+#define AGC_HPFGAIN_1dB 0.584893f
+#define AGC_GAIN_1dB 0.122018f
+#define AGC_HPFGAIN_2dB 0.778279f
+#define AGC_GAIN_2dB 0.258925f
+#define AGC_HPFGAIN_3dB 0.995262f
+#define AGC_GAIN_3dB 0.412538f
+#define AGC_HPFGAIN_4dB 1.238721f
+#define AGC_GAIN_4dB 0.584893f
+#define AGC_HPFGAIN_5dB 1.511886f
+#define AGC_GAIN_5dB 0.778279f
+#define AGC_HPFGAIN_6dB 1.818383f
+#define AGC_GAIN_6dB 0.995262f
+#define AGC_HPFGAIN_7dB 2.162278f
+#define AGC_GAIN_7dB 1.238721f
+#define AGC_HPFGAIN_8dB 2.548134f
+#define AGC_GAIN_8dB 1.511886f
+#define AGC_HPFGAIN_9dB 2.981072f
+#define AGC_GAIN_9dB 1.818383f
+#define AGC_HPFGAIN_10dB 3.466836f
+#define AGC_GAIN_10dB 2.162278f
+#define AGC_HPFGAIN_11dB 4.011872f
+#define AGC_GAIN_11dB 2.548134f
+#define AGC_HPFGAIN_12dB 4.623413f
+#define AGC_GAIN_12dB 2.981072f
+#define AGC_HPFGAIN_13dB 5.309573f
+#define AGC_GAIN_13dB 3.466836f
+#define AGC_HPFGAIN_14dB 6.079458f
+#define AGC_GAIN_14dB 4.011872f
+#define AGC_HPFGAIN_15dB 6.943282f
+#define AGC_GAIN_15dB 4.623413f
+
+/************************************************************************************/
+/* */
+/* Volume control */
+/* */
+/************************************************************************************/
+
+/* Volume control gain */
+#define VOLUME_MAX 0 /* In dBs */
+#define VOLUME_SHIFT 0 /* In dBs */
+
+/* Volume control time constants */
+#define VOL_TC_SHIFT 21 /* As a power of 2 */
+#define VOL_TC_Fs8000 0.024690f
+#define VOL_TC_Fs11025 0.017977f
+#define VOL_TC_Fs12000 0.016529f
+#define VOL_TC_Fs16000 0.012422f
+#define VOL_TC_Fs22050 0.009029f
+#define VOL_TC_Fs24000 0.008299f
+#define VOL_TC_Fs32000 0.006231f
+#define VOL_TC_Fs44100 0.004525f
+#define VOL_TC_Fs48000 0.004158f
+#ifdef HIGHER_FS
+#define VOL_TC_Fs96000 0.002079f
+#define VOL_TC_Fs192000 0.001039f
+#endif
+#define MIX_TC_Fs8000 29365 /* Floating point value 0.896151 */
+#define MIX_TC_Fs11025 30230 /* Floating point value 0.922548 */
+#define MIX_TC_Fs12000 30422 /* Floating point value 0.928415 */
+#define MIX_TC_Fs16000 30978 /* Floating point value 0.945387 */
+#define MIX_TC_Fs22050 31451 /* Floating point value 0.959804 */
+#define MIX_TC_Fs24000 31554 /* Floating point value 0.962956 */
+#define MIX_TC_Fs32000 31850 /* Floating point value 0.971973 */
+#define MIX_TC_Fs44100 32097 /* Floating point value 0.979515 */
+#define MIX_TC_Fs48000 32150 /* Floating point value 0.981150 */
+#ifdef HIGHER_FS
+#define MIX_TC_Fs96000 32456 /* Floating point value 0.990530 */
+#define MIX_TC_Fs192000 32611 /* Floating point value 0.992524 */
+#endif
+
+#endif /*BUILD_FLOAT*/
+#endif
\ No newline at end of file
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.c b/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.c
index b6632a3..fd4016b 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.c
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.c
@@ -107,35 +107,68 @@
LVDBE_Params_t *pParams)
{
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
/*
* Calculate the table offsets
*/
- LVM_UINT16 Offset = (LVM_UINT16)((LVM_UINT16)pParams->SampleRate + (LVM_UINT16)(pParams->CentreFrequency * (1+LVDBE_FS_48000)));
-
+ LVM_UINT16 Offset = (LVM_UINT16)((LVM_UINT16)pParams->SampleRate + \
+ (LVM_UINT16)(pParams->CentreFrequency * (1+LVDBE_FS_192000)));
+#else
+ /*
+ * Calculate the table offsets
+ */
+ LVM_UINT16 Offset = (LVM_UINT16)((LVM_UINT16)pParams->SampleRate + \
+ (LVM_UINT16)(pParams->CentreFrequency * (1+LVDBE_FS_48000)));
+#endif
/*
* Setup the high pass filter
*/
- LoadConst_16(0, /* Clear the history, value 0 */
- (void *)&pInstance->pData->HPFTaps, /* Destination Cast to void: \
- no dereferencing in function*/
+#ifndef BUILD_FLOAT
+ LoadConst_16(0, /* Clear the history, value 0 */
+ (void *)&pInstance->pData->HPFTaps, /* Destination Cast to void: \
+ no dereferencing in function*/
sizeof(pInstance->pData->HPFTaps)/sizeof(LVM_INT16)); /* Number of words */
- BQ_2I_D32F32Cll_TRC_WRA_01_Init(&pInstance->pCoef->HPFInstance, /* Initialise the filter */
+#else
+ LoadConst_Float(0, /* Clear the history, value 0 */
+ (void *)&pInstance->pData->HPFTaps, /* Destination Cast to void: \
+ no dereferencing in function*/
+ sizeof(pInstance->pData->HPFTaps) / sizeof(LVM_FLOAT)); /* Number of words */
+#endif
+#ifndef BUILD_FLOAT
+ BQ_2I_D32F32Cll_TRC_WRA_01_Init(&pInstance->pCoef->HPFInstance, /* Initialise the filter */
&pInstance->pData->HPFTaps,
(BQ_C32_Coefs_t *)&LVDBE_HPF_Table[Offset]);
+#else
+ BQ_2I_D32F32Cll_TRC_WRA_01_Init(&pInstance->pCoef->HPFInstance, /* Initialise the filter */
+ &pInstance->pData->HPFTaps,
+ (BQ_FLOAT_Coefs_t *)&LVDBE_HPF_Table[Offset]);
+#endif
/*
* Setup the band pass filter
*/
+#ifndef BUILD_FLOAT
LoadConst_16(0, /* Clear the history, value 0 */
- (void *)&pInstance->pData->BPFTaps, /* Destination Cast to void:\
+ (void *)&pInstance->pData->BPFTaps, /* Destination Cast to void: \
no dereferencing in function*/
sizeof(pInstance->pData->BPFTaps)/sizeof(LVM_INT16)); /* Number of words */
+#else
+ LoadConst_Float(0, /* Clear the history, value 0 */
+ (void *)&pInstance->pData->BPFTaps, /* Destination Cast to void: \
+ no dereferencing in function*/
+ sizeof(pInstance->pData->BPFTaps) / sizeof(LVM_FLOAT)); /* Number of words */
+#endif
+#ifndef BUILD_FLOAT
BP_1I_D32F32Cll_TRC_WRA_02_Init(&pInstance->pCoef->BPFInstance, /* Initialise the filter */
&pInstance->pData->BPFTaps,
(BP_C32_Coefs_t *)&LVDBE_BPF_Table[Offset]);
-
+#else
+ BP_1I_D32F32Cll_TRC_WRA_02_Init(&pInstance->pCoef->BPFInstance, /* Initialise the filter */
+ &pInstance->pData->BPFTaps,
+ (BP_FLOAT_Coefs_t *)&LVDBE_BPF_Table[Offset]);
+#endif
}
@@ -175,7 +208,9 @@
{
pInstance->pData->AGCInstance.AGC_MaxGain = LVDBE_AGC_GAIN_Table[(LVM_UINT16)pParams->EffectLevel]; /* High pass filter off */
}
+#ifndef BUILD_FLOAT
pInstance->pData->AGCInstance.AGC_GainShift = AGC_GAIN_SHIFT;
+#endif
pInstance->pData->AGCInstance.AGC_Target = AGC_TARGETLEVEL;
}
@@ -212,6 +247,9 @@
LVM_UINT16 dBOffset; /* Table offset */
LVM_INT16 Volume = 0; /* Required volume in dBs */
+#ifdef BUILD_FLOAT
+ LVM_FLOAT dBShifts_fac;
+#endif
/*
* Apply the volume if enabled
*/
@@ -237,33 +275,58 @@
dBOffset = (LVM_UINT16)(6 + Volume % 6); /* Get the dBs 0-5 */
dBShifts = (LVM_UINT16)(Volume / -6); /* Get the 6dB shifts */
-
+#ifdef BUILD_FLOAT
+ dBShifts_fac = (LVM_FLOAT)(1 << dBShifts);
+#endif
/*
* When DBE is enabled use AGC volume
*/
+#ifndef BUILD_FLOAT
pInstance->pData->AGCInstance.Target = ((LVM_INT32)LVDBE_VolumeTable[dBOffset] << 16);
pInstance->pData->AGCInstance.Target = pInstance->pData->AGCInstance.Target >> dBShifts;
-
+#else
+ pInstance->pData->AGCInstance.Target = (LVDBE_VolumeTable[dBOffset]);
+ pInstance->pData->AGCInstance.Target = pInstance->pData->AGCInstance.Target / dBShifts_fac;
+#endif
pInstance->pData->AGCInstance.VolumeTC = LVDBE_VolumeTCTable[(LVM_UINT16)pParams->SampleRate]; /* Volume update time constant */
+#ifndef BUILD_FLOAT
pInstance->pData->AGCInstance.VolumeShift = VOLUME_SHIFT+1;
+#endif
/*
* When DBE is disabled use the bypass volume control
*/
if(dBShifts > 0)
{
+#ifndef BUILD_FLOAT
LVC_Mixer_SetTarget(&pInstance->pData->BypassVolume.MixerStream[0],(((LVM_INT32)LVDBE_VolumeTable[dBOffset]) >> dBShifts));
+#else
+ LVC_Mixer_SetTarget(&pInstance->pData->BypassVolume.MixerStream[0],
+ LVDBE_VolumeTable[dBOffset] / dBShifts_fac);
+#endif
}
else
{
+#ifndef BUILD_FLOAT
LVC_Mixer_SetTarget(&pInstance->pData->BypassVolume.MixerStream[0],(LVM_INT32)LVDBE_VolumeTable[dBOffset]);
+#else
+ LVC_Mixer_SetTarget(&pInstance->pData->BypassVolume.MixerStream[0],
+ LVDBE_VolumeTable[dBOffset]);
+#endif
}
pInstance->pData->BypassVolume.MixerStream[0].CallbackSet = 1;
+#ifndef BUILD_FLOAT
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->pData->BypassVolume.MixerStream[0],
LVDBE_MIXER_TC,
(LVM_Fs_en)pInstance->Params.SampleRate,
2);
+#else
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->pData->BypassVolume.MixerStream[0],
+ LVDBE_MIXER_TC,
+ (LVM_Fs_en)pInstance->Params.SampleRate,
+ 2);
+#endif
}
@@ -309,7 +372,11 @@
{
LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance;
+#ifndef BUILD_FLOAT
LVMixer3_2St_st *pBypassMixer_Instance = &pInstance->pData->BypassMixer;
+#else
+ LVMixer3_2St_FLOAT_st *pBypassMixer_Instance = &pInstance->pData->BypassMixer;
+#endif
/*
@@ -332,12 +399,19 @@
{
LVDBE_SetAGC(pInstance, /* Instance pointer */
pParams); /* New parameters */
-
+#ifndef BUILD_FLOAT
LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[0],
LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[1],
LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
+#else
+ LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[0],
+ LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate, 2);
+
+ LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[1],
+ LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate, 2);
+#endif
}
@@ -357,13 +431,23 @@
if (pInstance->Params.OperatingMode==LVDBE_ON && pParams->OperatingMode==LVDBE_OFF)
{
+#ifndef BUILD_FLOAT
LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[0],0);
LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[1],0x00007FFF);
+#else
+ LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[0], 0);
+ LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[1], 1.0f);
+#endif
}
if (pInstance->Params.OperatingMode==LVDBE_OFF && pParams->OperatingMode==LVDBE_ON)
{
+#ifndef BUILD_FLOAT
LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[0],0x00007FFF);
LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[1],0);
+#else
+ LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[0], 1.0f);
+ LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[1], 0);
+#endif
}
/*
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c
index a3623bc..3fff2a2 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c
@@ -80,7 +80,11 @@
/*
* Data memory
*/
+#ifdef BUILD_FLOAT
+ pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Size = sizeof(LVDBE_Data_FLOAT_t);
+#else
pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Size = sizeof(LVDBE_Data_t);
+#endif
pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Alignment = LVDBE_PERSISTENT_DATA_ALIGN;
pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Type = LVDBE_PERSISTENT_DATA;
pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
@@ -88,7 +92,11 @@
/*
* Coef memory
*/
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size = sizeof(LVDBE_Coef_t);
+#ifdef BUILD_FLOAT
+ pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size = sizeof(LVDBE_Coef_FLOAT_t);
+#else
+ pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size = sizeof(LVDBE_Coef_t);
+#endif
pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Alignment = LVDBE_PERSISTENT_COEF_ALIGN;
pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Type = LVDBE_PERSISTENT_COEF;
pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
@@ -96,7 +104,12 @@
/*
* Scratch memory
*/
+#ifdef BUILD_FLOAT
+ ScratchSize = (LVM_UINT32)(LVDBE_SCRATCHBUFFERS_INPLACE*sizeof(LVM_FLOAT) * \
+ pCapabilities->MaxBlockSize);
+#else /*BUILD_FLOAT*/
ScratchSize = (LVM_UINT32)(LVDBE_SCRATCHBUFFERS_INPLACE*sizeof(LVM_INT16)*pCapabilities->MaxBlockSize);
+#endif
pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Size = ScratchSize;
pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Alignment = LVDBE_SCRATCH_ALIGN;
pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Type = LVDBE_SCRATCH;
@@ -151,10 +164,16 @@
{
LVDBE_Instance_t *pInstance;
+#ifdef BUILD_FLOAT
+ LVMixer3_1St_FLOAT_st *pMixer_Instance;
+ LVMixer3_2St_FLOAT_st *pBypassMixer_Instance;
+ LVM_FLOAT MixGain;
+#else
LVMixer3_1St_st *pMixer_Instance;
LVMixer3_2St_st *pBypassMixer_Instance;
- LVM_INT16 i;
LVM_INT32 MixGain;
+#endif
+ LVM_INT16 i;
/*
@@ -235,7 +254,11 @@
// initialize the mixer with some fixes values since otherwise LVDBE_SetVolume ends up
// reading uninitialized data
pMixer_Instance = &pInstance->pData->BypassVolume;
+#ifndef BUILD_FLOAT
LVC_Mixer_Init(&pMixer_Instance->MixerStream[0],0x00007FFF,0x00007FFF);
+#else
+ LVC_Mixer_Init(&pMixer_Instance->MixerStream[0], 1.0, 1.0);
+#endif
/*
* Initialise the volume
@@ -245,9 +268,13 @@
pInstance->pData->AGCInstance.Volume = pInstance->pData->AGCInstance.Target;
/* Initialise as the target */
-
+#ifndef BUILD_FLOAT
MixGain = LVC_Mixer_GetTarget(&pMixer_Instance->MixerStream[0]);
LVC_Mixer_Init(&pMixer_Instance->MixerStream[0],MixGain,MixGain);
+#else
+ MixGain = LVC_Mixer_GetTarget(&pMixer_Instance->MixerStream[0]);
+ LVC_Mixer_Init(&pMixer_Instance->MixerStream[0], MixGain, MixGain);
+#endif
/* Configure the mixer process path */
pMixer_Instance->MixerStream[0].CallbackParam = 0;
@@ -268,9 +295,11 @@
pBypassMixer_Instance->MixerStream[0].pCallbackHandle = LVM_NULL;
pBypassMixer_Instance->MixerStream[0].pCallBack = LVM_NULL;
pBypassMixer_Instance->MixerStream[0].CallbackSet=0;
+
LVC_Mixer_Init(&pBypassMixer_Instance->MixerStream[0],0,0);
LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[0],
LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pInstance->Params.SampleRate,2);
+
/*
* Setup the mixer gain for the unprocessed path
*/
@@ -278,9 +307,15 @@
pBypassMixer_Instance->MixerStream[1].pCallbackHandle = LVM_NULL;
pBypassMixer_Instance->MixerStream[1].pCallBack = LVM_NULL;
pBypassMixer_Instance->MixerStream[1].CallbackSet=0;
+#ifndef BUILD_FLOAT
LVC_Mixer_Init(&pBypassMixer_Instance->MixerStream[1],0x00007FFF,0x00007FFF);
LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[1],
LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pInstance->Params.SampleRate,2);
+#else
+ LVC_Mixer_Init(&pBypassMixer_Instance->MixerStream[1], 1.0, 1.0);
+ LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[1],
+ LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pInstance->Params.SampleRate, 2);
+#endif
return(LVDBE_SUCCESS);
}
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h b/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
index 8339d3c..4e5207f 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
@@ -77,6 +77,7 @@
/****************************************************************************************/
/* Data structure */
+#ifndef BUILD_FLOAT
typedef struct
{
/* AGC parameters */
@@ -98,7 +99,29 @@
Biquad_Instance_t BPFInstance; /* Band pass filter instance */
} LVDBE_Coef_t;
+#else
+/* Data structure */
+typedef struct
+{
+ /* AGC parameters */
+ AGC_MIX_VOL_2St1Mon_FLOAT_t AGCInstance; /* AGC instance parameters */
+ /* Process variables */
+ Biquad_2I_Order2_FLOAT_Taps_t HPFTaps; /* High pass filter taps */
+ Biquad_1I_Order2_FLOAT_Taps_t BPFTaps; /* Band pass filter taps */
+ LVMixer3_1St_FLOAT_st BypassVolume; /* Bypass volume scaler */
+ LVMixer3_2St_FLOAT_st BypassMixer; /* Bypass Mixer for Click Removal */
+
+} LVDBE_Data_FLOAT_t;
+
+/* Coefs structure */
+typedef struct
+{
+ /* Process variables */
+ Biquad_FLOAT_Instance_t HPFInstance; /* High pass filter instance */
+ Biquad_FLOAT_Instance_t BPFInstance; /* Band pass filter instance */
+} LVDBE_Coef_FLOAT_t;
+#endif
/* Instance structure */
typedef struct
{
@@ -108,8 +131,13 @@
LVDBE_Capabilities_t Capabilities; /* Instance capabilities */
/* Data and coefficient pointers */
+#ifndef BUILD_FLOAT
LVDBE_Data_t *pData; /* Instance data */
LVDBE_Coef_t *pCoef; /* Instance coefficients */
+#else
+ LVDBE_Data_FLOAT_t *pData; /* Instance data */
+ LVDBE_Coef_FLOAT_t *pCoef; /* Instance coefficients */
+#endif
} LVDBE_Instance_t;
@@ -136,5 +164,3 @@
#endif /* __cplusplus */
#endif /* __LVDBE_PRIVATE_H__ */
-
-
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.c b/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.c
index 69d79d2..10ea700 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.c
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.c
@@ -27,7 +27,6 @@
#include "AGC.h"
#include "LVDBE_Coeffs.h" /* Filter coefficients */
-
/********************************************************************************************/
/* */
/* FUNCTION: LVDBE_Process */
@@ -72,136 +71,236 @@
/* overall end to end gain is odB. */
/* */
/********************************************************************************************/
+#ifndef BUILD_FLOAT
+LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance,
+ const LVM_INT16 *pInData, LVM_INT16 *pOutData, LVM_UINT16 NumSamples) {
-LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples)
+ LVDBE_Instance_t *pInstance = (LVDBE_Instance_t *) hInstance;
+ LVM_INT32 *pScratch =
+ (LVM_INT32 *) pInstance->MemoryTable.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress;
+ LVM_INT32 *pMono;
+ LVM_INT16 *pInput = (LVM_INT16 *) pInData;
+
+ /* Scratch for Volume Control starts at offset of 2*NumSamples short values from pScratch */
+ LVM_INT16 *pScratchVol = (LVM_INT16 *) (&pScratch[NumSamples]);
+
+ /* Scratch for Mono path starts at offset of 2*NumSamples 32-bit values from pScratch */
+ pMono = &pScratch[2 * NumSamples];
+
+ /*
+ * Check the number of samples is not too large
+ */
+ if (NumSamples > pInstance->Capabilities.MaxBlockSize) {
+ return (LVDBE_TOOMANYSAMPLES);
+ }
+
+ /*
+ * Check if the algorithm is enabled
+ */
+ /* DBE path is processed when DBE is ON or during On/Off transitions */
+ if ((pInstance->Params.OperatingMode == LVDBE_ON)
+ || (LVC_Mixer_GetCurrent(
+ &pInstance->pData->BypassMixer.MixerStream[0])
+ != LVC_Mixer_GetTarget(
+ &pInstance->pData->BypassMixer.MixerStream[0]))) {
+
+ /*
+ * Convert 16-bit samples to 32-bit and scale
+ * (For a 16-bit implementation apply headroom loss here)
+ */
+ Int16LShiftToInt32_16x32(pInput, /* Source 16-bit data */
+ pScratch, /* Dest. 32-bit data */
+ (LVM_INT16) (2 * NumSamples), /* Left and right */
+ LVDBE_SCALESHIFT); /* Shift scale */
+
+ /*
+ * Apply the high pass filter if selected
+ */
+ if (pInstance->Params.HPFSelect == LVDBE_HPF_ON) {
+ BQ_2I_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance,/* Filter instance */
+ (LVM_INT32 *) pScratch, /* Source */
+ (LVM_INT32 *) pScratch, /* Destination */
+ (LVM_INT16) NumSamples); /* Number of samples */
+ }
+
+ /*
+ * Create the mono stream
+ */
+ From2iToMono_32(pScratch, /* Stereo source */
+ pMono, /* Mono destination */
+ (LVM_INT16) NumSamples); /* Number of samples */
+
+ /*
+ * Apply the band pass filter
+ */
+ BP_1I_D32F32C30_TRC_WRA_02(&pInstance->pCoef->BPFInstance, /* Filter instance */
+ (LVM_INT32 *) pMono, /* Source */
+ (LVM_INT32 *) pMono, /* Destination */
+ (LVM_INT16) NumSamples); /* Number of samples */
+
+ /*
+ * Apply the AGC and mix
+ */
+ AGC_MIX_VOL_2St1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer */
+ pScratch, /* Stereo source */
+ pMono, /* Mono band pass source */
+ pScratch, /* Stereo destination */
+ NumSamples); /* Number of samples */
+
+ /*
+ * Convert 32-bit samples to 16-bit and saturate
+ * (Not required for 16-bit implemenations)
+ */
+ Int32RShiftToInt16_Sat_32x16(pScratch, /* Source 32-bit data */
+ (LVM_INT16 *) pScratch, /* Dest. 16-bit data */
+ (LVM_INT16) (2 * NumSamples), /* Left and right */
+ LVDBE_SCALESHIFT); /* Shift scale */
+
+ }
+
+ /* Bypass Volume path is processed when DBE is OFF or during On/Off transitions */
+ if ((pInstance->Params.OperatingMode == LVDBE_OFF)
+ || (LVC_Mixer_GetCurrent(
+ &pInstance->pData->BypassMixer.MixerStream[1])
+ != LVC_Mixer_GetTarget(
+ &pInstance->pData->BypassMixer.MixerStream[1]))) {
+
+ /*
+ * The algorithm is disabled but volume management is required to compensate for
+ * headroom and volume (if enabled)
+ */
+ LVC_MixSoft_1St_D16C31_SAT(&pInstance->pData->BypassVolume, pInData,
+ pScratchVol, (LVM_INT16) (2 * NumSamples)); /* Left and right */
+
+ }
+
+ /*
+ * Mix DBE processed path and bypass volume path
+ */
+ LVC_MixSoft_2St_D16C31_SAT(&pInstance->pData->BypassMixer,
+ (LVM_INT16 *) pScratch, pScratchVol, pOutData,
+ (LVM_INT16) (2 * NumSamples));
+
+ return (LVDBE_SUCCESS);
+}
+#else /*BUILD_FLOAT*/
+LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples)
{
- LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance;
- LVM_INT32 *pScratch = (LVM_INT32 *)pInstance->MemoryTable.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress;
- LVM_INT32 *pMono;
- LVM_INT16 *pInput = (LVM_INT16 *)pInData;
+ LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance;
+ LVM_FLOAT *pScratch_in = (LVM_FLOAT *)pInstance->MemoryTable.Region
+ [LVDBE_MEMREGION_SCRATCH].pBaseAddress;
+ LVM_FLOAT *pScratch = pScratch_in + 2 * NumSamples;
+ LVM_FLOAT *pMono;
+ LVM_INT32 ii = 0;
+ /* Scratch for Volume Control starts at offset of 4*NumSamples float values from pScratch */
+ LVM_FLOAT *pScratchVol = (LVM_FLOAT *)(&pScratch_in[4 * NumSamples]);
+// LVM_INT16 *pScratchVol_int = (LVM_INT16 *)(pScratchVol);
- /* Scratch for Volume Control starts at offset of 2*NumSamples short values from pScratch */
- LVM_INT16 *pScratchVol = (LVM_INT16 *)(&pScratch[NumSamples]);
+ /* Scratch for Mono path starts at offset of 6*NumSamples 32-bit values from pScratch */
+ pMono = &pScratch_in[4 * NumSamples];
- /* Scratch for Mono path starts at offset of 2*NumSamples 32-bit values from pScratch */
- pMono = &pScratch[2*NumSamples];
+ /*
+ * Check the number of samples is not too large
+ */
+ if (NumSamples > pInstance->Capabilities.MaxBlockSize)
+ {
+ return(LVDBE_TOOMANYSAMPLES);
+ }
+
+ /*
+ * Convert 16-bit samples to Float
+ */
+ Copy_Float(pInData, /* Source 16-bit data */
+ pScratch_in, /* Dest. 32-bit data */
+ (LVM_INT16)(2 * NumSamples)); /* Left and right */
+
+ for (ii = 0; ii < 2 * NumSamples; ii++) {
+ pScratch[ii] = pScratch_in[ii];
+ }
+ /*
+ * Check if the algorithm is enabled
+ */
+ /* DBE path is processed when DBE is ON or during On/Off transitions */
+ if ((pInstance->Params.OperatingMode == LVDBE_ON)||
+ (LVC_Mixer_GetCurrent(&pInstance->pData->BypassMixer.MixerStream[0])
+ !=LVC_Mixer_GetTarget(&pInstance->pData->BypassMixer.MixerStream[0])))
+ {
/*
- * Check the number of samples is not too large
+ * Apply the high pass filter if selected
*/
- if (NumSamples > pInstance->Capabilities.MaxBlockSize)
+ if (pInstance->Params.HPFSelect == LVDBE_HPF_ON)
{
- return(LVDBE_TOOMANYSAMPLES);
+ BQ_2I_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance,/* Filter instance */
+ (LVM_FLOAT *)pScratch, /* Source */
+ (LVM_FLOAT *)pScratch, /* Destination */
+ (LVM_INT16)NumSamples); /* Number of samples */
}
/*
- * Check if the algorithm is enabled
+ * Create the mono stream
*/
- /* DBE path is processed when DBE is ON or during On/Off transitions */
- if ((pInstance->Params.OperatingMode == LVDBE_ON)||
- (LVC_Mixer_GetCurrent(&pInstance->pData->BypassMixer.MixerStream[0])
- !=LVC_Mixer_GetTarget(&pInstance->pData->BypassMixer.MixerStream[0])))
- {
-
- /*
- * Convert 16-bit samples to 32-bit and scale
- * (For a 16-bit implementation apply headroom loss here)
- */
- Int16LShiftToInt32_16x32(pInput, /* Source 16-bit data */
- pScratch, /* Dest. 32-bit data */
- (LVM_INT16)(2*NumSamples), /* Left and right */
- LVDBE_SCALESHIFT); /* Shift scale */
-
-
- /*
- * Apply the high pass filter if selected
- */
- if (pInstance->Params.HPFSelect == LVDBE_HPF_ON)
- {
- BQ_2I_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance,/* Filter instance */
- (LVM_INT32 *)pScratch, /* Source */
- (LVM_INT32 *)pScratch, /* Destination */
- (LVM_INT16)NumSamples); /* Number of samples */
- }
-
-
- /*
- * Create the mono stream
- */
- From2iToMono_32(pScratch, /* Stereo source */
- pMono, /* Mono destination */
- (LVM_INT16)NumSamples); /* Number of samples */
-
-
- /*
- * Apply the band pass filter
- */
- BP_1I_D32F32C30_TRC_WRA_02(&pInstance->pCoef->BPFInstance, /* Filter instance */
- (LVM_INT32 *)pMono, /* Source */
- (LVM_INT32 *)pMono, /* Destination */
- (LVM_INT16)NumSamples); /* Number of samples */
-
-
- /*
- * Apply the AGC and mix
- */
- AGC_MIX_VOL_2St1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer */
- pScratch, /* Stereo source */
- pMono, /* Mono band pass source */
- pScratch, /* Stereo destination */
- NumSamples); /* Number of samples */
-
- /*
- * Convert 32-bit samples to 16-bit and saturate
- * (Not required for 16-bit implemenations)
- */
- Int32RShiftToInt16_Sat_32x16(pScratch, /* Source 32-bit data */
- (LVM_INT16 *)pScratch, /* Dest. 16-bit data */
- (LVM_INT16)(2*NumSamples), /* Left and right */
- LVDBE_SCALESHIFT); /* Shift scale */
-
- }
-
- /* Bypass Volume path is processed when DBE is OFF or during On/Off transitions */
- if ((pInstance->Params.OperatingMode == LVDBE_OFF)||
- (LVC_Mixer_GetCurrent(&pInstance->pData->BypassMixer.MixerStream[1])
- !=LVC_Mixer_GetTarget(&pInstance->pData->BypassMixer.MixerStream[1])))
- {
-
- /*
- * The algorithm is disabled but volume management is required to compensate for
- * headroom and volume (if enabled)
- */
- LVC_MixSoft_1St_D16C31_SAT(&pInstance->pData->BypassVolume,
- pInData,
- pScratchVol,
- (LVM_INT16)(2*NumSamples)); /* Left and right */
-
- }
+ From2iToMono_Float((LVM_FLOAT *)pScratch, /* Stereo source */
+ pMono, /* Mono destination */
+ (LVM_INT16)NumSamples); /* Number of samples */
/*
- * Mix DBE processed path and bypass volume path
+ * Apply the band pass filter
*/
- LVC_MixSoft_2St_D16C31_SAT(&pInstance->pData->BypassMixer,
- (LVM_INT16 *) pScratch,
- pScratchVol,
- pOutData,
- (LVM_INT16)(2*NumSamples));
+ BP_1I_D32F32C30_TRC_WRA_02(&pInstance->pCoef->BPFInstance, /* Filter instance */
+ (LVM_FLOAT *)pMono, /* Source */
+ (LVM_FLOAT *)pMono, /* Destination */
+ (LVM_INT16)NumSamples); /* Number of samples */
- return(LVDBE_SUCCESS);
+ /*
+ * Apply the AGC and mix
+ */
+ AGC_MIX_VOL_2St1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer */
+ pScratch, /* Stereo source */
+ pMono, /* Mono band pass source */
+ pScratch, /* Stereo destination */
+ NumSamples); /* Number of samples */
+
+ for (ii = 0; ii < 2 * NumSamples; ii++) {
+ //TODO: replace with existing clamping function
+ if(pScratch[ii] < -1.0) {
+ pScratch[ii] = -1.0;
+ } else if(pScratch[ii] > 1.0) {
+ pScratch[ii] = 1.0;
+ }
+ }
+ }
+
+ /* Bypass Volume path is processed when DBE is OFF or during On/Off transitions */
+ if ((pInstance->Params.OperatingMode == LVDBE_OFF)||
+ (LVC_Mixer_GetCurrent(&pInstance->pData->BypassMixer.MixerStream[1])
+ !=LVC_Mixer_GetTarget(&pInstance->pData->BypassMixer.MixerStream[1])))
+ {
+
+ /*
+ * The algorithm is disabled but volume management is required to compensate for
+ * headroom and volume (if enabled)
+ */
+ LVC_MixSoft_1St_D16C31_SAT(&pInstance->pData->BypassVolume,
+ pScratch_in,
+ pScratchVol,
+ (LVM_INT16)(2 * NumSamples)); /* Left and right */
+ }
+
+ /*
+ * Mix DBE processed path and bypass volume path
+ */
+ LVC_MixSoft_2St_D16C31_SAT(&pInstance->pData->BypassMixer,
+ pScratch,
+ pScratchVol,
+ pOutData,
+ (LVM_INT16)(2 * NumSamples));
+
+ return(LVDBE_SUCCESS);
}
-
-
-
-
-
-
-
-
-
-
+#endif
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.c b/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.c
index f5d229e..c4a9b14 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.c
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.c
@@ -36,7 +36,11 @@
/*
* High Pass Filter Coefficient table
*/
+#ifndef BUILD_FLOAT
const BQ_C32_Coefs_t LVDBE_HPF_Table[] = {
+#else /*BUILD_FLOAT*/
+const BQ_FLOAT_Coefs_t LVDBE_HPF_Table[] = {
+#endif /*BUILD_FLOAT*/
/* Coefficients for 55Hz centre frequency */
{HPF_Fs8000_Fc55_A2, /* 8kS/s coefficients */
HPF_Fs8000_Fc55_A1,
@@ -83,6 +87,18 @@
HPF_Fs48000_Fc55_A0,
-HPF_Fs48000_Fc55_B2,
-HPF_Fs48000_Fc55_B1},
+#ifdef HIGHER_FS
+ {HPF_Fs96000_Fc55_A2, /* 96kS/s coefficients */
+ HPF_Fs96000_Fc55_A1,
+ HPF_Fs96000_Fc55_A0,
+ -HPF_Fs96000_Fc55_B2,
+ -HPF_Fs96000_Fc55_B1},
+ {HPF_Fs192000_Fc55_A2, /* 192kS/s coefficients */
+ HPF_Fs192000_Fc55_A1,
+ HPF_Fs192000_Fc55_A0,
+ -HPF_Fs192000_Fc55_B2,
+ -HPF_Fs192000_Fc55_B1},
+#endif
/* Coefficients for 66Hz centre frequency */
{HPF_Fs8000_Fc66_A2, /* 8kS/s coefficients */
@@ -130,6 +146,19 @@
HPF_Fs48000_Fc66_A0,
-HPF_Fs48000_Fc66_B2,
-HPF_Fs48000_Fc66_B1},
+#ifdef HIGHER_FS
+ {HPF_Fs96000_Fc66_A2, /* 96kS/s coefficients */
+ HPF_Fs96000_Fc66_A1,
+ HPF_Fs96000_Fc66_A0,
+ -HPF_Fs96000_Fc66_B2,
+ -HPF_Fs96000_Fc66_B1},
+ {HPF_Fs192000_Fc66_A2, /* 192kS/s coefficients */
+ HPF_Fs192000_Fc66_A1,
+ HPF_Fs192000_Fc66_A0,
+ -HPF_Fs192000_Fc66_B2,
+ -HPF_Fs192000_Fc66_B1},
+#endif
+
/* Coefficients for 78Hz centre frequency */
{HPF_Fs8000_Fc78_A2, /* 8kS/s coefficients */
@@ -177,6 +206,19 @@
HPF_Fs48000_Fc78_A0,
-HPF_Fs48000_Fc78_B2,
-HPF_Fs48000_Fc78_B1},
+#ifdef HIGHER_FS
+ {HPF_Fs96000_Fc78_A2, /* 96kS/s coefficients */
+ HPF_Fs96000_Fc78_A1,
+ HPF_Fs96000_Fc78_A0,
+ -HPF_Fs96000_Fc78_B2,
+ -HPF_Fs96000_Fc78_B1},
+ {HPF_Fs192000_Fc78_A2, /* 192kS/s coefficients */
+ HPF_Fs192000_Fc78_A1,
+ HPF_Fs192000_Fc78_A0,
+ -HPF_Fs192000_Fc78_B2,
+ -HPF_Fs192000_Fc78_B1},
+#endif
+
/* Coefficients for 90Hz centre frequency */
{HPF_Fs8000_Fc90_A2, /* 8kS/s coefficients */
@@ -223,12 +265,32 @@
HPF_Fs48000_Fc90_A1,
HPF_Fs48000_Fc90_A0,
-HPF_Fs48000_Fc90_B2,
- -HPF_Fs48000_Fc90_B1}};
+ -HPF_Fs48000_Fc90_B1}
+
+#ifdef HIGHER_FS
+ ,
+ {HPF_Fs96000_Fc90_A2, /* 96kS/s coefficients */
+ HPF_Fs96000_Fc90_A1,
+ HPF_Fs96000_Fc90_A0,
+ -HPF_Fs96000_Fc90_B2,
+ -HPF_Fs96000_Fc90_B1},
+ {HPF_Fs192000_Fc90_A2, /* 192kS/s coefficients */
+ HPF_Fs192000_Fc90_A1,
+ HPF_Fs192000_Fc90_A0,
+ -HPF_Fs192000_Fc90_B2,
+ -HPF_Fs192000_Fc90_B1}
+#endif
+
+};
/*
* Band Pass Filter coefficient table
*/
+#ifndef BUILD_FLOAT
const BP_C32_Coefs_t LVDBE_BPF_Table[] = {
+#else /*BUILD_FLOAT*/
+const BP_FLOAT_Coefs_t LVDBE_BPF_Table[] = {
+#endif /*BUILD_FLOAT*/
/* Coefficients for 55Hz centre frequency */
{BPF_Fs8000_Fc55_A0, /* 8kS/s coefficients */
-BPF_Fs8000_Fc55_B2,
@@ -257,6 +319,14 @@
{BPF_Fs48000_Fc55_A0, /* 48kS/s coefficients */
-BPF_Fs48000_Fc55_B2,
-BPF_Fs48000_Fc55_B1},
+#ifdef HIGHER_FS
+ {BPF_Fs96000_Fc55_A0, /* 96kS/s coefficients */
+ -BPF_Fs96000_Fc55_B2,
+ -BPF_Fs96000_Fc55_B1},
+ {BPF_Fs192000_Fc55_A0, /* 192kS/s coefficients */
+ -BPF_Fs192000_Fc55_B2,
+ -BPF_Fs192000_Fc55_B1},
+#endif
/* Coefficients for 66Hz centre frequency */
{BPF_Fs8000_Fc66_A0, /* 8kS/s coefficients */
@@ -286,6 +356,14 @@
{BPF_Fs48000_Fc66_A0, /* 48kS/s coefficients */
-BPF_Fs48000_Fc66_B2,
-BPF_Fs48000_Fc66_B1},
+#ifdef HIGHER_FS
+ {BPF_Fs96000_Fc66_A0, /* 96kS/s coefficients */
+ -BPF_Fs96000_Fc66_B2,
+ -BPF_Fs96000_Fc66_B1},
+ {BPF_Fs192000_Fc66_A0, /* 192kS/s coefficients */
+ -BPF_Fs192000_Fc66_B2,
+ -BPF_Fs192000_Fc66_B1},
+#endif
/* Coefficients for 78Hz centre frequency */
{BPF_Fs8000_Fc78_A0, /* 8kS/s coefficients */
@@ -315,6 +393,14 @@
{BPF_Fs48000_Fc78_A0, /* 48kS/s coefficients */
-BPF_Fs48000_Fc78_B2,
-BPF_Fs48000_Fc78_B1},
+#ifdef HIGHER_FS
+ {BPF_Fs96000_Fc78_A0, /* 96kS/s coefficients */
+ -BPF_Fs96000_Fc78_B2,
+ -BPF_Fs96000_Fc78_B1},
+ {BPF_Fs192000_Fc78_A0, /* 192kS/s coefficients */
+ -BPF_Fs192000_Fc78_B2,
+ -BPF_Fs192000_Fc78_B1},
+#endif
/* Coefficients for 90Hz centre frequency */
{BPF_Fs8000_Fc90_A0, /* 8kS/s coefficients */
@@ -343,7 +429,19 @@
-BPF_Fs44100_Fc90_B1},
{BPF_Fs48000_Fc90_A0, /* 48kS/s coefficients */
-BPF_Fs48000_Fc90_B2,
- -BPF_Fs48000_Fc90_B1}};
+ -BPF_Fs48000_Fc90_B1}
+#ifdef HIGHER_FS
+ ,
+ {BPF_Fs96000_Fc90_A0, /* 96kS/s coefficients */
+ -BPF_Fs96000_Fc90_B2,
+ -BPF_Fs96000_Fc90_B1},
+ {BPF_Fs192000_Fc90_A0, /* 192kS/s coefficients */
+ -BPF_Fs192000_Fc90_B2,
+ -BPF_Fs192000_Fc90_B1}
+#endif
+
+
+};
/************************************************************************************/
@@ -353,7 +451,11 @@
/************************************************************************************/
/* Attack time (signal too large) */
+#ifndef BUILD_FLOAT
const LVM_INT16 LVDBE_AGC_ATTACK_Table[] = {
+#else /*BUILD_FLOAT*/
+const LVM_FLOAT LVDBE_AGC_ATTACK_Table[] = {
+#endif /*BUILD_FLOAT*/
AGC_ATTACK_Fs8000,
AGC_ATTACK_Fs11025,
AGC_ATTACK_Fs12000,
@@ -362,10 +464,20 @@
AGC_ATTACK_Fs24000,
AGC_ATTACK_Fs32000,
AGC_ATTACK_Fs44100,
- AGC_ATTACK_Fs48000};
+ AGC_ATTACK_Fs48000
+#ifdef HIGHER_FS
+ ,AGC_ATTACK_Fs96000
+ ,AGC_ATTACK_Fs192000
+#endif
+
+};
/* Decay time (signal too small) */
+#ifndef BUILD_FLOAT
const LVM_INT16 LVDBE_AGC_DECAY_Table[] = {
+#else /*BUILD_FLOAT*/
+const LVM_FLOAT LVDBE_AGC_DECAY_Table[] = {
+#endif /*BUILD_FLOAT*/
AGC_DECAY_Fs8000,
AGC_DECAY_Fs11025,
AGC_DECAY_Fs12000,
@@ -374,10 +486,20 @@
AGC_DECAY_Fs24000,
AGC_DECAY_Fs32000,
AGC_DECAY_Fs44100,
- AGC_DECAY_Fs48000};
+ AGC_DECAY_Fs48000
+#ifdef HIGHER_FS
+ ,AGC_DECAY_FS96000
+ ,AGC_DECAY_FS192000
+#endif
+
+};
/* Gain for use without the high pass filter */
+#ifndef BUILD_FLOAT
const LVM_INT32 LVDBE_AGC_GAIN_Table[] = {
+#else /*BUILD_FLOAT*/
+const LVM_FLOAT LVDBE_AGC_GAIN_Table[] = {
+#endif /*BUILD_FLOAT*/
AGC_GAIN_0dB,
AGC_GAIN_1dB,
AGC_GAIN_2dB,
@@ -396,7 +518,11 @@
AGC_GAIN_15dB};
/* Gain for use with the high pass filter */
+#ifndef BUILD_FLOAT
const LVM_INT32 LVDBE_AGC_HPFGAIN_Table[] = {
+#else /*BUILD_FLOAT*/
+const LVM_FLOAT LVDBE_AGC_HPFGAIN_Table[] = {
+#endif /*BUILD_FLOAT*/
AGC_HPFGAIN_0dB,
AGC_HPFGAIN_1dB,
AGC_HPFGAIN_2dB,
@@ -422,6 +548,7 @@
/************************************************************************************/
/* dB to linear conversion table */
+#ifndef BUILD_FLOAT
const LVM_INT16 LVDBE_VolumeTable[] = {
0x4000, /* -6dB */
0x47FB, /* -5dB */
@@ -430,8 +557,22 @@
0x65AD, /* -2dB */
0x7215, /* -1dB */
0x7FFF}; /* 0dB */
+#else /*BUILD_FLOAT*/
+const LVM_FLOAT LVDBE_VolumeTable[] = {
+ 0.500000f, /* -6dB */
+ 0.562341f, /* -5dB */
+ 0.630957f, /* -4dB */
+ 0.707946f, /* -3dB */
+ 0.794328f, /* -2dB */
+ 0.891251f, /* -1dB */
+ 1.000000f}; /* 0dB */
+#endif /*BUILD_FLOAT*/
+#ifndef BUILD_FLOAT
const LVM_INT16 LVDBE_VolumeTCTable[] = {
+#else /*BUILD_FLOAT*/
+const LVM_FLOAT LVDBE_VolumeTCTable[] = {
+#endif /*BUILD_FLOAT*/
VOL_TC_Fs8000,
VOL_TC_Fs11025,
VOL_TC_Fs12000,
@@ -440,9 +581,17 @@
VOL_TC_Fs24000,
VOL_TC_Fs32000,
VOL_TC_Fs44100,
- VOL_TC_Fs48000};
+ VOL_TC_Fs48000
+#ifdef HIGHER_FS
+ ,VOL_TC_Fs96000
+ ,VOL_TC_Fs192000
+#endif
+};
+
+
const LVM_INT16 LVDBE_MixerTCTable[] = {
+
MIX_TC_Fs8000,
MIX_TC_Fs11025,
MIX_TC_Fs12000,
@@ -451,6 +600,10 @@
MIX_TC_Fs24000,
MIX_TC_Fs32000,
MIX_TC_Fs44100,
- MIX_TC_Fs48000};
+ MIX_TC_Fs48000
+#ifdef HIGHER_FS
+ ,MIX_TC_Fs96000
+ ,MIX_TC_Fs192000
+#endif
-
+};
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.h b/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.h
index 476e6a0..ca46e37 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.h
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.h
@@ -31,6 +31,7 @@
#include "BIQUAD.h"
#include "LVM_Types.h"
+#ifndef BUILD_FLOAT
/************************************************************************************/
/* */
/* Coefficients constant table */
@@ -76,8 +77,57 @@
extern const LVM_INT16 LVDBE_VolumeTCTable[];
+#else /*BUILD_FLOAT*/
+
+/************************************************************************************/
+/* */
+/* Coefficients constant table */
+/* */
+/************************************************************************************/
+
+/*
+ * High Pass Filter Coefficient table
+ */
+extern const BQ_FLOAT_Coefs_t LVDBE_HPF_Table[];
+
+/*
+ * Band Pass Filter coefficient table
+ */
+extern const BP_FLOAT_Coefs_t LVDBE_BPF_Table[];
+
+/************************************************************************************/
+/* */
+/* AGC constant tables */
+/* */
+/************************************************************************************/
+
+/* Attack time (signal too large) */
+extern const LVM_FLOAT LVDBE_AGC_ATTACK_Table[];
+
+/* Decay time (signal too small) */
+extern const LVM_FLOAT LVDBE_AGC_DECAY_Table[];
+
+/* Gain for use without the high pass filter */
+extern const LVM_FLOAT LVDBE_AGC_GAIN_Table[];
+
+/* Gain for use with the high pass filter */
+extern const LVM_FLOAT LVDBE_AGC_HPFGAIN_Table[];
+
+/************************************************************************************/
+/* */
+/* Volume control gain and time constant tables */
+/* */
+/************************************************************************************/
+
+/* dB to linear conversion table */
+extern const LVM_FLOAT LVDBE_VolumeTable[];
+extern const LVM_FLOAT LVDBE_VolumeTCTable[];
+
+#endif /*BUILD_FLOAT*/
+
extern const LVM_INT16 LVDBE_MixerTCTable[];
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/media/libeffects/lvm/lib/Bundle/lib/LVM.h b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
index 1ff2a2c..9b6da31 100644
--- a/media/libeffects/lvm/lib/Bundle/lib/LVM.h
+++ b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
@@ -514,11 +514,19 @@
/* STEREO the number of sample pairs in the block */
/* */
/****************************************************************************************/
+#ifdef BUILD_FLOAT
+LVM_ReturnStatus_en LVM_Process(LVM_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples,
+ LVM_UINT32 AudioTime);
+#else
LVM_ReturnStatus_en LVM_Process(LVM_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 *pOutData,
LVM_UINT16 NumSamples,
LVM_UINT32 AudioTime);
+#endif
/****************************************************************************************/
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c
index 6cbee7d..0a3c30e 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c
@@ -48,7 +48,152 @@
/* NOTES: */
/* */
/****************************************************************************************/
+#ifdef BUILD_FLOAT
+void LVM_BufferManagedIn(LVM_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT **pToProcess,
+ LVM_FLOAT **pProcessed,
+ LVM_UINT16 *pNumSamples)
+{
+ LVM_INT16 SampleCount; /* Number of samples to be processed this call */
+ LVM_INT16 NumSamples; /* Number of samples in scratch buffer */
+ LVM_FLOAT *pStart;
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+ LVM_Buffer_t *pBuffer;
+ LVM_FLOAT *pDest;
+ LVM_INT16 NumChannels = 2;
+
+
+ /*
+ * Set the processing address pointers
+ */
+ pBuffer = pInstance->pBufferManagement;
+ pDest = pBuffer->pScratch;
+ *pToProcess = pBuffer->pScratch;
+ *pProcessed = pBuffer->pScratch;
+
+ /*
+ * Check if it is the first call of a block
+ */
+ if (pInstance->SamplesToProcess == 0)
+ {
+ /*
+ * First call for a new block of samples
+ */
+ pInstance->SamplesToProcess = (LVM_INT16)(*pNumSamples + pBuffer->InDelaySamples);
+ pInstance->pInputSamples = (LVM_FLOAT *)pInData;
+ pBuffer->BufferState = LVM_FIRSTCALL;
+ }
+ pStart = pInstance->pInputSamples; /* Pointer to the input samples */
+ pBuffer->SamplesToOutput = 0; /* Samples to output is same as
+ number read for inplace processing */
+
+
+ /*
+ * Calculate the number of samples to process this call and update the buffer state
+ */
+ if (pInstance->SamplesToProcess > pInstance->InternalBlockSize)
+ {
+ /*
+ * Process the maximum bock size of samples.
+ */
+ SampleCount = pInstance->InternalBlockSize;
+ NumSamples = pInstance->InternalBlockSize;
+ }
+ else
+ {
+ /*
+ * Last call for the block, so calculate how many frames and samples to process
+ */
+ LVM_INT16 NumFrames;
+
+ NumSamples = pInstance->SamplesToProcess;
+ NumFrames = (LVM_INT16)(NumSamples >> MIN_INTERNAL_BLOCKSHIFT);
+ SampleCount = (LVM_INT16)(NumFrames << MIN_INTERNAL_BLOCKSHIFT);
+
+ /*
+ * Update the buffer state
+ */
+ if (pBuffer->BufferState == LVM_FIRSTCALL)
+ {
+ pBuffer->BufferState = LVM_FIRSTLASTCALL;
+ }
+ else
+ {
+ pBuffer->BufferState = LVM_LASTCALL;
+ }
+ }
+ *pNumSamples = (LVM_UINT16)SampleCount; /* Set the number of samples to process this call */
+
+
+ /*
+ * Copy samples from the delay buffer as required
+ */
+ if (((pBuffer->BufferState == LVM_FIRSTCALL) ||
+ (pBuffer->BufferState == LVM_FIRSTLASTCALL)) &&
+ (pBuffer->InDelaySamples != 0))
+ {
+ Copy_Float(&pBuffer->InDelayBuffer[0], /* Source */
+ pDest, /* Destination */
+ (LVM_INT16)(NumChannels * pBuffer->InDelaySamples)); /* Number of delay \
+ samples, left and right */
+ NumSamples = (LVM_INT16)(NumSamples - pBuffer->InDelaySamples); /* Update sample count */
+ pDest += NumChannels * pBuffer->InDelaySamples; /* Update the destination pointer */
+ }
+
+
+ /*
+ * Copy the rest of the samples for this call from the input buffer
+ */
+ if (NumSamples > 0)
+ {
+ Copy_Float(pStart, /* Source */
+ pDest, /* Destination */
+ (LVM_INT16)(NumChannels * NumSamples)); /* Number of input samples */
+ pStart += NumChannels * NumSamples; /* Update the input pointer */
+
+ /*
+ * Update the input data pointer and samples to output
+ */
+ /* Update samples to output */
+ pBuffer->SamplesToOutput = (LVM_INT16)(pBuffer->SamplesToOutput + NumSamples);
+ }
+
+
+ /*
+ * Update the sample count and input pointer
+ */
+ /* Update the count of samples */
+ pInstance->SamplesToProcess = (LVM_INT16)(pInstance->SamplesToProcess - SampleCount);
+ pInstance->pInputSamples = pStart; /* Update input sample pointer */
+
+
+ /*
+ * Save samples to the delay buffer if any left unprocessed
+ */
+ if ((pBuffer->BufferState == LVM_FIRSTLASTCALL) ||
+ (pBuffer->BufferState == LVM_LASTCALL))
+ {
+ NumSamples = pInstance->SamplesToProcess;
+ pStart = pBuffer->pScratch; /* Start of the buffer */
+ pStart += NumChannels * SampleCount; /* Offset by the number of processed samples */
+ if (NumSamples != 0)
+ {
+ Copy_Float(pStart, /* Source */
+ &pBuffer->InDelayBuffer[0], /* Destination */
+ (LVM_INT16)(NumChannels * NumSamples)); /* Number of input samples */
+ }
+
+
+ /*
+ * Update the delay sample count
+ */
+ pBuffer->InDelaySamples = NumSamples; /* Number of delay sample pairs */
+ pInstance->SamplesToProcess = 0; /* All Samples used */
+ }
+}
+#else
void LVM_BufferManagedIn(LVM_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 **pToProcess,
@@ -189,7 +334,7 @@
pInstance->SamplesToProcess = 0; /* All Samples used */
}
}
-
+#endif
/****************************************************************************************/
/* */
@@ -213,7 +358,47 @@
/* NOTES: */
/* */
/****************************************************************************************/
+#ifdef BUILD_FLOAT
+void LVM_BufferUnmanagedIn(LVM_Handle_t hInstance,
+ LVM_FLOAT **pToProcess,
+ LVM_FLOAT **pProcessed,
+ LVM_UINT16 *pNumSamples)
+{
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+
+
+ /*
+ * Check if this is the first call of a block
+ */
+ if (pInstance->SamplesToProcess == 0)
+ {
+ pInstance->SamplesToProcess = (LVM_INT16)*pNumSamples; /* Get the number of samples
+ on first call */
+ pInstance->pInputSamples = *pToProcess; /* Get the I/O pointers */
+ pInstance->pOutputSamples = *pProcessed;
+
+
+ /*
+ * Set te block size to process
+ */
+ if (pInstance->SamplesToProcess > pInstance->InternalBlockSize)
+ {
+ *pNumSamples = (LVM_UINT16)pInstance->InternalBlockSize;
+ }
+ else
+ {
+ *pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess;
+ }
+ }
+
+ /*
+ * Set the process pointers
+ */
+ *pToProcess = pInstance->pInputSamples;
+ *pProcessed = pInstance->pOutputSamples;
+}
+#else
void LVM_BufferUnmanagedIn(LVM_Handle_t hInstance,
LVM_INT16 **pToProcess,
LVM_INT16 **pProcessed,
@@ -252,7 +437,7 @@
*pToProcess = pInstance->pInputSamples;
*pProcessed = pInstance->pOutputSamples;
}
-
+#endif
/****************************************************************************************/
/* */
@@ -278,6 +463,7 @@
/* */
/****************************************************************************************/
+#ifndef BUILD_FLOAT
void LVM_BufferOptimisedIn(LVM_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 **pToProcess,
@@ -416,7 +602,7 @@
}
}
}
-
+#endif
/****************************************************************************************/
/* */
/* FUNCTION: LVM_BufferIn */
@@ -471,7 +657,37 @@
/* NOTES: */
/* */
/****************************************************************************************/
+#ifdef BUILD_FLOAT
+void LVM_BufferIn(LVM_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT **pToProcess,
+ LVM_FLOAT **pProcessed,
+ LVM_UINT16 *pNumSamples)
+{
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+
+
+ /*
+ * Check which mode, managed or unmanaged
+ */
+ if (pInstance->InstParams.BufferMode == LVM_MANAGED_BUFFERS)
+ {
+ LVM_BufferManagedIn(hInstance,
+ pInData,
+ pToProcess,
+ pProcessed,
+ pNumSamples);
+ }
+ else
+ {
+ LVM_BufferUnmanagedIn(hInstance,
+ pToProcess,
+ pProcessed,
+ pNumSamples);
+ }
+}
+#else
void LVM_BufferIn(LVM_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 **pToProcess,
@@ -501,7 +717,7 @@
pNumSamples);
}
}
-
+#endif
/****************************************************************************************/
/* */
/* FUNCTION: LVM_BufferManagedOut */
@@ -522,7 +738,156 @@
/* NOTES: */
/* */
/****************************************************************************************/
+#ifdef BUILD_FLOAT
+void LVM_BufferManagedOut(LVM_Handle_t hInstance,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 *pNumSamples)
+{
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+ LVM_Buffer_t *pBuffer = pInstance->pBufferManagement;
+ LVM_INT16 SampleCount = (LVM_INT16)*pNumSamples;
+ LVM_INT16 NumSamples;
+ LVM_FLOAT *pStart;
+ LVM_FLOAT *pDest;
+
+
+ /*
+ * Set the pointers
+ */
+ NumSamples = pBuffer->SamplesToOutput;
+ pStart = pBuffer->pScratch;
+
+
+ /*
+ * check if it is the first call of a block
+ */
+ if ((pBuffer->BufferState == LVM_FIRSTCALL) ||
+ (pBuffer->BufferState == LVM_FIRSTLASTCALL))
+ {
+ /* First call for a new block */
+ pInstance->pOutputSamples = pOutData; /* Initialise the destination */
+ }
+ pDest = pInstance->pOutputSamples; /* Set the output address */
+
+
+ /*
+ * If the number of samples is non-zero then there are still samples to send to
+ * the output buffer
+ */
+ if ((NumSamples != 0) &&
+ (pBuffer->OutDelaySamples != 0))
+ {
+ /*
+ * Copy the delayed output buffer samples to the output
+ */
+ if (pBuffer->OutDelaySamples <= NumSamples)
+ {
+ /*
+ * Copy all output delay samples to the output
+ */
+ Copy_Float(&pBuffer->OutDelayBuffer[0], /* Source */
+ pDest, /* Detsination */
+ (LVM_INT16)(2 * pBuffer->OutDelaySamples)); /* Number of delay samples */
+
+ /*
+ * Update the pointer and sample counts
+ */
+ pDest += 2 * pBuffer->OutDelaySamples; /* Output sample pointer */
+ NumSamples = (LVM_INT16)(NumSamples - pBuffer->OutDelaySamples); /* Samples left \
+ to send */
+ pBuffer->OutDelaySamples = 0; /* No samples left in the buffer */
+ }
+ else
+ {
+ /*
+ * Copy only some of the ouput delay samples to the output
+ */
+ Copy_Float(&pBuffer->OutDelayBuffer[0], /* Source */
+ pDest, /* Detsination */
+ (LVM_INT16)(2 * NumSamples)); /* Number of delay samples */
+
+ /*
+ * Update the pointer and sample counts
+ */
+ pDest += 2 * NumSamples; /* Output sample pointer */
+ /* No samples left in the buffer */
+ pBuffer->OutDelaySamples = (LVM_INT16)(pBuffer->OutDelaySamples - NumSamples);
+
+ /*
+ * Realign the delay buffer data to avoid using circular buffer management
+ */
+ Copy_Float(&pBuffer->OutDelayBuffer[2 * NumSamples], /* Source */
+ &pBuffer->OutDelayBuffer[0], /* Destination */
+ (LVM_INT16)(2 * pBuffer->OutDelaySamples)); /* Number of samples to move */
+ NumSamples = 0; /* Samples left to send */
+ }
+ }
+
+
+ /*
+ * Copy the processed results to the output
+ */
+ if ((NumSamples != 0) &&
+ (SampleCount != 0))
+ {
+ if (SampleCount <= NumSamples)
+ {
+ /*
+ * Copy all processed samples to the output
+ */
+ Copy_Float(pStart, /* Source */
+ pDest, /* Detsination */
+ (LVM_INT16)(2 * SampleCount)); /* Number of processed samples */
+ /*
+ * Update the pointer and sample counts
+ */
+ pDest += 2 * SampleCount; /* Output sample pointer */
+ NumSamples = (LVM_INT16)(NumSamples - SampleCount); /* Samples left to send */
+ SampleCount = 0; /* No samples left in the buffer */
+ }
+ else
+ {
+ /*
+ * Copy only some processed samples to the output
+ */
+ Copy_Float(pStart, /* Source */
+ pDest, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Number of processed samples */
+ /*
+ * Update the pointers and sample counts
+ */
+ pStart += 2 * NumSamples; /* Processed sample pointer */
+ pDest += 2 * NumSamples; /* Output sample pointer */
+ SampleCount = (LVM_INT16)(SampleCount - NumSamples); /* Processed samples left */
+ NumSamples = 0; /* Clear the sample count */
+ }
+ }
+
+
+ /*
+ * Copy the remaining processed data to the output delay buffer
+ */
+ if (SampleCount != 0)
+ {
+ Copy_Float(pStart, /* Source */
+ &pBuffer->OutDelayBuffer[2 * pBuffer->OutDelaySamples], /* Destination */
+ (LVM_INT16)(2 * SampleCount)); /* Number of processed samples */
+ /* Update the buffer count */
+ pBuffer->OutDelaySamples = (LVM_INT16)(pBuffer->OutDelaySamples + SampleCount);
+ }
+
+ /*
+ * pointers, counts and set default buffer processing
+ */
+ pBuffer->SamplesToOutput = NumSamples; /* Samples left to send */
+ pInstance->pOutputSamples = pDest; /* Output sample pointer */
+ pBuffer->BufferState = LVM_MAXBLOCKCALL; /* Set for the default call \
+ block size */
+ /* This will terminate the loop when all samples processed */
+ *pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess;
+}
+#else
void LVM_BufferManagedOut(LVM_Handle_t hInstance,
LVM_INT16 *pOutData,
LVM_UINT16 *pNumSamples)
@@ -672,7 +1037,7 @@
pBuffer->BufferState = LVM_MAXBLOCKCALL; /* Set for the default call block size */
*pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess; /* This will terminate the loop when all samples processed */
}
-
+#endif
/****************************************************************************************/
/* */
@@ -741,6 +1106,7 @@
/* */
/****************************************************************************************/
+#ifndef BUILD_FLOAT
void LVM_BufferOptimisedOut(LVM_Handle_t hInstance,
LVM_UINT16 *pNumSamples)
{
@@ -805,7 +1171,7 @@
}
}
}
-
+#endif
/****************************************************************************************/
/* */
@@ -843,7 +1209,31 @@
/* NOTES: */
/* */
/****************************************************************************************/
+#ifdef BUILD_FLOAT
+void LVM_BufferOut(LVM_Handle_t hInstance,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 *pNumSamples)
+{
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+
+
+ /*
+ * Check which mode, managed or unmanaged
+ */
+ if (pInstance->InstParams.BufferMode == LVM_MANAGED_BUFFERS)
+ {
+ LVM_BufferManagedOut(hInstance,
+ pOutData,
+ pNumSamples);
+ }
+ else
+ {
+ LVM_BufferUnmanagedOut(hInstance,
+ pNumSamples);
+ }
+}
+#else
void LVM_BufferOut(LVM_Handle_t hInstance,
LVM_INT16 *pOutData,
LVM_UINT16 *pNumSamples)
@@ -867,4 +1257,4 @@
pNumSamples);
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Coeffs.h b/media/libeffects/lvm/lib/Bundle/src/LVM_Coeffs.h
index 2712b2c..353560c 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Coeffs.h
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Coeffs.h
@@ -26,10 +26,655 @@
/************************************************************************************/
#define TrebleBoostCorner 8000
-#define TrebleBoostMinRate 4
-#define TrebleBoostSteps 15
+#define TrebleBoostMinRate 4
+#define TrebleBoostSteps 15
+#ifdef BUILD_FLOAT
+/* Coefficients for sample rate 22050Hz */
+ /* Gain = 1.000000 dB */
+#define HPF_Fs22050_Gain1_A0 1.038434
+#define HPF_Fs22050_Gain1_A1 0.331599
+#define HPF_Fs22050_Gain1_A2 0.000000
+#define HPF_Fs22050_Gain1_B1 0.370033
+#define HPF_Fs22050_Gain1_B2 0.000000
+ /* Gain = 2.000000 dB */
+#define HPF_Fs22050_Gain2_A0 1.081557
+#define HPF_Fs22050_Gain2_A1 0.288475
+#define HPF_Fs22050_Gain2_A2 0.000000
+#define HPF_Fs22050_Gain2_B1 0.370033
+#define HPF_Fs22050_Gain2_B2 0.000000
+ /* Gain = 3.000000 dB */
+#define HPF_Fs22050_Gain3_A0 1.129943
+#define HPF_Fs22050_Gain3_A1 0.240090
+#define HPF_Fs22050_Gain3_A2 0.000000
+#define HPF_Fs22050_Gain3_B1 0.370033
+#define HPF_Fs22050_Gain3_B2 0.000000
+ /* Gain = 4.000000 dB */
+#define HPF_Fs22050_Gain4_A0 1.184232
+#define HPF_Fs22050_Gain4_A1 0.185801
+#define HPF_Fs22050_Gain4_A2 0.000000
+#define HPF_Fs22050_Gain4_B1 0.370033
+#define HPF_Fs22050_Gain4_B2 0.000000
+ /* Gain = 5.000000 dB */
+#define HPF_Fs22050_Gain5_A0 1.245145
+#define HPF_Fs22050_Gain5_A1 0.124887
+#define HPF_Fs22050_Gain5_A2 0.000000
+#define HPF_Fs22050_Gain5_B1 0.370033
+#define HPF_Fs22050_Gain5_B2 0.000000
+ /* Gain = 6.000000 dB */
+#define HPF_Fs22050_Gain6_A0 1.313491
+#define HPF_Fs22050_Gain6_A1 0.056541
+#define HPF_Fs22050_Gain6_A2 0.000000
+#define HPF_Fs22050_Gain6_B1 0.370033
+#define HPF_Fs22050_Gain6_B2 0.000000
+ /* Gain = 7.000000 dB */
+#define HPF_Fs22050_Gain7_A0 1.390177
+#define HPF_Fs22050_Gain7_A1 -0.020144
+#define HPF_Fs22050_Gain7_A2 0.000000
+#define HPF_Fs22050_Gain7_B1 0.370033
+#define HPF_Fs22050_Gain7_B2 0.000000
+ /* Gain = 8.000000 dB */
+#define HPF_Fs22050_Gain8_A0 1.476219
+#define HPF_Fs22050_Gain8_A1 -0.106187
+#define HPF_Fs22050_Gain8_A2 0.000000
+#define HPF_Fs22050_Gain8_B1 0.370033
+#define HPF_Fs22050_Gain8_B2 0.000000
+ /* Gain = 9.000000 dB */
+#define HPF_Fs22050_Gain9_A0 1.572761
+#define HPF_Fs22050_Gain9_A1 -0.202728
+#define HPF_Fs22050_Gain9_A2 0.000000
+#define HPF_Fs22050_Gain9_B1 0.370033
+#define HPF_Fs22050_Gain9_B2 0.000000
+ /* Gain = 10.000000 dB */
+#define HPF_Fs22050_Gain10_A0 1.681082
+#define HPF_Fs22050_Gain10_A1 -0.311049
+#define HPF_Fs22050_Gain10_A2 0.000000
+#define HPF_Fs22050_Gain10_B1 0.370033
+#define HPF_Fs22050_Gain10_B2 0.000000
+ /* Gain = 11.000000 dB */
+#define HPF_Fs22050_Gain11_A0 1.802620
+#define HPF_Fs22050_Gain11_A1 -0.432588
+#define HPF_Fs22050_Gain11_A2 0.000000
+#define HPF_Fs22050_Gain11_B1 0.370033
+#define HPF_Fs22050_Gain11_B2 0.000000
+ /* Gain = 12.000000 dB */
+#define HPF_Fs22050_Gain12_A0 1.938989
+#define HPF_Fs22050_Gain12_A1 -0.568956
+#define HPF_Fs22050_Gain12_A2 0.000000
+#define HPF_Fs22050_Gain12_B1 0.370033
+#define HPF_Fs22050_Gain12_B2 0.000000
+ /* Gain = 13.000000 dB */
+#define HPF_Fs22050_Gain13_A0 2.091997
+#define HPF_Fs22050_Gain13_A1 -0.721964
+#define HPF_Fs22050_Gain13_A2 0.000000
+#define HPF_Fs22050_Gain13_B1 0.370033
+#define HPF_Fs22050_Gain13_B2 0.000000
+ /* Gain = 14.000000 dB */
+#define HPF_Fs22050_Gain14_A0 2.263674
+#define HPF_Fs22050_Gain14_A1 -0.893641
+#define HPF_Fs22050_Gain14_A2 0.000000
+#define HPF_Fs22050_Gain14_B1 0.370033
+#define HPF_Fs22050_Gain14_B2 0.000000
+ /* Gain = 15.000000 dB */
+#define HPF_Fs22050_Gain15_A0 2.456300
+#define HPF_Fs22050_Gain15_A1 -1.086267
+#define HPF_Fs22050_Gain15_A2 0.000000
+#define HPF_Fs22050_Gain15_B1 0.370033
+#define HPF_Fs22050_Gain15_B2 0.000000
+/* Coefficients for sample rate 24000Hz */
+ /* Gain = 1.000000 dB */
+#define HPF_Fs24000_Gain1_A0 1.044662
+#define HPF_Fs24000_Gain1_A1 0.223287
+#define HPF_Fs24000_Gain1_A2 0.000000
+#define HPF_Fs24000_Gain1_B1 0.267949
+#define HPF_Fs24000_Gain1_B2 0.000000
+ /* Gain = 2.000000 dB */
+#define HPF_Fs24000_Gain2_A0 1.094773
+#define HPF_Fs24000_Gain2_A1 0.173176
+#define HPF_Fs24000_Gain2_A2 0.000000
+#define HPF_Fs24000_Gain2_B1 0.267949
+#define HPF_Fs24000_Gain2_B2 0.000000
+ /* Gain = 3.000000 dB */
+#define HPF_Fs24000_Gain3_A0 1.150999
+#define HPF_Fs24000_Gain3_A1 0.116950
+#define HPF_Fs24000_Gain3_A2 0.000000
+#define HPF_Fs24000_Gain3_B1 0.267949
+#define HPF_Fs24000_Gain3_B2 0.000000
+ /* Gain = 4.000000 dB */
+#define HPF_Fs24000_Gain4_A0 1.214086
+#define HPF_Fs24000_Gain4_A1 0.053863
+#define HPF_Fs24000_Gain4_A2 0.000000
+#define HPF_Fs24000_Gain4_B1 0.267949
+#define HPF_Fs24000_Gain4_B2 0.000000
+ /* Gain = 5.000000 dB */
+#define HPF_Fs24000_Gain5_A0 1.284870
+#define HPF_Fs24000_Gain5_A1 -0.016921
+#define HPF_Fs24000_Gain5_A2 0.000000
+#define HPF_Fs24000_Gain5_B1 0.267949
+#define HPF_Fs24000_Gain5_B2 0.000000
+ /* Gain = 6.000000 dB */
+#define HPF_Fs24000_Gain6_A0 1.364291
+#define HPF_Fs24000_Gain6_A1 -0.096342
+#define HPF_Fs24000_Gain6_A2 0.000000
+#define HPF_Fs24000_Gain6_B1 0.267949
+#define HPF_Fs24000_Gain6_B2 0.000000
+ /* Gain = 7.000000 dB */
+#define HPF_Fs24000_Gain7_A0 1.453403
+#define HPF_Fs24000_Gain7_A1 -0.185454
+#define HPF_Fs24000_Gain7_A2 0.000000
+#define HPF_Fs24000_Gain7_B1 0.267949
+#define HPF_Fs24000_Gain7_B2 0.000000
+ /* Gain = 8.000000 dB */
+#define HPF_Fs24000_Gain8_A0 1.553389
+#define HPF_Fs24000_Gain8_A1 -0.285440
+#define HPF_Fs24000_Gain8_A2 0.000000
+#define HPF_Fs24000_Gain8_B1 0.267949
+#define HPF_Fs24000_Gain8_B2 0.000000
+ /* Gain = 9.000000 dB */
+#define HPF_Fs24000_Gain9_A0 1.665574
+#define HPF_Fs24000_Gain9_A1 -0.397625
+#define HPF_Fs24000_Gain9_A2 0.000000
+#define HPF_Fs24000_Gain9_B1 0.267949
+#define HPF_Fs24000_Gain9_B2 0.000000
+ /* Gain = 10.000000 dB */
+#define HPF_Fs24000_Gain10_A0 1.791449
+#define HPF_Fs24000_Gain10_A1 -0.523499
+#define HPF_Fs24000_Gain10_A2 0.000000
+#define HPF_Fs24000_Gain10_B1 0.267949
+#define HPF_Fs24000_Gain10_B2 0.000000
+ /* Gain = 11.000000 dB */
+#define HPF_Fs24000_Gain11_A0 1.932682
+#define HPF_Fs24000_Gain11_A1 -0.664733
+#define HPF_Fs24000_Gain11_A2 0.000000
+#define HPF_Fs24000_Gain11_B1 0.267949
+#define HPF_Fs24000_Gain11_B2 0.000000
+ /* Gain = 12.000000 dB */
+#define HPF_Fs24000_Gain12_A0 2.091148
+#define HPF_Fs24000_Gain12_A1 -0.823199
+#define HPF_Fs24000_Gain12_A2 0.000000
+#define HPF_Fs24000_Gain12_B1 0.267949
+#define HPF_Fs24000_Gain12_B2 0.000000
+ /* Gain = 13.000000 dB */
+#define HPF_Fs24000_Gain13_A0 2.268950
+#define HPF_Fs24000_Gain13_A1 -1.001001
+#define HPF_Fs24000_Gain13_A2 0.000000
+#define HPF_Fs24000_Gain13_B1 0.267949
+#define HPF_Fs24000_Gain13_B2 0.000000
+ /* Gain = 14.000000 dB */
+#define HPF_Fs24000_Gain14_A0 2.468447
+#define HPF_Fs24000_Gain14_A1 -1.200498
+#define HPF_Fs24000_Gain14_A2 0.000000
+#define HPF_Fs24000_Gain14_B1 0.267949
+#define HPF_Fs24000_Gain14_B2 0.000000
+ /* Gain = 15.000000 dB */
+#define HPF_Fs24000_Gain15_A0 2.692287
+#define HPF_Fs24000_Gain15_A1 -1.424338
+#define HPF_Fs24000_Gain15_A2 0.000000
+#define HPF_Fs24000_Gain15_B1 0.267949
+#define HPF_Fs24000_Gain15_B2 0.000000
+/* Coefficients for sample rate 32000Hz */
+ /* Gain = 1.000000 dB */
+#define HPF_Fs32000_Gain1_A0 1.061009
+#define HPF_Fs32000_Gain1_A1 -0.061009
+#define HPF_Fs32000_Gain1_A2 0.000000
+#define HPF_Fs32000_Gain1_B1 -0.000000
+#define HPF_Fs32000_Gain1_B2 0.000000
+ /* Gain = 2.000000 dB */
+#define HPF_Fs32000_Gain2_A0 1.129463
+#define HPF_Fs32000_Gain2_A1 -0.129463
+#define HPF_Fs32000_Gain2_A2 0.000000
+#define HPF_Fs32000_Gain2_B1 -0.000000
+#define HPF_Fs32000_Gain2_B2 0.000000
+ /* Gain = 3.000000 dB */
+#define HPF_Fs32000_Gain3_A0 1.206267
+#define HPF_Fs32000_Gain3_A1 -0.206267
+#define HPF_Fs32000_Gain3_A2 0.000000
+#define HPF_Fs32000_Gain3_B1 -0.000000
+#define HPF_Fs32000_Gain3_B2 0.000000
+ /* Gain = 4.000000 dB */
+#define HPF_Fs32000_Gain4_A0 1.292447
+#define HPF_Fs32000_Gain4_A1 -0.292447
+#define HPF_Fs32000_Gain4_A2 0.000000
+#define HPF_Fs32000_Gain4_B1 -0.000000
+#define HPF_Fs32000_Gain4_B2 0.000000
+ /* Gain = 5.000000 dB */
+#define HPF_Fs32000_Gain5_A0 1.389140
+#define HPF_Fs32000_Gain5_A1 -0.389140
+#define HPF_Fs32000_Gain5_A2 0.000000
+#define HPF_Fs32000_Gain5_B1 -0.000000
+#define HPF_Fs32000_Gain5_B2 0.000000
+ /* Gain = 6.000000 dB */
+#define HPF_Fs32000_Gain6_A0 1.497631
+#define HPF_Fs32000_Gain6_A1 -0.497631
+#define HPF_Fs32000_Gain6_A2 0.000000
+#define HPF_Fs32000_Gain6_B1 -0.000000
+#define HPF_Fs32000_Gain6_B2 0.000000
+ /* Gain = 7.000000 dB */
+#define HPF_Fs32000_Gain7_A0 1.619361
+#define HPF_Fs32000_Gain7_A1 -0.619361
+#define HPF_Fs32000_Gain7_A2 0.000000
+#define HPF_Fs32000_Gain7_B1 -0.000000
+#define HPF_Fs32000_Gain7_B2 0.000000
+ /* Gain = 8.000000 dB */
+#define HPF_Fs32000_Gain8_A0 1.755943
+#define HPF_Fs32000_Gain8_A1 -0.755943
+#define HPF_Fs32000_Gain8_A2 0.000000
+#define HPF_Fs32000_Gain8_B1 -0.000000
+#define HPF_Fs32000_Gain8_B2 0.000000
+ /* Gain = 9.000000 dB */
+#define HPF_Fs32000_Gain9_A0 1.909191
+#define HPF_Fs32000_Gain9_A1 -0.909191
+#define HPF_Fs32000_Gain9_A2 0.000000
+#define HPF_Fs32000_Gain9_B1 -0.000000
+#define HPF_Fs32000_Gain9_B2 0.000000
+ /* Gain = 10.000000 dB */
+#define HPF_Fs32000_Gain10_A0 2.081139
+#define HPF_Fs32000_Gain10_A1 -1.081139
+#define HPF_Fs32000_Gain10_A2 0.000000
+#define HPF_Fs32000_Gain10_B1 -0.000000
+#define HPF_Fs32000_Gain10_B2 0.000000
+ /* Gain = 11.000000 dB */
+#define HPF_Fs32000_Gain11_A0 2.274067
+#define HPF_Fs32000_Gain11_A1 -1.274067
+#define HPF_Fs32000_Gain11_A2 0.000000
+#define HPF_Fs32000_Gain11_B1 -0.000000
+#define HPF_Fs32000_Gain11_B2 0.000000
+ /* Gain = 12.000000 dB */
+#define HPF_Fs32000_Gain12_A0 2.490536
+#define HPF_Fs32000_Gain12_A1 -1.490536
+#define HPF_Fs32000_Gain12_A2 0.000000
+#define HPF_Fs32000_Gain12_B1 -0.000000
+#define HPF_Fs32000_Gain12_B2 0.000000
+ /* Gain = 13.000000 dB */
+#define HPF_Fs32000_Gain13_A0 2.733418
+#define HPF_Fs32000_Gain13_A1 -1.733418
+#define HPF_Fs32000_Gain13_A2 0.000000
+#define HPF_Fs32000_Gain13_B1 -0.000000
+#define HPF_Fs32000_Gain13_B2 0.000000
+ /* Gain = 14.000000 dB */
+#define HPF_Fs32000_Gain14_A0 3.005936
+#define HPF_Fs32000_Gain14_A1 -2.005936
+#define HPF_Fs32000_Gain14_A2 0.000000
+#define HPF_Fs32000_Gain14_B1 -0.000000
+#define HPF_Fs32000_Gain14_B2 0.000000
+ /* Gain = 15.000000 dB */
+#define HPF_Fs32000_Gain15_A0 3.311707
+#define HPF_Fs32000_Gain15_A1 -2.311707
+#define HPF_Fs32000_Gain15_A2 0.000000
+#define HPF_Fs32000_Gain15_B1 -0.000000
+#define HPF_Fs32000_Gain15_B2 0.000000
+/* Coefficients for sample rate 44100Hz */
+ /* Gain = 1.000000 dB */
+#define HPF_Fs44100_Gain1_A0 1.074364
+#define HPF_Fs44100_Gain1_A1 -0.293257
+#define HPF_Fs44100_Gain1_A2 0.000000
+#define HPF_Fs44100_Gain1_B1 -0.218894
+#define HPF_Fs44100_Gain1_B2 0.000000
+ /* Gain = 2.000000 dB */
+#define HPF_Fs44100_Gain2_A0 1.157801
+#define HPF_Fs44100_Gain2_A1 -0.376695
+#define HPF_Fs44100_Gain2_A2 0.000000
+#define HPF_Fs44100_Gain2_B1 -0.218894
+#define HPF_Fs44100_Gain2_B2 0.000000
+ /* Gain = 3.000000 dB */
+#define HPF_Fs44100_Gain3_A0 1.251420
+#define HPF_Fs44100_Gain3_A1 -0.470313
+#define HPF_Fs44100_Gain3_A2 0.000000
+#define HPF_Fs44100_Gain3_B1 -0.218894
+#define HPF_Fs44100_Gain3_B2 0.000000
+ /* Gain = 4.000000 dB */
+#define HPF_Fs44100_Gain4_A0 1.356461
+#define HPF_Fs44100_Gain4_A1 -0.575355
+#define HPF_Fs44100_Gain4_A2 0.000000
+#define HPF_Fs44100_Gain4_B1 -0.218894
+#define HPF_Fs44100_Gain4_B2 0.000000
+ /* Gain = 5.000000 dB */
+#define HPF_Fs44100_Gain5_A0 1.474320
+#define HPF_Fs44100_Gain5_A1 -0.693213
+#define HPF_Fs44100_Gain5_A2 0.000000
+#define HPF_Fs44100_Gain5_B1 -0.218894
+#define HPF_Fs44100_Gain5_B2 0.000000
+ /* Gain = 6.000000 dB */
+#define HPF_Fs44100_Gain6_A0 1.606559
+#define HPF_Fs44100_Gain6_A1 -0.825453
+#define HPF_Fs44100_Gain6_A2 0.000000
+#define HPF_Fs44100_Gain6_B1 -0.218894
+#define HPF_Fs44100_Gain6_B2 0.000000
+ /* Gain = 7.000000 dB */
+#define HPF_Fs44100_Gain7_A0 1.754935
+#define HPF_Fs44100_Gain7_A1 -0.973828
+#define HPF_Fs44100_Gain7_A2 0.000000
+#define HPF_Fs44100_Gain7_B1 -0.218894
+#define HPF_Fs44100_Gain7_B2 0.000000
+ /* Gain = 8.000000 dB */
+#define HPF_Fs44100_Gain8_A0 1.921414
+#define HPF_Fs44100_Gain8_A1 -1.140308
+#define HPF_Fs44100_Gain8_A2 0.000000
+#define HPF_Fs44100_Gain8_B1 -0.218894
+#define HPF_Fs44100_Gain8_B2 0.000000
+ /* Gain = 9.000000 dB */
+#define HPF_Fs44100_Gain9_A0 2.108208
+#define HPF_Fs44100_Gain9_A1 -1.327101
+#define HPF_Fs44100_Gain9_A2 0.000000
+#define HPF_Fs44100_Gain9_B1 -0.218894
+#define HPF_Fs44100_Gain9_B2 0.000000
+ /* Gain = 10.000000 dB */
+#define HPF_Fs44100_Gain10_A0 2.317793
+#define HPF_Fs44100_Gain10_A1 -1.536687
+#define HPF_Fs44100_Gain10_A2 0.000000
+#define HPF_Fs44100_Gain10_B1 -0.218894
+#define HPF_Fs44100_Gain10_B2 0.000000
+ /* Gain = 11.000000 dB */
+#define HPF_Fs44100_Gain11_A0 2.552952
+#define HPF_Fs44100_Gain11_A1 -1.771846
+#define HPF_Fs44100_Gain11_A2 0.000000
+#define HPF_Fs44100_Gain11_B1 -0.218894
+#define HPF_Fs44100_Gain11_B2 0.000000
+ /* Gain = 12.000000 dB */
+#define HPF_Fs44100_Gain12_A0 2.816805
+#define HPF_Fs44100_Gain12_A1 -2.035698
+#define HPF_Fs44100_Gain12_A2 0.000000
+#define HPF_Fs44100_Gain12_B1 -0.218894
+#define HPF_Fs44100_Gain12_B2 0.000000
+ /* Gain = 13.000000 dB */
+#define HPF_Fs44100_Gain13_A0 3.112852
+#define HPF_Fs44100_Gain13_A1 -2.331746
+#define HPF_Fs44100_Gain13_A2 0.000000
+#define HPF_Fs44100_Gain13_B1 -0.218894
+#define HPF_Fs44100_Gain13_B2 0.000000
+ /* Gain = 14.000000 dB */
+#define HPF_Fs44100_Gain14_A0 3.445023
+#define HPF_Fs44100_Gain14_A1 -2.663916
+#define HPF_Fs44100_Gain14_A2 0.000000
+#define HPF_Fs44100_Gain14_B1 -0.218894
+#define HPF_Fs44100_Gain14_B2 0.000000
+ /* Gain = 15.000000 dB */
+#define HPF_Fs44100_Gain15_A0 3.817724
+#define HPF_Fs44100_Gain15_A1 -3.036618
+#define HPF_Fs44100_Gain15_A2 0.000000
+#define HPF_Fs44100_Gain15_B1 -0.218894
+#define HPF_Fs44100_Gain15_B2 0.000000
+/* Coefficients for sample rate 48000Hz */
+ /* Gain = 1.000000 dB */
+#define HPF_Fs48000_Gain1_A0 1.077357
+#define HPF_Fs48000_Gain1_A1 -0.345306
+#define HPF_Fs48000_Gain1_A2 0.000000
+#define HPF_Fs48000_Gain1_B1 -0.267949
+#define HPF_Fs48000_Gain1_B2 0.000000
+ /* Gain = 2.000000 dB */
+#define HPF_Fs48000_Gain2_A0 1.164152
+#define HPF_Fs48000_Gain2_A1 -0.432101
+#define HPF_Fs48000_Gain2_A2 0.000000
+#define HPF_Fs48000_Gain2_B1 -0.267949
+#define HPF_Fs48000_Gain2_B2 0.000000
+ /* Gain = 3.000000 dB */
+#define HPF_Fs48000_Gain3_A0 1.261538
+#define HPF_Fs48000_Gain3_A1 -0.529488
+#define HPF_Fs48000_Gain3_A2 0.000000
+#define HPF_Fs48000_Gain3_B1 -0.267949
+#define HPF_Fs48000_Gain3_B2 0.000000
+ /* Gain = 4.000000 dB */
+#define HPF_Fs48000_Gain4_A0 1.370807
+#define HPF_Fs48000_Gain4_A1 -0.638757
+#define HPF_Fs48000_Gain4_A2 0.000000
+#define HPF_Fs48000_Gain4_B1 -0.267949
+#define HPF_Fs48000_Gain4_B2 0.000000
+ /* Gain = 5.000000 dB */
+#define HPF_Fs48000_Gain5_A0 1.493409
+#define HPF_Fs48000_Gain5_A1 -0.761359
+#define HPF_Fs48000_Gain5_A2 0.000000
+#define HPF_Fs48000_Gain5_B1 -0.267949
+#define HPF_Fs48000_Gain5_B2 0.000000
+ /* Gain = 6.000000 dB */
+#define HPF_Fs48000_Gain6_A0 1.630971
+#define HPF_Fs48000_Gain6_A1 -0.898920
+#define HPF_Fs48000_Gain6_A2 0.000000
+#define HPF_Fs48000_Gain6_B1 -0.267949
+#define HPF_Fs48000_Gain6_B2 0.000000
+ /* Gain = 7.000000 dB */
+#define HPF_Fs48000_Gain7_A0 1.785318
+#define HPF_Fs48000_Gain7_A1 -1.053267
+#define HPF_Fs48000_Gain7_A2 0.000000
+#define HPF_Fs48000_Gain7_B1 -0.267949
+#define HPF_Fs48000_Gain7_B2 0.000000
+ /* Gain = 8.000000 dB */
+#define HPF_Fs48000_Gain8_A0 1.958498
+#define HPF_Fs48000_Gain8_A1 -1.226447
+#define HPF_Fs48000_Gain8_A2 0.000000
+#define HPF_Fs48000_Gain8_B1 -0.267949
+#define HPF_Fs48000_Gain8_B2 0.000000
+ /* Gain = 9.000000 dB */
+#define HPF_Fs48000_Gain9_A0 2.152809
+#define HPF_Fs48000_Gain9_A1 -1.420758
+#define HPF_Fs48000_Gain9_A2 0.000000
+#define HPF_Fs48000_Gain9_B1 -0.267949
+#define HPF_Fs48000_Gain9_B2 0.000000
+ /* Gain = 10.000000 dB */
+#define HPF_Fs48000_Gain10_A0 2.370829
+#define HPF_Fs48000_Gain10_A1 -1.638778
+#define HPF_Fs48000_Gain10_A2 0.000000
+#define HPF_Fs48000_Gain10_B1 -0.267949
+#define HPF_Fs48000_Gain10_B2 0.000000
+ /* Gain = 11.000000 dB */
+#define HPF_Fs48000_Gain11_A0 2.615452
+#define HPF_Fs48000_Gain11_A1 -1.883401
+#define HPF_Fs48000_Gain11_A2 0.000000
+#define HPF_Fs48000_Gain11_B1 -0.267949
+#define HPF_Fs48000_Gain11_B2 0.000000
+ /* Gain = 12.000000 dB */
+#define HPF_Fs48000_Gain12_A0 2.889924
+#define HPF_Fs48000_Gain12_A1 -2.157873
+#define HPF_Fs48000_Gain12_A2 0.000000
+#define HPF_Fs48000_Gain12_B1 -0.267949
+#define HPF_Fs48000_Gain12_B2 0.000000
+ /* Gain = 13.000000 dB */
+#define HPF_Fs48000_Gain13_A0 3.197886
+#define HPF_Fs48000_Gain13_A1 -2.465835
+#define HPF_Fs48000_Gain13_A2 0.000000
+#define HPF_Fs48000_Gain13_B1 -0.267949
+#define HPF_Fs48000_Gain13_B2 0.000000
+ /* Gain = 14.000000 dB */
+#define HPF_Fs48000_Gain14_A0 3.543425
+#define HPF_Fs48000_Gain14_A1 -2.811374
+#define HPF_Fs48000_Gain14_A2 0.000000
+#define HPF_Fs48000_Gain14_B1 -0.267949
+#define HPF_Fs48000_Gain14_B2 0.000000
+ /* Gain = 15.000000 dB */
+#define HPF_Fs48000_Gain15_A0 3.931127
+#define HPF_Fs48000_Gain15_A1 -3.199076
+#define HPF_Fs48000_Gain15_A2 0.000000
+#define HPF_Fs48000_Gain15_B1 -0.267949
+#define HPF_Fs48000_Gain15_B2 0.000000
+#ifdef HIGHER_FS
+
+/* Coefficients for sample rate 96000Hz */
+ /* Gain = 1.000000 dB */
+#define HPF_Fs96000_Gain1_A0 1.096233
+#define HPF_Fs96000_Gain1_A1 -0.673583
+#define HPF_Fs96000_Gain1_A2 0.000000
+#define HPF_Fs96000_Gain1_B1 -0.577350
+#define HPF_Fs96000_Gain1_B2 0.000000
+ /* Gain = 2.000000 dB */
+#define HPF_Fs96000_Gain2_A0 1.204208
+#define HPF_Fs96000_Gain2_A1 -0.781558
+#define HPF_Fs96000_Gain2_A2 0.000000
+#define HPF_Fs96000_Gain2_B1 -0.577350
+#define HPF_Fs96000_Gain2_B2 0.000000
+ /* Gain = 3.000000 dB */
+#define HPF_Fs96000_Gain3_A0 1.325358
+#define HPF_Fs96000_Gain3_A1 -0.902708
+#define HPF_Fs96000_Gain3_A2 0.000000
+#define HPF_Fs96000_Gain3_B1 -0.577350
+#define HPF_Fs96000_Gain3_B2 0.000000
+ /* Gain = 4.000000 dB */
+#define HPF_Fs96000_Gain4_A0 1.461291
+#define HPF_Fs96000_Gain4_A1 -1.038641
+#define HPF_Fs96000_Gain4_A2 0.000000
+#define HPF_Fs96000_Gain4_B1 -0.577350
+#define HPF_Fs96000_Gain4_B2 0.000000
+ /* Gain = 5.000000 dB */
+#define HPF_Fs96000_Gain5_A0 1.613810
+#define HPF_Fs96000_Gain5_A1 -1.191160
+#define HPF_Fs96000_Gain5_A2 0.000000
+#define HPF_Fs96000_Gain5_B1 -0.577350
+#define HPF_Fs96000_Gain5_B2 0.000000
+ /* Gain = 6.000000 dB */
+#define HPF_Fs96000_Gain6_A0 1.784939
+#define HPF_Fs96000_Gain6_A1 -1.362289
+#define HPF_Fs96000_Gain6_A2 0.000000
+#define HPF_Fs96000_Gain6_B1 -0.577350
+#define HPF_Fs96000_Gain6_B2 0.000000
+ /* Gain = 7.000000 dB */
+#define HPF_Fs96000_Gain7_A0 1.976949
+#define HPF_Fs96000_Gain7_A1 -1.554299
+#define HPF_Fs96000_Gain7_A2 0.000000
+#define HPF_Fs96000_Gain7_B1 -0.577350
+#define HPF_Fs96000_Gain7_B2 0.000000
+ /* Gain = 8.000000 dB */
+#define HPF_Fs96000_Gain8_A0 2.192387
+#define HPF_Fs96000_Gain8_A1 -1.769738
+#define HPF_Fs96000_Gain8_A2 0.000000
+#define HPF_Fs96000_Gain8_B1 -0.577350
+#define HPF_Fs96000_Gain8_B2 0.000000
+ /* Gain = 9.000000 dB */
+#define HPF_Fs96000_Gain9_A0 2.434113
+#define HPF_Fs96000_Gain9_A1 -2.011464
+#define HPF_Fs96000_Gain9_A2 0.000000
+#define HPF_Fs96000_Gain9_B1 -0.577350
+#define HPF_Fs96000_Gain9_B2 0.000000
+ /* Gain = 10.000000 dB */
+#define HPF_Fs96000_Gain10_A0 2.705335
+#define HPF_Fs96000_Gain10_A1 -2.282685
+#define HPF_Fs96000_Gain10_A2 0.000000
+#define HPF_Fs96000_Gain10_B1 -0.577350
+#define HPF_Fs96000_Gain10_B2 0.000000
+ /* Gain = 11.000000 dB */
+#define HPF_Fs96000_Gain11_A0 3.009650
+#define HPF_Fs96000_Gain11_A1 -2.587000
+#define HPF_Fs96000_Gain11_A2 0.000000
+#define HPF_Fs96000_Gain11_B1 -0.577350
+#define HPF_Fs96000_Gain11_B2 0.000000
+ /* Gain = 12.000000 dB */
+#define HPF_Fs96000_Gain12_A0 3.351097
+#define HPF_Fs96000_Gain12_A1 -2.928447
+#define HPF_Fs96000_Gain12_A2 0.000000
+#define HPF_Fs96000_Gain12_B1 -0.577350
+#define HPF_Fs96000_Gain12_B2 0.000000
+ /* Gain = 13.000000 dB */
+#define HPF_Fs96000_Gain13_A0 3.734207
+#define HPF_Fs96000_Gain13_A1 -3.311558
+#define HPF_Fs96000_Gain13_A2 0.000000
+#define HPF_Fs96000_Gain13_B1 -0.577350
+#define HPF_Fs96000_Gain13_B2 0.000000
+ /* Gain = 14.000000 dB */
+#define HPF_Fs96000_Gain14_A0 4.164064
+#define HPF_Fs96000_Gain14_A1 -3.741414
+#define HPF_Fs96000_Gain14_A2 0.000000
+#define HPF_Fs96000_Gain14_B1 -0.577350
+#define HPF_Fs96000_Gain14_B2 0.000000
+ /* Gain = 15.000000 dB */
+#define HPF_Fs96000_Gain15_A0 4.646371
+#define HPF_Fs96000_Gain15_A1 -4.223721
+#define HPF_Fs96000_Gain15_A2 0.000000
+#define HPF_Fs96000_Gain15_B1 -0.577350
+#define HPF_Fs96000_Gain15_B2 0.000000
+
+/* Coefficients for sample rate 192000Hz */
+ /* Gain = 1.000000 dB */
+#define HPF_Fs192000_Gain1_A0 1.107823
+#define HPF_Fs192000_Gain1_A1 -0.875150
+#define HPF_Fs192000_Gain1_A2 0.000000
+#define HPF_Fs192000_Gain1_B1 -0.767327
+#define HPF_Fs192000_Gain1_B2 0.000000
+ /* Gain = 2.000000 dB */
+#define HPF_Fs192000_Gain2_A0 1.228803
+#define HPF_Fs192000_Gain2_A1 -0.996130
+#define HPF_Fs192000_Gain2_A2 0.000000
+#define HPF_Fs192000_Gain2_B1 -0.767327
+#define HPF_Fs192000_Gain2_B2 0.000000
+ /* Gain = 3.000000 dB */
+#define HPF_Fs192000_Gain3_A0 1.364544
+#define HPF_Fs192000_Gain3_A1 -1.131871
+#define HPF_Fs192000_Gain3_A2 0.000000
+#define HPF_Fs192000_Gain3_B1 -0.767327
+#define HPF_Fs192000_Gain3_B2 0.000000
+ /* Gain = 4.000000 dB */
+#define HPF_Fs192000_Gain4_A0 1.516849
+#define HPF_Fs192000_Gain4_A1 -1.284176
+#define HPF_Fs192000_Gain4_A2 0.000000
+#define HPF_Fs192000_Gain4_B1 -0.767327
+#define HPF_Fs192000_Gain4_B2 0.000000
+ /* Gain = 5.000000 dB */
+#define HPF_Fs192000_Gain5_A0 1.687737
+#define HPF_Fs192000_Gain5_A1 -1.455064
+#define HPF_Fs192000_Gain5_A2 0.000000
+#define HPF_Fs192000_Gain5_B1 -0.767327
+#define HPF_Fs192000_Gain5_B2 0.000000
+ /* Gain = 6.000000 dB */
+#define HPF_Fs192000_Gain6_A0 1.879477
+#define HPF_Fs192000_Gain6_A1 -1.646804
+#define HPF_Fs192000_Gain6_A2 0.000000
+#define HPF_Fs192000_Gain6_B1 -0.767327
+#define HPF_Fs192000_Gain6_B2 0.000000
+ /* Gain = 7.000000 dB */
+#define HPF_Fs192000_Gain7_A0 2.094613
+#define HPF_Fs192000_Gain7_A1 -1.861940
+#define HPF_Fs192000_Gain7_A2 0.000000
+#define HPF_Fs192000_Gain7_B1 -0.767327
+#define HPF_Fs192000_Gain7_B2 0.000000
+ /* Gain = 8.000000 dB */
+#define HPF_Fs192000_Gain8_A0 2.335999
+#define HPF_Fs192000_Gain8_A1 -2.103326
+#define HPF_Fs192000_Gain8_A2 0.000000
+#define HPF_Fs192000_Gain8_B1 -0.767327
+#define HPF_Fs192000_Gain8_B2 0.000000
+ /* Gain = 9.000000 dB */
+#define HPF_Fs192000_Gain9_A0 2.606839
+#define HPF_Fs192000_Gain9_A1 -2.374166
+#define HPF_Fs192000_Gain9_A2 0.000000
+#define HPF_Fs192000_Gain9_B1 -0.767327
+#define HPF_Fs192000_Gain9_B2 0.000000
+ /* Gain = 10.000000 dB */
+#define HPF_Fs192000_Gain10_A0 2.910726
+#define HPF_Fs192000_Gain10_A1 -2.678053
+#define HPF_Fs192000_Gain10_A2 0.000000
+#define HPF_Fs192000_Gain10_B1 -0.767327
+#define HPF_Fs192000_Gain10_B2 0.000000
+ /* Gain = 11.000000 dB */
+#define HPF_Fs192000_Gain11_A0 3.251693
+#define HPF_Fs192000_Gain11_A1 -3.019020
+#define HPF_Fs192000_Gain11_A2 0.000000
+#define HPF_Fs192000_Gain11_B1 -0.767327
+#define HPF_Fs192000_Gain11_B2 0.000000
+ /* Gain = 12.000000 dB */
+#define HPF_Fs192000_Gain12_A0 3.634264
+#define HPF_Fs192000_Gain12_A1 -3.401591
+#define HPF_Fs192000_Gain12_A2 0.000000
+#define HPF_Fs192000_Gain12_B1 -0.767327
+#define HPF_Fs192000_Gain12_B2 0.000000
+ /* Gain = 13.000000 dB */
+#define HPF_Fs192000_Gain13_A0 4.063516
+#define HPF_Fs192000_Gain13_A1 -3.830843
+#define HPF_Fs192000_Gain13_A2 0.000000
+#define HPF_Fs192000_Gain13_B1 -0.767327
+#define HPF_Fs192000_Gain13_B2 0.000000
+ /* Gain = 14.000000 dB */
+#define HPF_Fs192000_Gain14_A0 4.545145
+#define HPF_Fs192000_Gain14_A1 -4.312472
+#define HPF_Fs192000_Gain14_A2 0.000000
+#define HPF_Fs192000_Gain14_B1 -0.767327
+#define HPF_Fs192000_Gain14_B2 0.000000
+ /* Gain = 15.000000 dB */
+#define HPF_Fs192000_Gain15_A0 5.085542
+#define HPF_Fs192000_Gain15_A1 -4.852868
+#define HPF_Fs192000_Gain15_A2 0.000000
+#define HPF_Fs192000_Gain15_B1 -0.767327
+#define HPF_Fs192000_Gain15_B2 0.000000
+
+#endif
+
+#else
/* Coefficients for sample rate 22050Hz */
/* Gain = 1.000000 dB */
#define HPF_Fs22050_Gain1_A0 5383 /* Floating point value 0.164291 */
@@ -571,3 +1216,4 @@
#endif
+#endif
\ No newline at end of file
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
index 72564d4..cfe53b8 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
@@ -65,9 +65,16 @@
if(
/* General parameters */
((pParams->OperatingMode != LVM_MODE_OFF) && (pParams->OperatingMode != LVM_MODE_ON)) ||
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+ ((pParams->SampleRate != LVM_FS_8000) && (pParams->SampleRate != LVM_FS_11025) && (pParams->SampleRate != LVM_FS_12000) &&
+ (pParams->SampleRate != LVM_FS_16000) && (pParams->SampleRate != LVM_FS_22050) && (pParams->SampleRate != LVM_FS_24000) &&
+ (pParams->SampleRate != LVM_FS_32000) && (pParams->SampleRate != LVM_FS_44100) && (pParams->SampleRate != LVM_FS_48000) &&
+ (pParams->SampleRate != LVM_FS_96000) && (pParams->SampleRate != LVM_FS_192000)) ||
+#else
((pParams->SampleRate != LVM_FS_8000) && (pParams->SampleRate != LVM_FS_11025) && (pParams->SampleRate != LVM_FS_12000) &&
(pParams->SampleRate != LVM_FS_16000) && (pParams->SampleRate != LVM_FS_22050) && (pParams->SampleRate != LVM_FS_24000) &&
(pParams->SampleRate != LVM_FS_32000) && (pParams->SampleRate != LVM_FS_44100) && (pParams->SampleRate != LVM_FS_48000)) ||
+#endif
((pParams->SourceFormat != LVM_STEREO) && (pParams->SourceFormat != LVM_MONOINSTEREO) && (pParams->SourceFormat != LVM_MONO)) ||
(pParams->SpeakerType > LVM_EX_HEADPHONES))
{
@@ -268,7 +275,12 @@
void LVM_SetTrebleBoost(LVM_Instance_t *pInstance,
LVM_ControlParams_t *pParams)
{
+#ifdef BUILD_FLOAT
+ extern FO_FLOAT_LShx_Coefs_t LVM_TrebleBoostCoefs[];
+#else
extern FO_C16_LShx_Coefs_t LVM_TrebleBoostCoefs[];
+#endif
+
LVM_INT16 Offset;
LVM_INT16 EffectLevel = 0;
@@ -298,6 +310,20 @@
* Load the coefficients and enabled the treble boost
*/
Offset = (LVM_INT16)(EffectLevel - 1 + TrebleBoostSteps * (pParams->SampleRate - TrebleBoostMinRate));
+#ifdef BUILD_FLOAT
+ FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(&pInstance->pTE_State->TrebleBoost_State,
+ &pInstance->pTE_Taps->TrebleBoost_Taps,
+ &LVM_TrebleBoostCoefs[Offset]);
+
+ /*
+ * Clear the taps
+ */
+ LoadConst_Float((LVM_FLOAT)0, /* Value */
+ (void *)&pInstance->pTE_Taps->TrebleBoost_Taps, /* Destination.\
+ Cast to void: no dereferencing in function */
+ (LVM_UINT16)(sizeof(pInstance->pTE_Taps->TrebleBoost_Taps) / \
+ sizeof(LVM_FLOAT))); /* Number of words */
+#else
FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(&pInstance->pTE_State->TrebleBoost_State,
&pInstance->pTE_Taps->TrebleBoost_Taps,
&LVM_TrebleBoostCoefs[Offset]);
@@ -309,6 +335,7 @@
(void *)&pInstance->pTE_Taps->TrebleBoost_Taps, /* Destination.\
Cast to void: no dereferencing in function */
(LVM_UINT16)(sizeof(pInstance->pTE_Taps->TrebleBoost_Taps)/sizeof(LVM_INT16))); /* Number of words */
+#endif
}
}
else
@@ -342,6 +369,9 @@
LVM_UINT16 dBShifts; /* 6dB shifts */
LVM_UINT16 dBOffset; /* Table offset */
LVM_INT16 Volume = 0; /* Required volume in dBs */
+#ifdef BUILD_FLOAT
+ LVM_FLOAT Temp;
+#endif
/*
* Limit the gain to the maximum allowed
@@ -401,22 +431,46 @@
*/
if(dBShifts == 0)
{
+#ifdef BUILD_FLOAT
+ LVC_Mixer_SetTarget(&pInstance->VC_Volume.MixerStream[0],
+ (LVM_FLOAT)LVM_VolumeTable[dBOffset]);
+#else
LVC_Mixer_SetTarget(&pInstance->VC_Volume.MixerStream[0],
(LVM_INT32)LVM_VolumeTable[dBOffset]);
- }
+#endif
+ }
else
{
+#ifdef BUILD_FLOAT
+ Temp = LVM_VolumeTable[dBOffset];
+ while(dBShifts) {
+ Temp = Temp / 2.0f;
+ dBShifts--;
+ }
+ LVC_Mixer_SetTarget(&pInstance->VC_Volume.MixerStream[0], Temp);
+#else
LVC_Mixer_SetTarget(&pInstance->VC_Volume.MixerStream[0],
(((LVM_INT32)LVM_VolumeTable[dBOffset])>>dBShifts));
+#endif
}
pInstance->VC_Volume.MixerStream[0].CallbackSet = 1;
if(pInstance->NoSmoothVolume == LVM_TRUE)
{
+#ifdef BUILD_FLOAT
+ LVC_Mixer_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0], 0,
+ pInstance->Params.SampleRate, 2);
+#else
LVC_Mixer_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0],0,pInstance->Params.SampleRate,2);
+#endif
}
else
{
+#ifdef BUILD_FLOAT
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0],
+ LVM_VC_MIXER_TIME, pInstance->Params.SampleRate, 2);
+#else
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0],LVM_VC_MIXER_TIME,pInstance->Params.SampleRate,2);
+#endif
}
}
@@ -554,8 +608,23 @@
/* Configure Mixer module for gradual changes to volume*/
if(LocalParams.VC_Balance < 0)
{
+#ifdef BUILD_FLOAT
+ LVM_FLOAT Target_Float;
+#else
LVM_INT32 Target;
+#endif
/* Drop in right channel volume*/
+#ifdef BUILD_FLOAT
+ Target_Float = LVM_MAXFLOAT;
+ LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0], Target_Float);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],
+ LVM_VC_MIXER_TIME, LocalParams.SampleRate, 1);
+
+ Target_Float = dB_to_LinFloat((LVM_INT16)(LocalParams.VC_Balance << 4));
+ LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1], Target_Float);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],
+ LVM_VC_MIXER_TIME, LocalParams.SampleRate, 1);
+#else
Target = LVM_MAXINT_16;
LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0],Target);
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],LVM_VC_MIXER_TIME,LocalParams.SampleRate,1);
@@ -563,11 +632,27 @@
Target = dB_to_Lin32((LVM_INT16)(LocalParams.VC_Balance<<4));
LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1],Target);
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],LVM_VC_MIXER_TIME,LocalParams.SampleRate,1);
+#endif
}
else if(LocalParams.VC_Balance >0)
{
+#ifdef BUILD_FLOAT
+ LVM_FLOAT Target_Float;
+#else
LVM_INT32 Target;
+#endif
/* Drop in left channel volume*/
+#ifdef BUILD_FLOAT
+ Target_Float = dB_to_LinFloat((LVM_INT16)((-LocalParams.VC_Balance) << 4));
+ LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0], Target_Float);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],
+ LVM_VC_MIXER_TIME, LocalParams.SampleRate, 1);
+
+ Target_Float = LVM_MAXFLOAT;
+ LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1], Target_Float);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],
+ LVM_VC_MIXER_TIME, LocalParams.SampleRate, 1);
+#else
Target = dB_to_Lin32((LVM_INT16)((-LocalParams.VC_Balance)<<4));
LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0],Target);
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],LVM_VC_MIXER_TIME,LocalParams.SampleRate,1);
@@ -575,17 +660,36 @@
Target = LVM_MAXINT_16;
LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1],Target);
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],LVM_VC_MIXER_TIME,LocalParams.SampleRate,1);
+#endif
}
else
{
+#ifdef BUILD_FLOAT
+ LVM_FLOAT Target_Float;
+#else
LVM_INT32 Target;
+#endif
/* No drop*/
+#ifdef BUILD_FLOAT
+ Target_Float = LVM_MAXFLOAT;
+#else
Target = LVM_MAXINT_16;
+#endif
+#ifdef BUILD_FLOAT
+ LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0],Target_Float);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],
+ LVM_VC_MIXER_TIME,LocalParams.SampleRate, 1);
+
+ LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1],Target_Float);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],
+ LVM_VC_MIXER_TIME,LocalParams.SampleRate, 1);
+#else
LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0],Target);
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],LVM_VC_MIXER_TIME,LocalParams.SampleRate,1);
LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1],Target);
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],LVM_VC_MIXER_TIME,LocalParams.SampleRate,1);
+#endif
}
}
/*
@@ -1008,18 +1112,30 @@
short CallBackParam)
{
LVM_Instance_t *pInstance =(LVM_Instance_t *)pBundleHandle;
+#ifdef BUILD_FLOAT
+ LVM_FLOAT Target;
+#else
LVM_INT32 Target;
+#endif
(void) pGeneralPurpose;
(void) CallBackParam;
/* When volume mixer has reached 0 dB target then stop it to avoid
unnecessary processing. */
+#ifdef BUILD_FLOAT
+ Target = LVC_Mixer_GetTarget(&pInstance->VC_Volume.MixerStream[0]);
+ if(Target == 1.0f)
+ {
+ pInstance->VC_Active = LVM_FALSE;
+ }
+#else
Target = LVC_Mixer_GetTarget(&pInstance->VC_Volume.MixerStream[0]);
if(Target == 0x7FFF)
{
pInstance->VC_Active = LVM_FALSE;
}
+#endif
return 1;
}
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Init.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Init.c
index 542c3c8..26c1c4f 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Init.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Init.c
@@ -232,7 +232,11 @@
/*
* Set the capabilities
*/
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+ DBE_Capabilities.SampleRate = LVDBE_CAP_FS_8000 | LVDBE_CAP_FS_11025 | LVDBE_CAP_FS_12000 | LVDBE_CAP_FS_16000 | LVDBE_CAP_FS_22050 | LVDBE_CAP_FS_24000 | LVDBE_CAP_FS_32000 | LVDBE_CAP_FS_44100 | LVDBE_CAP_FS_48000 | LVDBE_CAP_FS_96000 | LVDBE_CAP_FS_192000;
+#else
DBE_Capabilities.SampleRate = LVDBE_CAP_FS_8000 | LVDBE_CAP_FS_11025 | LVDBE_CAP_FS_12000 | LVDBE_CAP_FS_16000 | LVDBE_CAP_FS_22050 | LVDBE_CAP_FS_24000 | LVDBE_CAP_FS_32000 | LVDBE_CAP_FS_44100 | LVDBE_CAP_FS_48000;
+#endif
DBE_Capabilities.CentreFrequency = LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_66Hz | LVDBE_CAP_CENTRE_78Hz | LVDBE_CAP_CENTRE_90Hz;
DBE_Capabilities.MaxBlockSize = InternalBlockSize;
@@ -265,7 +269,11 @@
/*
* Set the capabilities
*/
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+ EQNB_Capabilities.SampleRate = LVEQNB_CAP_FS_8000 | LVEQNB_CAP_FS_11025 | LVEQNB_CAP_FS_12000 | LVEQNB_CAP_FS_16000 | LVEQNB_CAP_FS_22050 | LVEQNB_CAP_FS_24000 | LVEQNB_CAP_FS_32000 | LVEQNB_CAP_FS_44100 | LVEQNB_CAP_FS_48000 | LVEQNB_CAP_FS_96000 | LVEQNB_CAP_FS_192000;
+#else
EQNB_Capabilities.SampleRate = LVEQNB_CAP_FS_8000 | LVEQNB_CAP_FS_11025 | LVEQNB_CAP_FS_12000 | LVEQNB_CAP_FS_16000 | LVEQNB_CAP_FS_22050 | LVEQNB_CAP_FS_24000 | LVEQNB_CAP_FS_32000 | LVEQNB_CAP_FS_44100 | LVEQNB_CAP_FS_48000;
+#endif
EQNB_Capabilities.SourceFormat = LVEQNB_CAP_STEREO | LVEQNB_CAP_MONOINSTEREO;
EQNB_Capabilities.MaxBlockSize = InternalBlockSize;
EQNB_Capabilities.MaxBands = pInstParams->EQNB_NumBands;
@@ -542,10 +550,15 @@
BundleScratchSize = (LVM_INT32)(6 * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) * sizeof(LVM_INT16));
pInstance->pBufferManagement->pScratch = InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST], /* Scratch 1 buffer */
(LVM_UINT32)BundleScratchSize);
-
+#ifdef BUILD_FLOAT
+ LoadConst_Float(0, /* Clear the input delay buffer */
+ (LVM_FLOAT *)&pInstance->pBufferManagement->InDelayBuffer,
+ (LVM_INT16)(2 * MIN_INTERNAL_BLOCKSIZE));
+#else
LoadConst_16(0, /* Clear the input delay buffer */
(LVM_INT16 *)&pInstance->pBufferManagement->InDelayBuffer,
(LVM_INT16)(2 * MIN_INTERNAL_BLOCKSIZE));
+#endif
pInstance->pBufferManagement->InDelaySamples = MIN_INTERNAL_BLOCKSIZE; /* Set the number of delay samples */
pInstance->pBufferManagement->OutDelaySamples = 0; /* No samples in the output buffer */
pInstance->pBufferManagement->BufferState = LVM_FIRSTCALL; /* Set the state ready for the first call */
@@ -598,14 +611,26 @@
/* In managed buffering, start with low signal level as delay in buffer management causes a click*/
if (pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
{
+#ifdef BUILD_FLOAT
+ LVC_Mixer_Init(&pInstance->VC_Volume.MixerStream[0], 0, 0);
+#else
LVC_Mixer_Init(&pInstance->VC_Volume.MixerStream[0],0,0);
+#endif
}
else
{
+#ifdef BUILD_FLOAT
+ LVC_Mixer_Init(&pInstance->VC_Volume.MixerStream[0], LVM_MAXFLOAT, LVM_MAXFLOAT);
+#else
LVC_Mixer_Init(&pInstance->VC_Volume.MixerStream[0],LVM_MAXINT_16,LVM_MAXINT_16);
+#endif
}
+#ifdef BUILD_FLOAT
LVC_Mixer_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0],0,LVM_FS_8000,2);
+#else
+ LVC_Mixer_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0], 0, LVM_FS_8000, 2);
+#endif
pInstance->VC_VolumedB = 0;
pInstance->VC_AVLFixedVolume = 0;
@@ -615,15 +640,24 @@
pInstance->VC_BalanceMix.MixerStream[0].CallbackSet = 0;
pInstance->VC_BalanceMix.MixerStream[0].pCallbackHandle = pInstance;
pInstance->VC_BalanceMix.MixerStream[0].pCallBack = LVM_VCCallBack;
+#ifdef BUILD_FLOAT
+ LVC_Mixer_Init(&pInstance->VC_BalanceMix.MixerStream[0], LVM_MAXFLOAT, LVM_MAXFLOAT);
+#else
LVC_Mixer_Init(&pInstance->VC_BalanceMix.MixerStream[0],LVM_MAXINT_16,LVM_MAXINT_16);
+#endif
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],LVM_VC_MIXER_TIME,LVM_FS_8000,2);
pInstance->VC_BalanceMix.MixerStream[1].CallbackParam = 0;
pInstance->VC_BalanceMix.MixerStream[1].CallbackSet = 0;
pInstance->VC_BalanceMix.MixerStream[1].pCallbackHandle = pInstance;
pInstance->VC_BalanceMix.MixerStream[1].pCallBack = LVM_VCCallBack;
+#ifdef BUILD_FLOAT
+ LVC_Mixer_Init(&pInstance->VC_BalanceMix.MixerStream[1], LVM_MAXFLOAT, LVM_MAXFLOAT);
+#else
LVC_Mixer_Init(&pInstance->VC_BalanceMix.MixerStream[1],LVM_MAXINT_16,LVM_MAXINT_16);
+#endif
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],LVM_VC_MIXER_TIME,LVM_FS_8000,2);
+
/*
* Set the default EQNB pre-gain and pointer to the band definitions
*/
@@ -709,7 +743,11 @@
/*
* Set the initialisation capabilities
*/
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+ DBE_Capabilities.SampleRate = LVDBE_CAP_FS_8000 | LVDBE_CAP_FS_11025 | LVDBE_CAP_FS_12000 | LVDBE_CAP_FS_16000 | LVDBE_CAP_FS_22050 | LVDBE_CAP_FS_24000 | LVDBE_CAP_FS_32000 | LVDBE_CAP_FS_44100 | LVDBE_CAP_FS_48000 | LVDBE_CAP_FS_96000 | LVDBE_CAP_FS_192000;
+#else
DBE_Capabilities.SampleRate = LVDBE_CAP_FS_8000 | LVDBE_CAP_FS_11025 | LVDBE_CAP_FS_12000 | LVDBE_CAP_FS_16000 | LVDBE_CAP_FS_22050 | LVDBE_CAP_FS_24000 | LVDBE_CAP_FS_32000 | LVDBE_CAP_FS_44100 | LVDBE_CAP_FS_48000;
+#endif
DBE_Capabilities.CentreFrequency = LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_66Hz | LVDBE_CAP_CENTRE_78Hz | LVDBE_CAP_CENTRE_90Hz;
DBE_Capabilities.MaxBlockSize = (LVM_UINT16)InternalBlockSize;
@@ -763,7 +801,11 @@
/*
* Set the initialisation capabilities
*/
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+ EQNB_Capabilities.SampleRate = LVEQNB_CAP_FS_8000 | LVEQNB_CAP_FS_11025 | LVEQNB_CAP_FS_12000 | LVEQNB_CAP_FS_16000 | LVEQNB_CAP_FS_22050 | LVEQNB_CAP_FS_24000 | LVEQNB_CAP_FS_32000 | LVEQNB_CAP_FS_44100 | LVEQNB_CAP_FS_48000 | LVEQNB_CAP_FS_96000 | LVEQNB_CAP_FS_192000;
+#else
EQNB_Capabilities.SampleRate = LVEQNB_CAP_FS_8000 | LVEQNB_CAP_FS_11025 | LVEQNB_CAP_FS_12000 | LVEQNB_CAP_FS_16000 | LVEQNB_CAP_FS_22050 | LVEQNB_CAP_FS_24000 | LVEQNB_CAP_FS_32000 | LVEQNB_CAP_FS_44100 | LVEQNB_CAP_FS_48000;
+#endif
EQNB_Capabilities.MaxBlockSize = (LVM_UINT16)InternalBlockSize;
EQNB_Capabilities.MaxBands = pInstParams->EQNB_NumBands;
EQNB_Capabilities.SourceFormat = LVEQNB_CAP_STEREO | LVEQNB_CAP_MONOINSTEREO;
@@ -868,9 +910,14 @@
PSA_MemTab.Region[LVM_PERSISTENT_FAST_COEF].Size);
/* Fast Temporary */
+#ifdef BUILD_FLOAT
pInstance->pPSAInput = InstAlloc_AddMember(&AllocMem[LVM_TEMPORARY_FAST],
- (LVM_UINT32) MAX_INTERNAL_BLOCKSIZE * sizeof(LVM_INT16));
-
+ (LVM_UINT32) MAX_INTERNAL_BLOCKSIZE * \
+ sizeof(LVM_FLOAT));
+#else
+ pInstance->pPSAInput = InstAlloc_AddMember(&AllocMem[LVM_TEMPORARY_FAST],
+ (LVM_UINT32) MAX_INTERNAL_BLOCKSIZE * sizeof(LVM_INT16));
+#endif
PSA_MemTab.Region[LVM_TEMPORARY_FAST].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],0);
@@ -994,7 +1041,6 @@
/* DC removal filter */
DC_2I_D16_TRC_WRA_01_Init(&pInstance->DC_RemovalInstance);
-
return LVM_SUCCESS;
}
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
index 2e85f77..b453222 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
@@ -138,6 +138,23 @@
/* Buffer Management */
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVM_FLOAT *pScratch; /* Bundle scratch buffer */
+
+ LVM_INT16 BufferState; /* Buffer status */
+ LVM_FLOAT InDelayBuffer[6 * MIN_INTERNAL_BLOCKSIZE]; /* Input buffer delay line, \
+ left and right */
+ LVM_INT16 InDelaySamples; /* Number of samples in the input delay buffer */
+
+ LVM_FLOAT OutDelayBuffer[2 * MIN_INTERNAL_BLOCKSIZE]; /* Output buffer delay \
+ line */
+ LVM_INT16 OutDelaySamples; /* Number of samples in the output delay buffer, \
+ left and right */
+ LVM_INT16 SamplesToOutput; /* Samples to write to the output */
+} LVM_Buffer_t;
+#else
typedef struct
{
LVM_INT16 *pScratch; /* Bundle scratch buffer */
@@ -150,22 +167,28 @@
LVM_INT16 OutDelaySamples; /* Number of samples in the output delay buffer, left and right */
LVM_INT16 SamplesToOutput; /* Samples to write to the output */
} LVM_Buffer_t;
-
+#endif
/* Filter taps */
typedef struct
{
+#ifdef BUILD_FLOAT
+ Biquad_2I_Order1_FLOAT_Taps_t TrebleBoost_Taps; /* Treble boost Taps */
+#else
Biquad_2I_Order1_Taps_t TrebleBoost_Taps; /* Treble boost Taps */
+#endif
} LVM_TE_Data_t;
-
/* Coefficients */
typedef struct
{
+#ifdef BUILD_FLOAT
+ Biquad_FLOAT_Instance_t TrebleBoost_State; /* State for the treble boost filter */
+#else
Biquad_Instance_t TrebleBoost_State; /* State for the treble boost filter */
+#endif
} LVM_TE_Coefs_t;
-
typedef struct
{
/* Public parameters */
@@ -181,15 +204,24 @@
LVM_INT16 InternalBlockSize; /* Maximum internal block size */
LVM_Buffer_t *pBufferManagement; /* Buffer management variables */
LVM_INT16 SamplesToProcess; /* Input samples left to process */
+#ifdef BUILD_FLOAT
+ LVM_FLOAT *pInputSamples; /* External input sample pointer */
+ LVM_FLOAT *pOutputSamples; /* External output sample pointer */
+#else
LVM_INT16 *pInputSamples; /* External input sample pointer */
LVM_INT16 *pOutputSamples; /* External output sample pointer */
+#endif
/* Configuration number */
LVM_INT32 ConfigurationNumber;
LVM_INT32 BlickSizeMultiple;
/* DC removal */
+#ifdef BUILD_FLOAT
+ Biquad_FLOAT_Instance_t DC_RemovalInstance; /* DC removal filter instance */
+#else
Biquad_Instance_t DC_RemovalInstance; /* DC removal filter instance */
+#endif
/* Concert Sound */
LVCS_Handle_t hCSInstance; /* Concert Sound instance handle */
@@ -209,8 +241,16 @@
LVM_INT16 DBE_Active; /* Control flag */
/* Volume Control */
+#ifdef BUILD_FLOAT
+ LVMixer3_1St_FLOAT_st VC_Volume; /* Volume scaler */
+#else
LVMixer3_1St_st VC_Volume; /* Volume scaler */
+#endif
+#ifdef BUILD_FLOAT
+ LVMixer3_2St_FLOAT_st VC_BalanceMix; /* VC balance mixer */
+#else
LVMixer3_2St_st VC_BalanceMix; /* VC balance mixer */
+#endif
LVM_INT16 VC_VolumedB; /* Gain in dB */
LVM_INT16 VC_Active; /* Control flag */
LVM_INT16 VC_AVLFixedVolume; /* AVL fixed volume */
@@ -234,7 +274,11 @@
LVPSA_ControlParams_t PSA_ControlParams; /* Spectrum Analyzer control parameters */
LVM_INT16 PSA_GainOffset; /* Tone control flag */
LVM_Callback CallBack;
+#ifdef BUILD_FLOAT
+ LVM_FLOAT *pPSAInput; /* PSA input pointer */
+#else
LVM_INT16 *pPSAInput; /* PSA input pointer */
+#endif
LVM_INT16 NoSmoothVolume; /* Enable or disable smooth volume changes*/
@@ -261,16 +305,28 @@
void LVM_SetHeadroom( LVM_Instance_t *pInstance,
LVM_ControlParams_t *pParams);
-
+#ifdef BUILD_FLOAT
+void LVM_BufferIn( LVM_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT **pToProcess,
+ LVM_FLOAT **pProcessed,
+ LVM_UINT16 *pNumSamples);
+#else
void LVM_BufferIn( LVM_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 **pToProcess,
LVM_INT16 **pProcessed,
LVM_UINT16 *pNumSamples);
-
+#endif
+#ifdef BUILD_FLOAT
+void LVM_BufferOut( LVM_Handle_t hInstance,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 *pNumSamples);
+#else
void LVM_BufferOut( LVM_Handle_t hInstance,
LVM_INT16 *pOutData,
LVM_UINT16 *pNumSamples);
+#endif
LVM_INT32 LVM_AlgoCallBack( void *pBundleHandle,
void *pData,
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
index f5a01f3..4a19a13 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
@@ -51,7 +51,231 @@
/* NOTES: */
/* */
/****************************************************************************************/
+#ifdef BUILD_FLOAT
+LVM_ReturnStatus_en LVM_Process(LVM_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples,
+ LVM_UINT32 AudioTime)
+{
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+ LVM_UINT16 SampleCount = NumSamples;
+ LVM_FLOAT *pInput = (LVM_FLOAT *)pInData;
+ LVM_FLOAT *pToProcess = (LVM_FLOAT *)pInData;
+ LVM_FLOAT *pProcessed = pOutData;
+ LVM_ReturnStatus_en Status;
+
+ /*
+ * Check if the number of samples is zero
+ */
+ if (NumSamples == 0)
+ {
+ return(LVM_SUCCESS);
+ }
+
+
+ /*
+ * Check valid points have been given
+ */
+ if ((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
+ {
+ return (LVM_NULLADDRESS);
+ }
+
+ /*
+ * For unmanaged mode only
+ */
+ if(pInstance->InstParams.BufferMode == LVM_UNMANAGED_BUFFERS)
+ {
+ /*
+ * Check if the number of samples is a good multiple (unmanaged mode only)
+ */
+ if((NumSamples % pInstance->BlickSizeMultiple) != 0)
+ {
+ return(LVM_INVALIDNUMSAMPLES);
+ }
+
+ /*
+ * Check the buffer alignment
+ */
+ if((((uintptr_t)pInData % 4) != 0) || (((uintptr_t)pOutData % 4) != 0))
+ {
+ return(LVM_ALIGNMENTERROR);
+ }
+ }
+
+
+ /*
+ * Update new parameters if necessary
+ */
+ if (pInstance->ControlPending == LVM_TRUE)
+ {
+ Status = LVM_ApplyNewSettings(hInstance);
+
+ if(Status != LVM_SUCCESS)
+ {
+ return Status;
+ }
+ }
+
+
+ /*
+ * Convert from Mono if necessary
+ */
+ if (pInstance->Params.SourceFormat == LVM_MONO)
+ {
+ MonoTo2I_Float(pInData, /* Source */
+ pOutData, /* Destination */
+ (LVM_INT16)NumSamples); /* Number of input samples */
+ pInput = pOutData;
+ pToProcess = pOutData;
+ }
+
+
+ /*
+ * Process the data with managed buffers
+ */
+ while (SampleCount != 0)
+ {
+ /*
+ * Manage the input buffer and frame processing
+ */
+ LVM_BufferIn(hInstance,
+ pInput,
+ &pToProcess,
+ &pProcessed,
+ &SampleCount);
+
+ /*
+ * Only process data when SampleCount is none zero, a zero count can occur when
+ * the BufferIn routine is working in managed mode.
+ */
+ if (SampleCount != 0)
+ {
+
+ /*
+ * Apply ConcertSound if required
+ */
+ if (pInstance->CS_Active == LVM_TRUE)
+ {
+ (void)LVCS_Process(pInstance->hCSInstance, /* Concert Sound instance handle */
+ pToProcess,
+ pProcessed,
+ SampleCount);
+ pToProcess = pProcessed;
+ }
+
+ /*
+ * Apply volume if required
+ */
+ if (pInstance->VC_Active!=0)
+ {
+ LVC_MixSoft_1St_D16C31_SAT(&pInstance->VC_Volume,
+ pToProcess,
+ pProcessed,
+ (LVM_INT16)(2 * SampleCount)); /* Left and right*/
+ pToProcess = pProcessed;
+ }
+
+ /*
+ * Call N-Band equaliser if enabled
+ */
+ if (pInstance->EQNB_Active == LVM_TRUE)
+ {
+ LVEQNB_Process(pInstance->hEQNBInstance, /* N-Band equaliser instance handle */
+ pToProcess,
+ pProcessed,
+ SampleCount);
+ pToProcess = pProcessed;
+ }
+
+ /*
+ * Call bass enhancement if enabled
+ */
+ if (pInstance->DBE_Active == LVM_TRUE)
+ {
+ LVDBE_Process(pInstance->hDBEInstance, /* Dynamic Bass Enhancement \
+ instance handle */
+ pToProcess,
+ pProcessed,
+ SampleCount);
+ pToProcess = pProcessed;
+ }
+
+ /*
+ * Bypass mode or everything off, so copy the input to the output
+ */
+ if (pToProcess != pProcessed)
+ {
+ Copy_Float(pToProcess, /* Source */
+ pProcessed, /* Destination */
+ (LVM_INT16)(2 * SampleCount)); /* Left and right */
+ }
+
+ /*
+ * Apply treble boost if required
+ */
+ if (pInstance->TE_Active == LVM_TRUE)
+ {
+ /*
+ * Apply the filter
+ */
+ FO_2I_D16F32C15_LShx_TRC_WRA_01(&pInstance->pTE_State->TrebleBoost_State,
+ pProcessed,
+ pProcessed,
+ (LVM_INT16)SampleCount);
+
+ }
+
+ /*
+ * Volume balance
+ */
+ LVC_MixSoft_1St_2i_D16C31_SAT(&pInstance->VC_BalanceMix,
+ pProcessed,
+ pProcessed,
+ SampleCount);
+
+ /*
+ * Perform Parametric Spectum Analysis
+ */
+ if ((pInstance->Params.PSA_Enable == LVM_PSA_ON) &&
+ (pInstance->InstParams.PSA_Included == LVM_PSA_ON))
+ {
+ From2iToMono_Float(pProcessed,
+ pInstance->pPSAInput,
+ (LVM_INT16)(SampleCount));
+
+ LVPSA_Process(pInstance->hPSAInstance,
+ pInstance->pPSAInput,
+ (LVM_UINT16)(SampleCount),
+ AudioTime);
+ }
+
+
+ /*
+ * DC removal
+ */
+ DC_2I_D16_TRC_WRA_01(&pInstance->DC_RemovalInstance,
+ pProcessed,
+ pProcessed,
+ (LVM_INT16)SampleCount);
+
+
+ }
+
+ /*
+ * Manage the output buffer
+ */
+ LVM_BufferOut(hInstance,
+ pOutData,
+ &SampleCount);
+
+ }
+
+ return(LVM_SUCCESS);
+}
+#else
LVM_ReturnStatus_en LVM_Process(LVM_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 *pOutData,
@@ -273,3 +497,4 @@
return(LVM_SUCCESS);
}
+#endif
\ No newline at end of file
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.c
index e14f909..199ddde 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.c
@@ -29,7 +29,342 @@
/* Treble Boost Filter Coefficients */
/* */
/************************************************************************************/
+#ifdef BUILD_FLOAT
+FO_FLOAT_LShx_Coefs_t LVM_TrebleBoostCoefs[] = {
+
+ /* 22kHz sampling rate */
+ {HPF_Fs22050_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs22050_Gain1_A0,
+ -HPF_Fs22050_Gain1_B1},
+ {HPF_Fs22050_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs22050_Gain2_A0,
+ -HPF_Fs22050_Gain2_B1},
+ {HPF_Fs22050_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs22050_Gain3_A0,
+ -HPF_Fs22050_Gain3_B1},
+ {HPF_Fs22050_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs22050_Gain4_A0,
+ -HPF_Fs22050_Gain4_B1},
+ {HPF_Fs22050_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs22050_Gain5_A0,
+ -HPF_Fs22050_Gain5_B1},
+ {HPF_Fs22050_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs22050_Gain6_A0,
+ -HPF_Fs22050_Gain6_B1},
+ {HPF_Fs22050_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs22050_Gain7_A0,
+ -HPF_Fs22050_Gain7_B1},
+ {HPF_Fs22050_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs22050_Gain8_A0,
+ -HPF_Fs22050_Gain8_B1},
+ {HPF_Fs22050_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs22050_Gain9_A0,
+ -HPF_Fs22050_Gain9_B1},
+ {HPF_Fs22050_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs22050_Gain10_A0,
+ -HPF_Fs22050_Gain10_B1},
+ {HPF_Fs22050_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs22050_Gain11_A0,
+ -HPF_Fs22050_Gain11_B1},
+ {HPF_Fs22050_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs22050_Gain12_A0,
+ -HPF_Fs22050_Gain12_B1},
+ {HPF_Fs22050_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs22050_Gain13_A0,
+ -HPF_Fs22050_Gain13_B1},
+ {HPF_Fs22050_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs22050_Gain14_A0,
+ -HPF_Fs22050_Gain14_B1},
+ {HPF_Fs22050_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs22050_Gain15_A0,
+ -HPF_Fs22050_Gain15_B1},
+
+ /* 24kHz sampling rate */
+ {HPF_Fs24000_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs24000_Gain1_A0,
+ -HPF_Fs24000_Gain1_B1},
+ {HPF_Fs24000_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs24000_Gain2_A0,
+ -HPF_Fs24000_Gain2_B1},
+ {HPF_Fs24000_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs24000_Gain3_A0,
+ -HPF_Fs24000_Gain3_B1},
+ {HPF_Fs24000_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs24000_Gain4_A0,
+ -HPF_Fs24000_Gain4_B1},
+ {HPF_Fs24000_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs24000_Gain5_A0,
+ -HPF_Fs24000_Gain5_B1},
+ {HPF_Fs24000_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs24000_Gain6_A0,
+ -HPF_Fs24000_Gain6_B1},
+ {HPF_Fs24000_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs24000_Gain7_A0,
+ -HPF_Fs24000_Gain7_B1},
+ {HPF_Fs24000_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs24000_Gain8_A0,
+ -HPF_Fs24000_Gain8_B1},
+ {HPF_Fs24000_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs24000_Gain9_A0,
+ -HPF_Fs24000_Gain9_B1},
+ {HPF_Fs24000_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs24000_Gain10_A0,
+ -HPF_Fs24000_Gain10_B1},
+ {HPF_Fs24000_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs24000_Gain11_A0,
+ -HPF_Fs24000_Gain11_B1},
+ {HPF_Fs24000_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs24000_Gain12_A0,
+ -HPF_Fs24000_Gain12_B1},
+ {HPF_Fs24000_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs24000_Gain13_A0,
+ -HPF_Fs24000_Gain13_B1},
+ {HPF_Fs24000_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs24000_Gain14_A0,
+ -HPF_Fs24000_Gain14_B1},
+ {HPF_Fs24000_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs24000_Gain15_A0,
+ -HPF_Fs24000_Gain15_B1},
+
+ /* 32kHz sampling rate */
+ {HPF_Fs32000_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs32000_Gain1_A0,
+ -HPF_Fs32000_Gain1_B1},
+ {HPF_Fs32000_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs32000_Gain2_A0,
+ -HPF_Fs32000_Gain2_B1},
+ {HPF_Fs32000_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs32000_Gain3_A0,
+ -HPF_Fs32000_Gain3_B1},
+ {HPF_Fs32000_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs32000_Gain4_A0,
+ -HPF_Fs32000_Gain4_B1},
+ {HPF_Fs32000_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs32000_Gain5_A0,
+ -HPF_Fs32000_Gain5_B1},
+ {HPF_Fs32000_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs32000_Gain6_A0,
+ -HPF_Fs32000_Gain6_B1},
+ {HPF_Fs32000_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs32000_Gain7_A0,
+ -HPF_Fs32000_Gain7_B1},
+ {HPF_Fs32000_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs32000_Gain8_A0,
+ -HPF_Fs32000_Gain8_B1},
+ {HPF_Fs32000_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs32000_Gain9_A0,
+ -HPF_Fs32000_Gain9_B1},
+ {HPF_Fs32000_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs32000_Gain10_A0,
+ -HPF_Fs32000_Gain10_B1},
+ {HPF_Fs32000_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs32000_Gain11_A0,
+ -HPF_Fs32000_Gain11_B1},
+ {HPF_Fs32000_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs32000_Gain12_A0,
+ -HPF_Fs32000_Gain12_B1},
+ {HPF_Fs32000_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs32000_Gain13_A0,
+ -HPF_Fs32000_Gain13_B1},
+ {HPF_Fs32000_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs32000_Gain14_A0,
+ -HPF_Fs32000_Gain14_B1},
+ {HPF_Fs32000_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs32000_Gain15_A0,
+ -HPF_Fs32000_Gain15_B1},
+
+ /* 44kHz sampling rate */
+ {HPF_Fs44100_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs44100_Gain1_A0,
+ -HPF_Fs44100_Gain1_B1,},
+ {HPF_Fs44100_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs44100_Gain2_A0,
+ -HPF_Fs44100_Gain2_B1},
+ {HPF_Fs44100_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs44100_Gain3_A0,
+ -HPF_Fs44100_Gain3_B1},
+ {HPF_Fs44100_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs44100_Gain4_A0,
+ -HPF_Fs44100_Gain4_B1},
+ {HPF_Fs44100_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs44100_Gain5_A0,
+ -HPF_Fs44100_Gain5_B1},
+ {HPF_Fs44100_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs44100_Gain6_A0,
+ -HPF_Fs44100_Gain6_B1},
+ {HPF_Fs44100_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs44100_Gain7_A0,
+ -HPF_Fs44100_Gain7_B1},
+ {HPF_Fs44100_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs44100_Gain8_A0,
+ -HPF_Fs44100_Gain8_B1},
+ {HPF_Fs44100_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs44100_Gain9_A0,
+ -HPF_Fs44100_Gain9_B1},
+ {HPF_Fs44100_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs44100_Gain10_A0,
+ -HPF_Fs44100_Gain10_B1},
+ {HPF_Fs44100_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs44100_Gain11_A0,
+ -HPF_Fs44100_Gain11_B1},
+ {HPF_Fs44100_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs44100_Gain12_A0,
+ -HPF_Fs44100_Gain12_B1},
+ {HPF_Fs44100_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs44100_Gain13_A0,
+ -HPF_Fs44100_Gain13_B1},
+ {HPF_Fs44100_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs44100_Gain14_A0,
+ -HPF_Fs44100_Gain14_B1},
+ {HPF_Fs44100_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs44100_Gain15_A0,
+ -HPF_Fs44100_Gain15_B1},
+
+ /* 48kHz sampling rate */
+ {HPF_Fs48000_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs48000_Gain1_A0,
+ -HPF_Fs48000_Gain1_B1},
+ {HPF_Fs48000_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs48000_Gain2_A0,
+ -HPF_Fs48000_Gain2_B1},
+ {HPF_Fs48000_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs48000_Gain3_A0,
+ -HPF_Fs48000_Gain3_B1},
+ {HPF_Fs48000_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs48000_Gain4_A0,
+ -HPF_Fs48000_Gain4_B1},
+ {HPF_Fs48000_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs48000_Gain5_A0,
+ -HPF_Fs48000_Gain5_B1},
+ {HPF_Fs48000_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs48000_Gain6_A0,
+ -HPF_Fs48000_Gain6_B1},
+ {HPF_Fs48000_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs48000_Gain7_A0,
+ -HPF_Fs48000_Gain7_B1},
+ {HPF_Fs48000_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs48000_Gain8_A0,
+ -HPF_Fs48000_Gain8_B1},
+ {HPF_Fs48000_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs48000_Gain9_A0,
+ -HPF_Fs48000_Gain9_B1},
+ {HPF_Fs48000_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs48000_Gain10_A0,
+ -HPF_Fs48000_Gain10_B1},
+ {HPF_Fs48000_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs48000_Gain11_A0,
+ -HPF_Fs48000_Gain11_B1},
+ {HPF_Fs48000_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs48000_Gain12_A0,
+ -HPF_Fs48000_Gain12_B1},
+ {HPF_Fs48000_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs48000_Gain13_A0,
+ -HPF_Fs48000_Gain13_B1},
+ {HPF_Fs48000_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs48000_Gain14_A0,
+ -HPF_Fs48000_Gain14_B1},
+ {HPF_Fs48000_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs48000_Gain15_A0,
+ -HPF_Fs48000_Gain15_B1}
+#ifdef HIGHER_FS
+ ,
+ /* 96kHz sampling rate */
+ {HPF_Fs96000_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs96000_Gain1_A0,
+ -HPF_Fs96000_Gain1_B1},
+ {HPF_Fs96000_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs96000_Gain2_A0,
+ -HPF_Fs96000_Gain2_B1},
+ {HPF_Fs96000_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs96000_Gain3_A0,
+ -HPF_Fs96000_Gain3_B1},
+ {HPF_Fs96000_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs96000_Gain4_A0,
+ -HPF_Fs96000_Gain4_B1},
+ {HPF_Fs96000_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs96000_Gain5_A0,
+ -HPF_Fs96000_Gain5_B1},
+ {HPF_Fs96000_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs96000_Gain6_A0,
+ -HPF_Fs96000_Gain6_B1},
+ {HPF_Fs96000_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs96000_Gain7_A0,
+ -HPF_Fs96000_Gain7_B1},
+ {HPF_Fs96000_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs96000_Gain8_A0,
+ -HPF_Fs96000_Gain8_B1},
+ {HPF_Fs96000_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs96000_Gain9_A0,
+ -HPF_Fs96000_Gain9_B1},
+ {HPF_Fs96000_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs96000_Gain10_A0,
+ -HPF_Fs96000_Gain10_B1},
+ {HPF_Fs96000_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs96000_Gain11_A0,
+ -HPF_Fs96000_Gain11_B1},
+ {HPF_Fs96000_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs96000_Gain12_A0,
+ -HPF_Fs96000_Gain12_B1},
+ {HPF_Fs96000_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs96000_Gain13_A0,
+ -HPF_Fs96000_Gain13_B1},
+ {HPF_Fs96000_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs96000_Gain14_A0,
+ -HPF_Fs96000_Gain14_B1},
+ {HPF_Fs96000_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs96000_Gain15_A0,
+ -HPF_Fs96000_Gain15_B1},
+
+ /* 192kHz sampling rate */
+ {HPF_Fs192000_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs192000_Gain1_A0,
+ -HPF_Fs192000_Gain1_B1},
+ {HPF_Fs192000_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs192000_Gain2_A0,
+ -HPF_Fs192000_Gain2_B1},
+ {HPF_Fs192000_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs192000_Gain3_A0,
+ -HPF_Fs192000_Gain3_B1},
+ {HPF_Fs192000_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs192000_Gain4_A0,
+ -HPF_Fs192000_Gain4_B1},
+ {HPF_Fs192000_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs192000_Gain5_A0,
+ -HPF_Fs192000_Gain5_B1},
+ {HPF_Fs192000_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs192000_Gain6_A0,
+ -HPF_Fs192000_Gain6_B1},
+ {HPF_Fs192000_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs192000_Gain7_A0,
+ -HPF_Fs192000_Gain7_B1},
+ {HPF_Fs192000_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs192000_Gain8_A0,
+ -HPF_Fs192000_Gain8_B1},
+ {HPF_Fs192000_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs192000_Gain9_A0,
+ -HPF_Fs192000_Gain9_B1},
+ {HPF_Fs192000_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs192000_Gain10_A0,
+ -HPF_Fs192000_Gain10_B1},
+ {HPF_Fs192000_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs192000_Gain11_A0,
+ -HPF_Fs192000_Gain11_B1},
+ {HPF_Fs192000_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs192000_Gain12_A0,
+ -HPF_Fs192000_Gain12_B1},
+ {HPF_Fs192000_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs192000_Gain13_A0,
+ -HPF_Fs192000_Gain13_B1},
+ {HPF_Fs192000_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs192000_Gain14_A0,
+ -HPF_Fs192000_Gain14_B1},
+ {HPF_Fs192000_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs192000_Gain15_A0,
+ -HPF_Fs192000_Gain15_B1}
+#endif
+ };
+#else
FO_C16_LShx_Coefs_t LVM_TrebleBoostCoefs[] = {
/* 22kHz sampling rate */
@@ -340,8 +675,9 @@
{HPF_Fs48000_Gain15_A1, /* Gain setting 15 */
HPF_Fs48000_Gain15_A0,
-HPF_Fs48000_Gain15_B1,
- HPF_Fs48000_Gain15_Shift}};
-
+ HPF_Fs48000_Gain15_Shift}
+ };
+#endif
/************************************************************************************/
/* */
@@ -350,6 +686,16 @@
/************************************************************************************/
/* dB to linear conversion table */
+#ifdef BUILD_FLOAT
+const LVM_FLOAT LVM_VolumeTable[] = {
+ 1.000f, /* 0dB */
+ 0.891f, /* -1dB */
+ 0.794f, /* -2dB */
+ 0.708f, /* -3dB */
+ 0.631f, /* -4dB */
+ 0.562f, /* -5dB */
+ 0.501f}; /* -6dB */
+#else
const LVM_INT16 LVM_VolumeTable[] = {
0x7FFF, /* 0dB */
0x7215, /* -1dB */
@@ -358,6 +704,7 @@
0x50C3, /* -4dB */
0x47FB, /* -5dB */
0x4000}; /* -6dB */
+#endif
/************************************************************************************/
/* */
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.h b/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.h
index a7601ff..4cf7119 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.h
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.h
@@ -37,16 +37,23 @@
/* */
/************************************************************************************/
+#ifdef BUILD_FLOAT
+extern FO_FLOAT_LShx_Coefs_t LVM_TrebleBoostCoefs[];
+#else
extern FO_C16_LShx_Coefs_t LVM_TrebleBoostCoefs[];
-
+#endif
/************************************************************************************/
/* */
/* Volume control gain and time constant tables */
/* */
/************************************************************************************/
-
+#ifdef BUILD_FLOAT
+extern const LVM_FLOAT LVM_VolumeTable[];
+#else
extern const LVM_INT16 LVM_VolumeTable[];
+#endif
+
extern const LVM_INT16 LVM_MixerTCTable[];
diff --git a/media/libeffects/lvm/lib/Common/lib/AGC.h b/media/libeffects/lvm/lib/Common/lib/AGC.h
index 2080d64..9a3d35d 100644
--- a/media/libeffects/lvm/lib/Common/lib/AGC.h
+++ b/media/libeffects/lvm/lib/Common/lib/AGC.h
@@ -37,7 +37,7 @@
/* Types */
/* */
/**********************************************************************************/
-
+#ifndef BUILD_FLOAT
typedef struct
{
LVM_INT32 AGC_Gain; /* The current AGC gain */
@@ -52,20 +52,39 @@
LVM_INT16 VolumeTC; /* Volume update time constant */
} AGC_MIX_VOL_2St1Mon_D32_t;
+#else
+typedef struct
+{
+ LVM_FLOAT AGC_Gain; /* The current AGC gain */
+ LVM_FLOAT AGC_MaxGain; /* The maximum AGC gain */
+ LVM_FLOAT Volume; /* The current volume setting */
+ LVM_FLOAT Target; /* The target volume setting */
+ LVM_FLOAT AGC_Target; /* AGC target level */
+ LVM_FLOAT AGC_Attack; /* AGC attack scaler */
+ LVM_FLOAT AGC_Decay; /* AGC decay scaler */
+ LVM_FLOAT VolumeTC; /* Volume update time constant */
+} AGC_MIX_VOL_2St1Mon_FLOAT_t;
+#endif
/**********************************************************************************/
/* */
/* Function Prototypes */
/* */
/**********************************************************************************/
-
+#ifdef BUILD_FLOAT
+void AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t *pInstance, /* Instance pointer */
+ const LVM_FLOAT *pStSrc, /* Stereo source */
+ const LVM_FLOAT *pMonoSrc, /* Mono source */
+ LVM_FLOAT *pDst, /* Stereo destination */
+ LVM_UINT16 n); /* Number of samples */
+#else
void AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_D32_t *pInstance, /* Instance pointer */
const LVM_INT32 *pStSrc, /* Stereo source */
const LVM_INT32 *pMonoSrc, /* Mono source */
LVM_INT32 *pDst, /* Stereo destination */
LVM_UINT16 n); /* Number of samples */
-
+#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/media/libeffects/lvm/lib/Common/lib/BIQUAD.h b/media/libeffects/lvm/lib/Common/lib/BIQUAD.h
index 7ac7fbd..3ee7f63 100644
--- a/media/libeffects/lvm/lib/Common/lib/BIQUAD.h
+++ b/media/libeffects/lvm/lib/Common/lib/BIQUAD.h
@@ -27,19 +27,34 @@
/**********************************************************************************
INSTANCE MEMORY TYPE DEFINITION
***********************************************************************************/
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVM_FLOAT Storage[6];
+} Biquad_FLOAT_Instance_t;
+#else
typedef struct
{
LVM_INT32 Storage[6];
} Biquad_Instance_t;
-
-
+#endif
/**********************************************************************************
COEFFICIENT TYPE DEFINITIONS
***********************************************************************************/
/*** Biquad coefficients **********************************************************/
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVM_FLOAT A2; /* a2 */
+ LVM_FLOAT A1; /* a1 */
+ LVM_FLOAT A0; /* a0 */
+ LVM_FLOAT B2; /* -b2! */
+ LVM_FLOAT B1; /* -b1! */
+} BQ_FLOAT_Coefs_t;
+#else
typedef struct
{
LVM_INT16 A2; /* a2 */
@@ -57,8 +72,17 @@
LVM_INT32 B2; /* -b2! */
LVM_INT32 B1; /* -b1! */
} BQ_C32_Coefs_t;
+#endif
/*** First order coefficients *****************************************************/
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVM_FLOAT A1; /* a1 */
+ LVM_FLOAT A0; /* a0 */
+ LVM_FLOAT B1; /* -b1! */
+} FO_FLOAT_Coefs_t;
+#else
typedef struct
{
LVM_INT16 A1; /* a1 */
@@ -72,8 +96,17 @@
LVM_INT32 A0; /* a0 */
LVM_INT32 B1; /* -b1! */
} FO_C32_Coefs_t;
+#endif
/*** First order coefficients with Shift*****************************************************/
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVM_FLOAT A1; /* a1 */
+ LVM_FLOAT A0; /* a0 */
+ LVM_FLOAT B1; /* -b1! */
+} FO_FLOAT_LShx_Coefs_t;
+#else
typedef struct
{
LVM_INT16 A1; /* a1 */
@@ -81,8 +114,16 @@
LVM_INT16 B1; /* -b1! */
LVM_INT16 Shift; /* Shift */
} FO_C16_LShx_Coefs_t;
-
+#endif
/*** Band pass coefficients *******************************************************/
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVM_FLOAT A0; /* a0 */
+ LVM_FLOAT B2; /* -b2! */
+ LVM_FLOAT B1; /* -b1! */
+} BP_FLOAT_Coefs_t;
+#else
typedef struct
{
LVM_INT16 A0; /* a0 */
@@ -96,8 +137,18 @@
LVM_INT32 B2; /* -b2! */
LVM_INT32 B1; /* -b1! */
} BP_C32_Coefs_t;
+#endif
/*** Peaking coefficients *********************************************************/
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVM_FLOAT A0; /* a0 */
+ LVM_FLOAT B2; /* -b2! */
+ LVM_FLOAT B1; /* -b1! */
+ LVM_FLOAT G; /* Gain */
+} PK_FLOAT_Coefs_t;
+#else
typedef struct
{
LVM_INT16 A0; /* a0 */
@@ -113,16 +164,26 @@
LVM_INT32 B1; /* -b1! */
LVM_INT16 G; /* Gain */
} PK_C32_Coefs_t;
-
+#endif
/**********************************************************************************
TAPS TYPE DEFINITIONS
***********************************************************************************/
/*** Types used for first order and shelving filter *******************************/
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVM_FLOAT Storage[ (1 * 2) ]; /* One channel, two taps of size LVM_INT32 */
+} Biquad_1I_Order1_FLOAT_Taps_t;
typedef struct
{
+ LVM_FLOAT Storage[ (2 * 2) ]; /* Two channels, two taps of size LVM_INT32 */
+} Biquad_2I_Order1_FLOAT_Taps_t;
+#else
+typedef struct
+{
LVM_INT32 Storage[ (1*2) ]; /* One channel, two taps of size LVM_INT32 */
} Biquad_1I_Order1_Taps_t;
@@ -130,12 +191,22 @@
{
LVM_INT32 Storage[ (2*2) ]; /* Two channels, two taps of size LVM_INT32 */
} Biquad_2I_Order1_Taps_t;
-
+#endif
/*** Types used for biquad, band pass and peaking filter **************************/
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVM_FLOAT Storage[ (1 * 4) ]; /* One channel, four taps of size LVM_INT32 */
+} Biquad_1I_Order2_FLOAT_Taps_t;
typedef struct
{
+ LVM_FLOAT Storage[ (2 * 4) ]; /* Two channels, four taps of size LVM_INT32 */
+} Biquad_2I_Order2_FLOAT_Taps_t;
+#else
+typedef struct
+{
LVM_INT32 Storage[ (1*4) ]; /* One channel, four taps of size LVM_INT32 */
} Biquad_1I_Order2_Taps_t;
@@ -143,7 +214,7 @@
{
LVM_INT32 Storage[ (2*4) ]; /* Two channels, four taps of size LVM_INT32 */
} Biquad_2I_Order2_Taps_t;
-
+#endif
/* The names of the functions are changed to satisfy QAC rules: Name should be Unique withing 16 characters*/
#define BQ_2I_D32F32Cll_TRC_WRA_01_Init Init_BQ_2I_D32F32Cll_TRC_WRA_01
#define BP_1I_D32F32C30_TRC_WRA_02 TWO_BP_1I_D32F32C30_TRC_WRA_02
@@ -154,59 +225,148 @@
/*** 16 bit data path *************************************************************/
+
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F32Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef);
+#else
void BQ_2I_D16F32Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_2I_Order2_Taps_t *pTaps,
BQ_C16_Coefs_t *pCoef);
+#endif
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F32C15_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void BQ_2I_D16F32C15_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
LVM_INT16 NrSamples);
+#endif
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F32C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void BQ_2I_D16F32C14_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
LVM_INT16 NrSamples);
+#endif
+
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F32C13_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void BQ_2I_D16F32C13_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
LVM_INT16 NrSamples);
+#endif
+
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F16Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef);
+#else
void BQ_2I_D16F16Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_2I_Order2_Taps_t *pTaps,
BQ_C16_Coefs_t *pCoef);
+#endif
+
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F16C15_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void BQ_2I_D16F16C15_TRC_WRA_01( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
LVM_INT16 NrSamples);
+#endif
+
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F16C14_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void BQ_2I_D16F16C14_TRC_WRA_01( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
LVM_INT16 NrSamples);
+#endif
+#ifdef BUILD_FLOAT
+void BQ_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef);
+#else
void BQ_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_1I_Order2_Taps_t *pTaps,
BQ_C16_Coefs_t *pCoef);
+#endif
+
+#ifdef BUILD_FLOAT
+void BQ_1I_D16F16C15_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void BQ_1I_D16F16C15_TRC_WRA_01( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
LVM_INT16 NrSamples);
+#endif
+
+#ifdef BUILD_FLOAT
+void BQ_1I_D16F32Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef);
+#else
void BQ_1I_D16F32Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_1I_Order2_Taps_t *pTaps,
BQ_C16_Coefs_t *pCoef);
+#endif
+
+#ifdef BUILD_FLOAT
+void BQ_1I_D16F32C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void BQ_1I_D16F32C14_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
LVM_INT16 NrSamples);
+#endif
/*** 32 bit data path *************************************************************/
-
+#ifdef BUILD_FLOAT
+void BQ_2I_D32F32Cll_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef);
+void BQ_2I_D32F32C30_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void BQ_2I_D32F32Cll_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_2I_Order2_Taps_t *pTaps,
BQ_C32_Coefs_t *pCoef);
@@ -215,33 +375,66 @@
LVM_INT32 *pDataIn,
LVM_INT32 *pDataOut,
LVM_INT16 NrSamples);
+#endif
/**********************************************************************************
FUNCTION PROTOTYPES: FIRST ORDER FILTERS
***********************************************************************************/
/*** 16 bit data path *************************************************************/
-
+#ifdef BUILD_FLOAT
+void FO_1I_D16F16Css_TRC_WRA_01_Init( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order1_FLOAT_Taps_t *pTaps,
+ FO_FLOAT_Coefs_t *pCoef);
+#else
void FO_1I_D16F16Css_TRC_WRA_01_Init( Biquad_Instance_t *pInstance,
Biquad_1I_Order1_Taps_t *pTaps,
FO_C16_Coefs_t *pCoef);
+#endif
+#ifdef BUILD_FLOAT
+void FO_1I_D16F16C15_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void FO_1I_D16F16C15_TRC_WRA_01( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
LVM_INT16 NrSamples);
+#endif
+#ifdef BUILD_FLOAT
+void FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order1_FLOAT_Taps_t *pTaps,
+ FO_FLOAT_LShx_Coefs_t *pCoef);
+#else
void FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(Biquad_Instance_t *pInstance,
Biquad_2I_Order1_Taps_t *pTaps,
FO_C16_LShx_Coefs_t *pCoef);
+#endif
+#ifdef BUILD_FLOAT
+void FO_2I_D16F32C15_LShx_TRC_WRA_01(Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void FO_2I_D16F32C15_LShx_TRC_WRA_01(Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
LVM_INT16 NrSamples);
-
+#endif
/*** 32 bit data path *************************************************************/
-
+#ifdef BUILD_FLOAT
+void FO_1I_D32F32Cll_TRC_WRA_01_Init( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order1_FLOAT_Taps_t *pTaps,
+ FO_FLOAT_Coefs_t *pCoef);
+void FO_1I_D32F32C31_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void FO_1I_D32F32Cll_TRC_WRA_01_Init( Biquad_Instance_t *pInstance,
Biquad_1I_Order1_Taps_t *pTaps,
FO_C32_Coefs_t *pCoef);
@@ -250,13 +443,28 @@
LVM_INT32 *pDataIn,
LVM_INT32 *pDataOut,
LVM_INT16 NrSamples);
-
+#endif
/**********************************************************************************
FUNCTION PROTOTYPES: BAND PASS FILTERS
***********************************************************************************/
/*** 16 bit data path *************************************************************/
-
+#ifdef BUILD_FLOAT
+void BP_1I_D16F16Css_TRC_WRA_01_Init( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BP_FLOAT_Coefs_t *pCoef);
+void BP_1I_D16F16C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+void BP_1I_D16F32Cll_TRC_WRA_01_Init (Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BP_FLOAT_Coefs_t *pCoef);
+void BP_1I_D16F32C30_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void BP_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_1I_Order2_Taps_t *pTaps,
BP_C16_Coefs_t *pCoef);
@@ -274,10 +482,17 @@
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
LVM_INT16 NrSamples);
-
-
+#endif
/*** 32 bit data path *************************************************************/
-
+#ifdef BUILD_FLOAT
+void BP_1I_D32F32Cll_TRC_WRA_02_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BP_FLOAT_Coefs_t *pCoef);
+void BP_1I_D32F32C30_TRC_WRA_02( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void BP_1I_D32F32Cll_TRC_WRA_02_Init ( Biquad_Instance_t *pInstance,
Biquad_1I_Order2_Taps_t *pTaps,
BP_C32_Coefs_t *pCoef);
@@ -286,42 +501,59 @@
LVM_INT32 *pDataIn,
LVM_INT32 *pDataOut,
LVM_INT16 NrSamples);
-
+#endif
/*** 32 bit data path STEREO ******************************************************/
-
+#ifndef BUILD_FLOAT
void PK_2I_D32F32CllGss_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_2I_Order2_Taps_t *pTaps,
PK_C32_Coefs_t *pCoef);
-
void PK_2I_D32F32C30G11_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT32 *pDataIn,
LVM_INT32 *pDataOut,
LVM_INT16 NrSamples);
-
+#endif
+#ifdef BUILD_FLOAT
+void PK_2I_D32F32CssGss_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
+ PK_FLOAT_Coefs_t *pCoef);
+#else
void PK_2I_D32F32CssGss_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_2I_Order2_Taps_t *pTaps,
PK_C16_Coefs_t *pCoef);
-
+#endif
+#ifdef BUILD_FLOAT
+void PK_2I_D32F32C14G11_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void PK_2I_D32F32C14G11_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT32 *pDataIn,
LVM_INT32 *pDataOut,
LVM_INT16 NrSamples);
-
+#endif
/**********************************************************************************
FUNCTION PROTOTYPES: DC REMOVAL FILTERS
***********************************************************************************/
/*** 16 bit data path STEREO ******************************************************/
+#ifdef BUILD_FLOAT
+void DC_2I_D16_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance);
+void DC_2I_D16_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples);
+#else
void DC_2I_D16_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance);
void DC_2I_D16_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
LVM_INT16 NrSamples);
-
+#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/media/libeffects/lvm/lib/Common/lib/CompLim.h b/media/libeffects/lvm/lib/Common/lib/CompLim.h
index 4cb8aa2..498faa3 100644
--- a/media/libeffects/lvm/lib/Common/lib/CompLim.h
+++ b/media/libeffects/lvm/lib/Common/lib/CompLim.h
@@ -66,13 +66,17 @@
/* Function Prototypes */
/* */
/************************************************************************************/
-
+#ifdef BUILD_FLOAT
+void NonLinComp_Float(LVM_FLOAT Gain,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT32 BlockLength);
+#else
void NonLinComp_D16(LVM_INT16 Gain,
LVM_INT16 *pSterBfIn,
LVM_INT16 *pSterBfOut,
LVM_INT32 BlockLength);
-
-
+#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/media/libeffects/lvm/lib/Common/lib/Filter.h b/media/libeffects/lvm/lib/Common/lib/Filter.h
index 229701a..0c8955d 100644
--- a/media/libeffects/lvm/lib/Common/lib/Filter.h
+++ b/media/libeffects/lvm/lib/Common/lib/Filter.h
@@ -33,11 +33,32 @@
DEFINES
***********************************************************************************/
#define FILTER_LOSS 32730 /* -0.01dB loss to avoid wrapping due to band ripple */
-
+#ifdef BUILD_FLOAT
+#define FILTER_LOSS_FLOAT 0.998849f
+#endif
/**********************************************************************************
FUNCTION PROTOTYPES
***********************************************************************************/
+#ifdef BUILD_FLOAT
+LVM_FLOAT LVM_Power10( LVM_FLOAT X);
+
+LVM_FLOAT LVM_Polynomial(LVM_UINT16 N,
+ LVM_FLOAT *pCoefficients,
+ LVM_FLOAT X);
+#ifdef HIGHER_FS
+LVM_FLOAT LVM_GetOmega(LVM_UINT32 Fc,
+#else
+LVM_FLOAT LVM_GetOmega(LVM_UINT16 Fc,
+#endif
+ LVM_Fs_en SampleRate);
+
+LVM_FLOAT LVM_FO_LPF( LVM_FLOAT w,
+ FO_FLOAT_Coefs_t *pCoeffs);
+
+LVM_FLOAT LVM_FO_HPF( LVM_FLOAT w,
+ FO_FLOAT_Coefs_t *pCoeffs);
+#else
LVM_INT32 LVM_Polynomial(LVM_UINT16 N,
LVM_INT32 *pCoefficients,
LVM_INT32 X);
@@ -52,7 +73,7 @@
LVM_INT32 LVM_GetOmega(LVM_UINT16 Fc,
LVM_Fs_en SampleRate);
-
+#endif
/**********************************************************************************/
#ifdef __cplusplus
}
diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
index 68c55f7..cb15b60 100644
--- a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
+++ b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
@@ -44,6 +44,9 @@
#define LVM_MAXINT_8 127 /* Maximum positive integer size */
#define LVM_MAXINT_16 32767
+#ifdef BUILD_FLOAT
+#define LVM_MAXFLOAT 1.0f
+#endif
#define LVM_MAXINT_32 2147483647
#define LVM_MAXENUM 2147483647
@@ -95,7 +98,9 @@
typedef int32_t LVM_INT32; /* Signed 32-bit word */
typedef uint32_t LVM_UINT32; /* Unsigned 32-bit word */
-
+#ifdef BUILD_FLOAT
+typedef float LVM_FLOAT; /* single precission floating point*/
+#endif
/****************************************************************************************/
/* */
/* Standard Enumerated types */
@@ -133,6 +138,10 @@
LVM_FS_32000 = 6,
LVM_FS_44100 = 7,
LVM_FS_48000 = 8,
+#ifdef HIGHER_FS
+ LVM_FS_96000 = 9,
+ LVM_FS_192000 = 10,
+#endif
LVM_FS_INVALID = LVM_MAXENUM-1,
LVM_FS_DUMMY = LVM_MAXENUM
} LVM_Fs_en;
diff --git a/media/libeffects/lvm/lib/Common/lib/Mixer.h b/media/libeffects/lvm/lib/Common/lib/Mixer.h
index 89deb0d..07c53cd 100644
--- a/media/libeffects/lvm/lib/Common/lib/Mixer.h
+++ b/media/libeffects/lvm/lib/Common/lib/Mixer.h
@@ -30,6 +30,43 @@
INSTANCE MEMORY TYPE DEFINITION
***********************************************************************************/
+#ifdef BUILD_FLOAT /* BUILD_FLOAT*/
+typedef struct
+{
+ LVM_FLOAT Alpha; /* Time constant. Set by calling application. \
+ Can be changed at any time */
+ LVM_FLOAT Target; /* Target value. Set by calling application. \
+ Can be changed at any time */
+ LVM_FLOAT Current; /* Current value. Set by the mixer function. */
+ LVM_INT16 CallbackSet; /* Boolean. Should be set by calling application \
+ each time the target value is updated */
+ LVM_INT16 CallbackParam; /* Parameter that will be used in the calback function */
+ void *pCallbackHandle; /* Pointer to the instance of the callback function */
+ void *pGeneralPurpose; /* Pointer for general purpose usage */
+ LVM_Callback pCallBack; /* Pointer to the callback function */
+} Mix_1St_Cll_FLOAT_t;
+typedef struct
+{
+ LVM_FLOAT Alpha1;
+ LVM_FLOAT Target1;
+ LVM_FLOAT Current1;
+ LVM_INT16 CallbackSet1;
+ LVM_INT16 CallbackParam1;
+ void *pCallbackHandle1;
+ void *pGeneralPurpose1;
+ LVM_Callback pCallBack1;
+
+ LVM_FLOAT Alpha2; /* Warning the address of this location is passed as a \
+ pointer to Mix_1St_Cll_t in some functions */
+ LVM_FLOAT Target2;
+ LVM_FLOAT Current2;
+ LVM_INT16 CallbackSet2;
+ LVM_INT16 CallbackParam2;
+ void *pCallbackHandle2;
+ void *pGeneralPurpose2;
+ LVM_Callback pCallBack2;
+} Mix_2St_Cll_FLOAT_t;
+#else
typedef struct
{
LVM_INT32 Alpha; /* Time constant. Set by calling application. Can be changed at any time */
@@ -64,9 +101,35 @@
} Mix_2St_Cll_t;
+#endif
/*** General functions ************************************************************/
+#ifdef BUILD_FLOAT
+LVM_FLOAT LVM_Mixer_TimeConstant(LVM_UINT32 tc,
+#ifdef HIGHER_FS
+ LVM_UINT32 Fs,
+#else
+ LVM_UINT16 Fs,
+#endif
+ LVM_UINT16 NumChannels);
+
+void MixSoft_1St_D32C31_WRA( Mix_1St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+
+void MixSoft_2St_D32C31_SAT( Mix_2St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src1,
+ const LVM_FLOAT *src2,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+
+void MixInSoft_D32C31_SAT( Mix_1St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
LVM_UINT32 LVM_Mixer_TimeConstant(LVM_UINT32 tc,
LVM_UINT16 Fs,
LVM_UINT16 NumChannels);
@@ -88,10 +151,26 @@
LVM_INT32 *dst,
LVM_INT16 n);
+#endif
+
/**********************************************************************************
FUNCTION PROTOTYPES (LOW LEVEL SUBFUNCTIONS)
***********************************************************************************/
-
+#ifdef BUILD_FLOAT
+void Core_MixSoft_1St_D32C31_WRA( Mix_1St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+void Core_MixHard_2St_D32C31_SAT( Mix_2St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src1,
+ const LVM_FLOAT *src2,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+void Core_MixInSoft_D32C31_SAT( Mix_1St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
void Core_MixSoft_1St_D32C31_WRA( Mix_1St_Cll_t *pInstance,
const LVM_INT32 *src,
LVM_INT32 *dst,
@@ -107,6 +186,7 @@
const LVM_INT32 *src,
LVM_INT32 *dst,
LVM_INT16 n);
+#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
@@ -115,13 +195,3 @@
/**********************************************************************************/
#endif /* __MIXER_H__ */
-
-
-
-
-
-
-
-
-
-
diff --git a/media/libeffects/lvm/lib/Common/lib/ScalarArithmetic.h b/media/libeffects/lvm/lib/Common/lib/ScalarArithmetic.h
index 3d62704..cdb3837 100644
--- a/media/libeffects/lvm/lib/Common/lib/ScalarArithmetic.h
+++ b/media/libeffects/lvm/lib/Common/lib/ScalarArithmetic.h
@@ -34,7 +34,12 @@
/*######################################################################################*/
/* Absolute value including the corner case for the extreme negative value */
+
+#ifdef BUILD_FLOAT
+LVM_FLOAT Abs_Float(LVM_FLOAT input);
+#else
LVM_INT32 Abs_32(LVM_INT32 input);
+#endif
/****************************************************************************************
* Name : dB_to_Lin32()
@@ -48,8 +53,11 @@
* (15->01) = decimal part
* Returns : Lin value format 1.16.15
****************************************************************************************/
-
+#ifdef BUILD_FLOAT
+LVM_FLOAT dB_to_LinFloat(LVM_INT16 db_fix);
+#else
LVM_INT32 dB_to_Lin32(LVM_INT16 db_fix);
+#endif
#ifdef __cplusplus
}
diff --git a/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h b/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
index 2b791bd..0ba20a3 100644
--- a/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
+++ b/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
@@ -29,6 +29,11 @@
VARIOUS FUNCTIONS
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void LoadConst_Float( const LVM_FLOAT val,
+ LVM_FLOAT *dst,
+ LVM_INT16 n );
+#else
void LoadConst_16( const LVM_INT16 val,
LVM_INT16 *dst,
LVM_INT16 n );
@@ -36,10 +41,17 @@
void LoadConst_32( const LVM_INT32 val,
LVM_INT32 *dst,
LVM_INT16 n );
+#endif
+#ifdef BUILD_FLOAT
+void Copy_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n );
+#else
void Copy_16( const LVM_INT16 *src,
LVM_INT16 *dst,
LVM_INT16 n );
+#endif
/*********************************************************************************
* note: In Mult3s_16x16() saturation of result is not taken care when *
@@ -49,10 +61,17 @@
* This is the only case which will give wrong result. *
* For more information refer to Vector_Arithmetic.doc in /doc folder *
*********************************************************************************/
+#ifdef BUILD_FLOAT
+void Mult3s_Float( const LVM_FLOAT *src,
+ const LVM_FLOAT val,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
void Mult3s_16x16( const LVM_INT16 *src,
const LVM_INT16 val,
- LVM_INT16 *dst,
- LVM_INT16 n);
+ LVM_INT16 *dst,
+ LVM_INT16 n);
+#endif
/*********************************************************************************
* note: In Mult3s_32x16() saturation of result is not taken care when *
@@ -66,20 +85,31 @@
const LVM_INT16 val,
LVM_INT32 *dst,
LVM_INT16 n);
-
+#ifdef BUILD_FLOAT
+void DelayMix_Float(const LVM_FLOAT *src, /* Source 1, to be delayed */
+ LVM_FLOAT *delay, /* Delay buffer */
+ LVM_INT16 size, /* Delay size */
+ LVM_FLOAT *dst, /* Source/destination */
+ LVM_INT16 *pOffset, /* Delay offset */
+ LVM_INT16 n) ; /* Number of stereo samples */
+#else
void DelayMix_16x16( const LVM_INT16 *src,
LVM_INT16 *delay,
LVM_INT16 size,
LVM_INT16 *dst,
LVM_INT16 *pOffset,
LVM_INT16 n);
-
+#endif
void DelayWrite_32( const LVM_INT32 *src, /* Source 1, to be delayed */
LVM_INT32 *delay, /* Delay buffer */
LVM_UINT16 size, /* Delay size */
LVM_UINT16 *pOffset, /* Delay offset */
LVM_INT16 n);
-
+#ifdef BUILD_FLOAT
+void Add2_Sat_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n );
+#else
void Add2_Sat_16x16( const LVM_INT16 *src,
LVM_INT16 *dst,
LVM_INT16 n );
@@ -87,7 +117,13 @@
void Add2_Sat_32x32( const LVM_INT32 *src,
LVM_INT32 *dst,
LVM_INT16 n );
-
+#endif
+#ifdef BUILD_FLOAT
+void Mac3s_Sat_Float( const LVM_FLOAT *src,
+ const LVM_FLOAT val,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
void Mac3s_Sat_16x16( const LVM_INT16 *src,
const LVM_INT16 val,
LVM_INT16 *dst,
@@ -97,7 +133,7 @@
const LVM_INT16 val,
LVM_INT32 *dst,
LVM_INT16 n);
-
+#endif
void DelayAllPass_Sat_32x16To32( LVM_INT32 *delay, /* Delay buffer */
LVM_UINT16 size, /* Delay size */
LVM_INT16 coeff, /* All pass filter coefficient */
@@ -109,7 +145,12 @@
/**********************************************************************************
SHIFT FUNCTIONS
***********************************************************************************/
-
+#ifdef BUILD_FLOAT
+void Shift_Sat_Float (const LVM_INT16 val,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
void Shift_Sat_v16xv16 ( const LVM_INT16 val,
const LVM_INT16 *src,
LVM_INT16 *dst,
@@ -119,11 +160,15 @@
const LVM_INT32 *src,
LVM_INT32 *dst,
LVM_INT16 n);
-
+#endif
/**********************************************************************************
AUDIO FORMAT CONVERSION FUNCTIONS
***********************************************************************************/
-
+#ifdef BUILD_FLOAT
+void MonoTo2I_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
void MonoTo2I_16( const LVM_INT16 *src,
LVM_INT16 *dst,
LVM_INT16 n);
@@ -131,29 +176,52 @@
void MonoTo2I_32( const LVM_INT32 *src,
LVM_INT32 *dst,
LVM_INT16 n);
-
+#endif
+#ifdef BUILD_FLOAT
+void From2iToMono_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
void From2iToMono_32( const LVM_INT32 *src,
LVM_INT32 *dst,
LVM_INT16 n);
-
+#endif
+#ifdef BUILD_FLOAT
+void MSTo2i_Sat_Float( const LVM_FLOAT *srcM,
+ const LVM_FLOAT *srcS,
+ LVM_FLOAT *dst,
+ LVM_INT16 n );
+#else
void MSTo2i_Sat_16x16( const LVM_INT16 *srcM,
const LVM_INT16 *srcS,
LVM_INT16 *dst,
LVM_INT16 n );
-
+#endif
+#ifdef BUILD_FLOAT
+void From2iToMS_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dstM,
+ LVM_FLOAT *dstS,
+ LVM_INT16 n );
+#else
void From2iToMS_16x16( const LVM_INT16 *src,
LVM_INT16 *dstM,
LVM_INT16 *dstS,
LVM_INT16 n );
-
+#endif
+#ifdef BUILD_FLOAT
+void JoinTo2i_Float( const LVM_FLOAT *srcL,
+ const LVM_FLOAT *srcR,
+ LVM_FLOAT *dst,
+ LVM_INT16 n );
+#else
void From2iToMono_16( const LVM_INT16 *src,
LVM_INT16 *dst,
LVM_INT16 n);
-
void JoinTo2i_32x32( const LVM_INT32 *srcL,
const LVM_INT32 *srcR,
- LVM_INT32 *dst,
- LVM_INT16 n );
+ LVM_INT32 *dst,
+ LVM_INT16 n );
+#endif
/**********************************************************************************
DATA TYPE CONVERSION FUNCTIONS
diff --git a/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c b/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c
index 920b515..fa9f01f 100644
--- a/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c
+++ b/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c
@@ -33,7 +33,10 @@
#define VOL_TC_SHIFT 21 /* As a power of 2 */
#define DECAY_SHIFT 10 /* As a power of 2 */
-
+#ifdef BUILD_FLOAT
+#define VOL_TC_FLOAT 2.0f /* As a power of 2 */
+#define DECAY_FAC_FLOAT 64.0f /* As a power of 2 */
+#endif
/****************************************************************************************/
/* */
@@ -69,7 +72,7 @@
/* NOTES: */
/* */
/****************************************************************************************/
-
+#ifndef BUILD_FLOAT
void AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_D32_t *pInstance, /* Instance pointer */
const LVM_INT32 *pStSrc, /* Stereo source */
const LVM_INT32 *pMonoSrc, /* Mono source */
@@ -193,4 +196,113 @@
return;
}
+#else
+void AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t *pInstance, /* Instance pointer */
+ const LVM_FLOAT *pStSrc, /* Stereo source */
+ const LVM_FLOAT *pMonoSrc, /* Mono source */
+ LVM_FLOAT *pDst, /* Stereo destination */
+ LVM_UINT16 NumSamples) /* Number of samples */
+{
+ /*
+ * General variables
+ */
+ LVM_UINT16 i; /* Sample index */
+ LVM_FLOAT Left; /* Left sample */
+ LVM_FLOAT Right; /* Right sample */
+ LVM_FLOAT Mono; /* Mono sample */
+ LVM_FLOAT AbsPeak; /* Absolute peak signal */
+ LVM_FLOAT AGC_Mult; /* Short AGC gain */
+ LVM_FLOAT Vol_Mult; /* Short volume */
+
+
+ /*
+ * Instance control variables
+ */
+ LVM_FLOAT AGC_Gain = pInstance->AGC_Gain; /* Get the current AGC gain */
+ LVM_FLOAT AGC_MaxGain = pInstance->AGC_MaxGain; /* Get maximum AGC gain */
+ LVM_FLOAT AGC_Attack = pInstance->AGC_Attack; /* Attack scaler */
+ LVM_FLOAT AGC_Decay = (pInstance->AGC_Decay * (1 << (DECAY_SHIFT)));/* Decay scaler */
+ LVM_FLOAT AGC_Target = pInstance->AGC_Target; /* Get the target level */
+ LVM_FLOAT Vol_Current = pInstance->Volume; /* Actual volume setting */
+ LVM_FLOAT Vol_Target = pInstance->Target; /* Target volume setting */
+ LVM_FLOAT Vol_TC = pInstance->VolumeTC; /* Time constant */
+
+
+ /*
+ * Process on a sample by sample basis
+ */
+ for (i = 0; i < NumSamples; i++) /* For each sample */
+ {
+
+ /*
+ * Get the short scalers
+ */
+ AGC_Mult = (LVM_FLOAT)(AGC_Gain); /* Get the short AGC gain */
+ Vol_Mult = (LVM_FLOAT)(Vol_Current); /* Get the short volume gain */
+
+
+ /*
+ * Get the input samples
+ */
+ Left = *pStSrc++; /* Get the left sample */
+ Right = *pStSrc++; /* Get the right sample */
+ Mono = *pMonoSrc++; /* Get the mono sample */
+
+
+ /*
+ * Apply the AGC gain to the mono input and mix with the stereo signal
+ */
+ Left += (Mono * AGC_Mult); /* Mix in the mono signal */
+ Right += (Mono * AGC_Mult);
+
+ /*
+ * Apply the volume and write to the output stream
+ */
+ Left = Left * Vol_Mult;
+ Right = Right * Vol_Mult;
+ *pDst++ = Left; /* Save the results */
+ *pDst++ = Right;
+
+ /*
+ * Update the AGC gain
+ */
+ AbsPeak = Abs_Float(Left) > Abs_Float(Right) ? Abs_Float(Left) : Abs_Float(Right);
+ if (AbsPeak > AGC_Target)
+ {
+ /*
+ * The signal is too large so decrease the gain
+ */
+ AGC_Gain = AGC_Gain * AGC_Attack;
+ }
+ else
+ {
+ /*
+ * The signal is too small so increase the gain
+ */
+ if (AGC_Gain > AGC_MaxGain)
+ {
+ AGC_Gain -= (AGC_Decay);
+ }
+ else
+ {
+ AGC_Gain += (AGC_Decay);
+ }
+ }
+
+ /*
+ * Update the gain
+ */
+ Vol_Current += (Vol_Target - Vol_Current) * ((LVM_FLOAT)Vol_TC / VOL_TC_FLOAT);
+ }
+
+
+ /*
+ * Update the parameters
+ */
+ pInstance->Volume = Vol_Current; /* Actual volume setting */
+ pInstance->AGC_Gain = AGC_Gain;
+
+ return;
+}
+#endif /*BUILD_FLOAT*/
diff --git a/media/libeffects/lvm/lib/Common/src/Abs_32.c b/media/libeffects/lvm/lib/Common/src/Abs_32.c
index 9128b82..84fabd8 100644
--- a/media/libeffects/lvm/lib/Common/src/Abs_32.c
+++ b/media/libeffects/lvm/lib/Common/src/Abs_32.c
@@ -47,4 +47,14 @@
}
return input;
}
-
+#ifdef BUILD_FLOAT
+LVM_FLOAT Abs_Float(LVM_FLOAT input)
+{
+ if(input < 0)
+ {
+ /* Negative input, so invert */
+ input = (LVM_FLOAT)(-input);
+ }
+ return input;
+}
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/Add2_Sat_32x32.c b/media/libeffects/lvm/lib/Common/src/Add2_Sat_32x32.c
index 69d357e..e3edccc 100644
--- a/media/libeffects/lvm/lib/Common/src/Add2_Sat_32x32.c
+++ b/media/libeffects/lvm/lib/Common/src/Add2_Sat_32x32.c
@@ -57,4 +57,33 @@
return;
}
+#ifdef BUILD_FLOAT
+void Add2_Sat_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n )
+{
+ LVM_FLOAT Temp;
+ LVM_INT16 ii;
+ for (ii = n; ii != 0; ii--)
+ {
+ Temp = ((LVM_FLOAT) *src) + ((LVM_FLOAT) *dst);
+ src++;
+
+ if (Temp > 1.000000f)
+ {
+ *dst = 1.000000f;
+ }
+ else if (Temp < -1.000000f)
+ {
+ *dst = -1.000000f;
+ }
+ else
+ {
+ *dst = Temp;
+ }
+ dst++;
+ }
+ return;
+}
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16C14_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16C14_TRC_WRA_01.c
index f4c5757..88f9986 100644
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16C14_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16C14_TRC_WRA_01.c
@@ -33,7 +33,51 @@
pBiquadState->pDelays[2] is y(n-1)L in Q0 format
pBiquadState->pDelays[3] is y(n-2)L in Q0 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void BP_1I_D16F16C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+
+ {
+ LVM_FLOAT ynL;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL= (A0 * (x(n)L - x(n-2)L ) )
+ ynL = pBiquadState->coefs[0] * ((*pDataIn)-pBiquadState->pDelays[1]);
+
+ // ynL+= ((-B2 * y(n-2)L ) )
+ ynL += pBiquadState->coefs[1] * pBiquadState->pDelays[3];
+
+ // ynL+= ((-B1 * y(n-1)L ) )
+ ynL += pBiquadState->coefs[2] * pBiquadState->pDelays[2];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[2] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++=ynL; // Write Left output
+
+ }
+
+ }
+#else
void BP_1I_D16F16C14_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
@@ -78,4 +122,5 @@
}
}
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.c
index 88914ad..27ab57a 100644
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.c
@@ -38,6 +38,19 @@
/* RETURNS: */
/* void return code */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+void BP_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BP_FLOAT_Coefs_t *pCoef)
+{
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
+
+ pBiquadState->coefs[0] = pCoef->A0;
+ pBiquadState->coefs[1] = pCoef->B2;
+ pBiquadState->coefs[2] = pCoef->B1;
+}
+#else
void BP_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_1I_Order2_Taps_t *pTaps,
BP_C16_Coefs_t *pCoef)
@@ -49,6 +62,7 @@
pBiquadState->coefs[1]=pCoef->B2;
pBiquadState->coefs[2]=pCoef->B1;
}
+#endif
/*-------------------------------------------------------------------------*/
/* End Of File: BP_1I_D16F16Css_TRC_WRA_01_Init.c */
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Private.h
index 980539c..e194f92 100644
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Private.h
@@ -27,4 +27,13 @@
typedef Filter_State * PFilter_State ;
+#ifdef BUILD_FLOAT
+typedef struct _Filter_State_FLOAT
+{
+
+ LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
+ LVM_FLOAT coefs[3]; /* pointer to the filter coefficients */
+}Filter_State_FLOAT;
+typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
+#endif
#endif /*_BP_1I_D16F16CSS_TRC_WRA_01_PRIVATE_H_*/
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32C30_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32C30_TRC_WRA_01.c
index ba1a42f..3abdd43 100644
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32C30_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32C30_TRC_WRA_01.c
@@ -33,7 +33,48 @@
pBiquadState->pDelays[2] is y(n-1)L in Q16 format
pBiquadState->pDelays[3] is y(n-2)L in Q16 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void BP_1I_D16F32C30_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+{
+ LVM_FLOAT ynL,templ;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT)pInstance;
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL= (A0 * (x(n)L - x(n-2)L ))
+ templ = (LVM_FLOAT) *pDataIn - pBiquadState->pDelays[1];
+ ynL = pBiquadState->coefs[0] * templ;
+
+ // ynL+= ((-B2 * y(n-2)L ) )
+ templ = pBiquadState->coefs[1] * pBiquadState->pDelays[3];
+ ynL += templ;
+
+ // ynL+= ((-B1 * y(n-1)L ))
+ templ = pBiquadState->coefs[2] * pBiquadState->pDelays[2];
+ ynL += templ;
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[2] = ynL; // Update y(n-1)L in Q16
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L in Q0
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (ynL); // Write Left output
+ }
+}
+#else
void BP_1I_D16F32C30_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
@@ -80,4 +121,4 @@
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.c
index e833218..d6e047a 100644
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.c
@@ -48,6 +48,20 @@
/* RETURNS: */
/* void return code */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+void BP_1I_D16F32Cll_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BP_FLOAT_Coefs_t *pCoef)
+{
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays =(LVM_FLOAT *) pTaps;
+
+
+ pBiquadState->coefs[0] = pCoef->A0;
+ pBiquadState->coefs[1] = pCoef->B2;
+ pBiquadState->coefs[2] = pCoef->B1;
+}
+#else
void BP_1I_D16F32Cll_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_1I_Order2_Taps_t *pTaps,
BP_C32_Coefs_t *pCoef)
@@ -59,6 +73,7 @@
pBiquadState->coefs[1] = pCoef->B2;
pBiquadState->coefs[2] = pCoef->B1;
}
+#endif
/*-------------------------------------------------------------------------*/
/* End Of File: BP_1I_D16F32Cll_TRC_WRA_01_Init.c */
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Private.h
index 9cca627..aa9e669 100644
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Private.h
@@ -26,5 +26,12 @@
}Filter_State;
typedef Filter_State * PFilter_State ;
-
+#ifdef BUILD_FLOAT
+typedef struct _Filter_State_FLOAT
+{
+ LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
+ LVM_FLOAT coefs[3]; /* pointer to the filter coefficients */
+}Filter_State_Float;
+typedef Filter_State_Float * PFilter_State_FLOAT ;
+#endif
#endif /*_BP_1I_D16F32CLL_TRC_WRA_01_PRIVATE_H_*/
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32C30_TRC_WRA_02.c b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32C30_TRC_WRA_02.c
index b09c1aa..abdb2f7 100644
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32C30_TRC_WRA_02.c
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32C30_TRC_WRA_02.c
@@ -33,7 +33,52 @@
pBiquadState->pDelays[2] is y(n-1)L in Q0 format
pBiquadState->pDelays[3] is y(n-2)L in Q0 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void BP_1I_D32F32C30_TRC_WRA_02 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,templ;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL= (A0 * (x(n)L - x(n-2)L ) )
+ templ = (*pDataIn) - pBiquadState->pDelays[1];
+ ynL = pBiquadState->coefs[0] * templ;
+
+ // ynL+= ((-B2 * y(n-2)L ) )
+ templ = pBiquadState->coefs[1] * pBiquadState->pDelays[3];
+ ynL += templ;
+
+ // ynL+= ((-B1 * y(n-1)L ) )
+ templ = pBiquadState->coefs[2] * pBiquadState->pDelays[2];
+ ynL += templ;
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[2] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = ynL; // Write Left output in Q0
+
+ }
+
+ }
+#else
void BP_1I_D32F32C30_TRC_WRA_02 ( Biquad_Instance_t *pInstance,
LVM_INT32 *pDataIn,
LVM_INT32 *pDataOut,
@@ -78,4 +123,4 @@
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.c b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.c
index 9367912..5590c32 100644
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.c
@@ -37,6 +37,21 @@
/* RETURNS: */
/* void return code */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+void BP_1I_D32F32Cll_TRC_WRA_02_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BP_FLOAT_Coefs_t *pCoef)
+{
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays =(LVM_FLOAT *) pTaps;
+
+ pBiquadState->coefs[0] = pCoef->A0;
+
+ pBiquadState->coefs[1] = pCoef->B2;
+
+ pBiquadState->coefs[2] = pCoef->B1;
+}
+#else
void BP_1I_D32F32Cll_TRC_WRA_02_Init ( Biquad_Instance_t *pInstance,
Biquad_1I_Order2_Taps_t *pTaps,
BP_C32_Coefs_t *pCoef)
@@ -50,6 +65,7 @@
pBiquadState->coefs[2]=pCoef->B1;
}
+#endif
/*-------------------------------------------------------------------------*/
/* End Of File: BP_1I_D32F32Cll_TRC_WRA_02_Init.c */
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Private.h b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Private.h
index 5cc1ce2..80c3920 100644
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Private.h
@@ -26,5 +26,13 @@
}Filter_State;
typedef Filter_State * PFilter_State ;
+#ifdef BUILD_FLOAT
+typedef struct _Filter_State_FLOAT
+{
+ LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
+ LVM_FLOAT coefs[3]; /* pointer to the filter coefficients */
+}Filter_State_Float;
+typedef Filter_State_Float* PFilter_State_FLOAT ;
+#endif
#endif /*_BP_1I_D32F32CLL_TRC_WRA_02_PRIVATE_H_*/
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16C15_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16C15_TRC_WRA_01.c
index f2f8c6b..ee9bf7a 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16C15_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16C15_TRC_WRA_01.c
@@ -32,7 +32,56 @@
pBiquadState->pDelays[2] is y(n-1)L in Q0 format
pBiquadState->pDelays[3] is y(n-2)L in Q0 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void BQ_1I_D16F16C15_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL=A2 * x(n-2)L
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[1];
+
+ // ynL+=A1 * x(n-1)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ // ynL+=A0 * x(n)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ // ynL+= (-B2 * y(n-2)L )
+ ynL += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[3];
+
+ // ynL+= (-B1 * y(n-1)L )
+ ynL += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[2];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[2] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output in Q0
+
+
+ }
+
+ }
+#else
void BQ_1I_D16F16C15_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
@@ -82,4 +131,4 @@
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.c
index baf0c1a..3d5befa 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.c
@@ -37,6 +37,26 @@
/* RETURNS: */
/* void return code */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+void BQ_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps ;
+ temp = pCoef->A2;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A1;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[2] = temp;
+ temp = pCoef->B2;
+ pBiquadState->coefs[3] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[4] = temp;
+}
+#else
void BQ_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_1I_Order2_Taps_t *pTaps,
BQ_C16_Coefs_t *pCoef)
@@ -56,6 +76,7 @@
temp=pCoef->B1;
pBiquadState->coefs[4]=temp;
}
+#endif
/*-------------------------------------------------------------------------*/
/* End Of File: BQ_1I_D16F16Css_TRC_WRA_01_Init.c */
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Private.h
index 909c699..811da8b 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Private.h
@@ -27,4 +27,13 @@
typedef Filter_State * PFilter_State ;
+#ifdef BUILD_FLOAT
+typedef struct _Filter_State_FLOAT
+{
+ LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
+ LVM_FLOAT coefs[5]; /* pointer to the filter coefficients */
+
+}Filter_State_FLOAT;
+typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
+#endif
#endif /*_BQ_1I_D16F16CSS_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32C14_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32C14_TRC_WRA_01.c
index 92f6caf..c74a137 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32C14_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32C14_TRC_WRA_01.c
@@ -32,7 +32,54 @@
pBiquadState->pDelays[2] is y(n-1)L in Q16 format
pBiquadState->pDelays[3] is y(n-2)L in Q16 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void BQ_1I_D16F32C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL=A2 * x(n-2)L
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[1];
+
+ // ynL+=A1 * x(n-1)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ // ynL+=A0 * x(n)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ // ynL+= ( (-B2 * y(n-2)L )
+ ynL += pBiquadState->pDelays[3] * pBiquadState->coefs[3];
+
+ // ynL+= -B1 * y(n-1)L
+ ynL += pBiquadState->pDelays[2] * pBiquadState->coefs[4];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[2] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (LVM_FLOAT)(ynL); // Write Left output
+
+ }
+ }
+#else
void BQ_1I_D16F32C14_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
@@ -81,4 +128,4 @@
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_Private.h
index aea10f0..9812274 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_Private.h
@@ -27,4 +27,13 @@
typedef Filter_State * PFilter_State ;
+#ifdef BUILD_FLOAT
+typedef struct _Filter_State_FLOAT
+{
+ LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
+ LVM_FLOAT coefs[5]; /* pointer to the filter coefficients */
+
+}Filter_State_FLOAT;
+typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
+#endif
#endif /*_BQ_1I_D16F32CSS_TRC_WRA_01_PRIVATE_H_*/
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.c b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.c
index 1d6be4e..feae20d 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.c
@@ -38,6 +38,27 @@
/* RETURNS: */
/* void return code */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+void BQ_1I_D16F32Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *)pTaps;
+
+ temp = pCoef->A2;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A1;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[2] = temp;
+ temp = pCoef->B2;
+ pBiquadState->coefs[3] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[4] = temp;
+}
+#else
void BQ_1I_D16F32Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_1I_Order2_Taps_t *pTaps,
BQ_C16_Coefs_t *pCoef)
@@ -57,6 +78,7 @@
temp=pCoef->B1;
pBiquadState->coefs[4]=temp;
}
+#endif
/*-------------------------------------------------------------------------*/
/* End Of File: BQ_1I_D16F32Css_TRC_WRA_01_Init */
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C14_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C14_TRC_WRA_01.c
index 972e704..9b0fde3 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C14_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C14_TRC_WRA_01.c
@@ -37,7 +37,81 @@
pBiquadState->pDelays[6] is y(n-2)L in Q0 format
pBiquadState->pDelays[7] is y(n-2)R in Q0 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F16C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL=A2 * x(n-2)L
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+ // ynL+=A1 * x(n-1)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ // ynL+=A0 * x(n)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ // ynL+= ( -B2 * y(n-2)L )
+ ynL += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[6];
+
+ // ynL+=( -B1 * y(n-1)L )
+ ynL += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[4];
+
+
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ // ynR=A2 * x(n-2)R
+ ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
+
+ // ynR+=A1 * x(n-1)R
+ ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
+
+ // ynR+=A0 * x(n)R
+ ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
+
+ // ynR+= ( -B2 * y(n-2)R )
+ ynR += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[7];
+
+ // ynR+=( -B1 * y(n-1)R )
+ ynR += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[5];
+
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; // y(n-2)R=y(n-1)R
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; // x(n-2)R=x(n-1)R
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[5] = ynR; // Update y(n-1)R
+ pBiquadState->pDelays[4] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+ pBiquadState->pDelays[1] = (*pDataIn++); // Update x(n-1)R
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output
+ *pDataOut++ = (LVM_FLOAT)ynR; // Write Right ouput
+
+
+ }
+
+ }
+#else
void BQ_2I_D16F16C14_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
@@ -112,3 +186,4 @@
}
+#endif
\ No newline at end of file
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C15_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C15_TRC_WRA_01.c
index e056373..f24db8f 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C15_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C15_TRC_WRA_01.c
@@ -37,7 +37,81 @@
pBiquadState->pDelays[6] is y(n-2)L in Q0 format
pBiquadState->pDelays[7] is y(n-2)R in Q0 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F16C15_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL=A2 * x(n-2)L
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+ // ynL+=A1 * x(n-1)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ // ynL+=A0 * x(n)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ // ynL+= ( -B2 * y(n-2)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[6];
+
+ // ynL+=( -B1 * y(n-1)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[4];
+
+
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ // ynR=A2 * x(n-2)R
+ ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
+
+ // ynR+=A1 * x(n-1)R
+ ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
+
+ // ynR+=A0 * x(n)R
+ ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
+
+ // ynR+= ( -B2 * y(n-2)R )
+ ynR += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[7];
+
+ // ynR+=( -B1 * y(n-1)R )
+ ynR += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[5];
+
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; // y(n-2)R=y(n-1)R
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; // x(n-2)R=x(n-1)R
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[5] = ynR; // Update y(n-1)R
+ pBiquadState->pDelays[4] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+ pBiquadState->pDelays[1] = (*pDataIn++); // Update x(n-1)R
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output
+ *pDataOut++ = (LVM_FLOAT)ynR; // Write Right ouput
+
+ }
+
+ }
+#else
void BQ_2I_D16F16C15_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
@@ -111,4 +185,4 @@
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.c
index 0a8ac35..39e1bda 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.c
@@ -38,6 +38,27 @@
/* RETURNS: */
/* void return code */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F16Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps ;
+
+ temp = pCoef->A2;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A1;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[2] = temp;
+ temp = pCoef->B2;
+ pBiquadState->coefs[3] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[4] = temp;
+}
+#else
void BQ_2I_D16F16Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_2I_Order2_Taps_t *pTaps,
BQ_C16_Coefs_t *pCoef)
@@ -57,6 +78,7 @@
temp=pCoef->B1;
pBiquadState->coefs[4]=temp;
}
+#endif
/*-------------------------------------------------------------------------*/
/* End Of File: BQ_2I_D16F16Css_TRC_WRA_01_Init.c */
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Private.h
index 7d42ced..0691b8c 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Private.h
@@ -28,4 +28,14 @@
typedef Filter_State * PFilter_State ;
+#ifdef BUILD_FLOAT
+typedef struct _Filter_State_FLOAT
+{
+ LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
+ LVM_FLOAT coefs[5]; /* pointer to the filter coefficients */
+
+}Filter_State_FLOAT;
+typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
+#endif
+
#endif /* _BQ_2I_D16F16CSS_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C13_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C13_TRC_WRA_01.c
index 4a0cce4..61c07c7 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C13_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C13_TRC_WRA_01.c
@@ -37,7 +37,79 @@
pBiquadState->pDelays[6] is y(n-2)L in Q16 format
pBiquadState->pDelays[7] is y(n-2)R in Q16 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F32C13_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ /* ynL=A2 * x(n-2)L */
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+ /* ynL+=A1* x(n-1)L */
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ /* ynL+=A0* x(n)L */
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ /* ynL+=-B2*y(n-2)L */
+ ynL += pBiquadState->pDelays[6] * pBiquadState->coefs[3];
+
+ /* ynL+=-B1*y(n-1)L */
+ ynL += pBiquadState->pDelays[4] * pBiquadState->coefs[4];
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ /* ynR=A2 * x(n-2)R */
+ ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
+
+ /* ynR+=A1* x(n-1)R */
+ ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
+
+ /* ynR+=A0* x(n)R */
+ ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
+
+ /* ynR+=-B2 * y(n-2)R */
+ ynR += pBiquadState->pDelays[7] * pBiquadState->coefs[3];
+
+ /* ynR+=-B1 * y(n-1)R */
+ ynR += pBiquadState->pDelays[5] * pBiquadState->coefs[4];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
+ pBiquadState->pDelays[5] = ynR; /* Update y(n-1)R */
+ pBiquadState->pDelays[4] = ynL; /* Update y(n-1)L */
+ pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L */
+ pDataIn++;
+ pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R */
+ pDataIn++;
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut = (LVM_FLOAT)(ynL); /* Write Left output */
+ pDataOut++;
+ *pDataOut = (LVM_FLOAT)(ynR); /* Write Right ouput */
+ pDataOut++;
+ }
+ }
+#else
void BQ_2I_D16F32C13_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
@@ -115,4 +187,4 @@
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C14_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C14_TRC_WRA_01.c
index 052e2a0..cf19e06 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C14_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C14_TRC_WRA_01.c
@@ -36,7 +36,82 @@
pBiquadState->pDelays[6] is y(n-2)L in Q16 format
pBiquadState->pDelays[7] is y(n-2)R in Q16 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F32C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ /* ynL=A2 * x(n-2)L */
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+ /* ynL+=A1 * x(n-1)L */
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ /* ynL+=A0 * x(n)L */
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ /* ynL+= ( (-B2 * y(n-2)L ))*/
+ ynL += pBiquadState->pDelays[6] * pBiquadState->coefs[3];
+
+
+ /* ynL+=( (-B1 * y(n-1)L )) */
+ ynL += pBiquadState->pDelays[4] * pBiquadState->coefs[4];
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ /* ynR=A2 * x(n-2)R */
+ ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
+
+ /* ynR+=A1 * x(n-1)R */
+ ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
+
+ /* ynR+=A0 * x(n)R */
+ ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
+
+ /* ynR+= ( (-B2 * y(n-2)R ))*/
+ ynR += pBiquadState->pDelays[7] * pBiquadState->coefs[3];
+
+ /* ynR+=( (-B1 * y(n-1)R )) */
+ ynR += pBiquadState->pDelays[5] * pBiquadState->coefs[4];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
+ pBiquadState->pDelays[5] = ynR; /* Update y(n-1)R */
+ pBiquadState->pDelays[4] = ynL; /* Update y(n-1)L */
+ pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L */
+ pDataIn++;
+ pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R */
+ pDataIn++;
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut = (LVM_FLOAT)(ynL); /* Write Left output */
+ pDataOut++;
+ *pDataOut = (LVM_FLOAT)(ynR); /* Write Right ouput */
+ pDataOut++;
+ }
+
+ }
+#else
void BQ_2I_D16F32C14_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
@@ -114,4 +189,4 @@
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C15_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C15_TRC_WRA_01.c
index 8c741e1..2611b19 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C15_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C15_TRC_WRA_01.c
@@ -36,7 +36,84 @@
pBiquadState->pDelays[6] is y(n-2)L in Q16 format
pBiquadState->pDelays[7] is y(n-2)R in Q16 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F32C15_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ /* ynL=A2 * x(n-2)L */
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+ /* ynL+=A1 * x(n-1)L */
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ /* ynL+=A0 * x(n)L */
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ /* ynL+= ( (-B2 * y(n-2)L ) */
+ ynL += pBiquadState->pDelays[6] * pBiquadState->coefs[3];
+
+
+ /* ynL+=( (-B1 * y(n-1)L )) */
+ ynL += pBiquadState->pDelays[4] * pBiquadState->coefs[4];
+
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ /* ynR=A2 * x(n-2)R */
+ ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
+
+ /* ynR+=A1 * x(n-1)R */
+ ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
+
+ /* ynR+=A0 * x(n)R */
+ ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
+
+ /* ynR+= ( (-B2 * y(n-2)R ) */
+ ynR += pBiquadState->pDelays[7] * pBiquadState->coefs[3];
+
+
+ /* ynR+=( (-B1 * y(n-1)R )) in Q15 */
+ ynR += pBiquadState->pDelays[5] * pBiquadState->coefs[4];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
+ pBiquadState->pDelays[5] = ynR; /* Update y(n-1)R*/
+ pBiquadState->pDelays[4] = ynL; /* Update y(n-1)L*/
+ pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L*/
+ pDataIn++;
+ pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R*/
+ pDataIn++;
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut = (LVM_FLOAT)(ynL); /* Write Left output*/
+ pDataOut++;
+ *pDataOut = (LVM_FLOAT)(ynR); /* Write Right ouput*/
+ pDataOut++;
+ }
+
+ }
+#else
void BQ_2I_D16F32C15_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
@@ -114,4 +191,4 @@
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_Private.h
index 4f0cf67..c0319c9 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_Private.h
@@ -28,4 +28,14 @@
typedef Filter_State * PFilter_State ;
+#ifdef BUILD_FLOAT
+typedef struct _Filter_State_FLOAT
+{
+ LVM_FLOAT * pDelays; /* pointer to the delayed samples \
+ (data of 32 bits) */
+ LVM_FLOAT coefs[5]; /* pointer to the filter coefficients */
+}Filter_State_FLOAT;
+typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
+#endif
+
#endif /* _BQ_2I_D16F32CSS_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.c
index 4591ee0..4d9bbfe 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.c
@@ -37,6 +37,26 @@
/* RETURNS: */
/* void return code */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+void BQ_2I_D16F32Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
+ temp = pCoef->A2;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A1;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[2] = temp;
+ temp = pCoef->B2;
+ pBiquadState->coefs[3] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[4] = temp;
+}
+#else
void BQ_2I_D16F32Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_2I_Order2_Taps_t *pTaps,
BQ_C16_Coefs_t *pCoef)
@@ -56,6 +76,7 @@
temp=pCoef->B1;
pBiquadState->coefs[4]=temp;
}
+#endif
/*-------------------------------------------------------------------------*/
/* End Of File: BQ_2I_D16F32Css_TRC_WRA_01_Init */
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c
index fd8212e4..960de79 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c
@@ -36,7 +36,94 @@
pBiquadState->pDelays[6] is y(n-2)L in Q0 format
pBiquadState->pDelays[7] is y(n-2)R in Q0 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void BQ_2I_D32F32C30_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+
+ {
+ LVM_FLOAT ynL,ynR,templ,tempd;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ /* ynL= ( A2 * x(n-2)L ) */
+ ynL = pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+ /* ynL+= ( A1 * x(n-1)L )*/
+ templ = pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+ ynL += templ;
+
+ /* ynL+= ( A0 * x(n)L ) */
+ templ = pBiquadState->coefs[2] * (*pDataIn);
+ ynL += templ;
+
+ /* ynL+= (-B2 * y(n-2)L ) */
+ templ = pBiquadState->coefs[3] * pBiquadState->pDelays[6];
+ ynL += templ;
+
+ /* ynL+= (-B1 * y(n-1)L )*/
+ templ = pBiquadState->coefs[4] * pBiquadState->pDelays[4];
+ ynL += templ;
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ /* ynR= ( A2 * x(n-2)R ) */
+ ynR = pBiquadState->coefs[0] * pBiquadState->pDelays[3];
+
+ /* ynR+= ( A1 * x(n-1)R ) */
+ templ = pBiquadState->coefs[1] * pBiquadState->pDelays[1];
+ ynR += templ;
+
+ /* ynR+= ( A0 * x(n)R ) */
+ tempd =* (pDataIn+1);
+ templ = pBiquadState->coefs[2] * tempd;
+ ynR += templ;
+
+ /* ynR+= (-B2 * y(n-2)R ) */
+ templ = pBiquadState->coefs[3] * pBiquadState->pDelays[7];
+ ynR += templ;
+
+ /* ynR+= (-B1 * y(n-1)R ) */
+ templ = pBiquadState->coefs[4] * pBiquadState->pDelays[5];
+ ynR += templ;
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
+ pBiquadState->pDelays[5] = (LVM_FLOAT)ynR; /* Update y(n-1)R */
+ pBiquadState->pDelays[4] = (LVM_FLOAT)ynL; /* Update y(n-1)L */
+ pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L */
+ pDataIn++;
+ pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R */
+ pDataIn++;
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut = (LVM_FLOAT)ynL; /* Write Left output */
+ pDataOut++;
+ *pDataOut = (LVM_FLOAT)ynR; /* Write Right ouput */
+ pDataOut++;
+
+
+ }
+
+ }
+#else
void BQ_2I_D32F32C30_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT32 *pDataIn,
LVM_INT32 *pDataOut,
@@ -123,4 +210,4 @@
}
}
-
+#endif /*BUILD_FLOAT*/
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.c
index 1709f71..fff05ed 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.c
@@ -37,6 +37,26 @@
/* RETURNS: */
/* void return code */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+void BQ_2I_D32F32Cll_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
+ temp = pCoef->A2;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A1;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[2] = temp;
+ temp = pCoef->B2;
+ pBiquadState->coefs[3] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[4] = temp;
+}
+#else
void BQ_2I_D32F32Cll_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
Biquad_2I_Order2_Taps_t *pTaps,
BQ_C32_Coefs_t *pCoef)
@@ -56,6 +76,7 @@
temp=pCoef->B1;
pBiquadState->coefs[4]=temp;
}
+#endif
/*-------------------------------------------------------------------------*/
/* End Of File: BQ_2I_D32F32C32_TRC_WRA_01_Init.c */
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Private.h
index 747af6a..c0f0dcc 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Private.h
@@ -29,4 +29,14 @@
typedef Filter_State * PFilter_State ;
+#ifdef BUILD_FLOAT
+typedef struct _Filter_State_FLOAT
+{
+ LVM_FLOAT * pDelays; /* pointer to the delayed samples \
+ (data of 32 bits) */
+ LVM_FLOAT coefs[5]; /* pointer to the filter coefficients */
+}Filter_State_FLOAT;
+typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
+#endif
+
#endif /* _BQ_2I_D32F32CLL_TRC_WRA_01_PRIVATE_H_*/
diff --git a/media/libeffects/lvm/lib/Common/src/Copy_16.c b/media/libeffects/lvm/lib/Common/src/Copy_16.c
index 20404ad..e489031 100644
--- a/media/libeffects/lvm/lib/Common/src/Copy_16.c
+++ b/media/libeffects/lvm/lib/Common/src/Copy_16.c
@@ -54,5 +54,35 @@
return;
}
+#ifdef BUILD_FLOAT
+void Copy_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n )
+{
+ LVM_INT16 ii;
+ if (src > dst)
+ {
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = *src;
+ dst++;
+ src++;
+ }
+ }
+ else
+ {
+ src += n - 1;
+ dst += n - 1;
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = *src;
+ dst--;
+ src--;
+ }
+ }
+
+ return;
+}
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Core_MixHard_2St_D32C31_SAT.c b/media/libeffects/lvm/lib/Common/src/Core_MixHard_2St_D32C31_SAT.c
index bf69e35..ea98041 100644
--- a/media/libeffects/lvm/lib/Common/src/Core_MixHard_2St_D32C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/Core_MixHard_2St_D32C31_SAT.c
@@ -25,7 +25,37 @@
/**********************************************************************************
FUNCTION CORE_MIXHARD_2ST_D32C31_SAT
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void Core_MixHard_2St_D32C31_SAT( Mix_2St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src1,
+ const LVM_FLOAT *src2,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_FLOAT Temp1,Temp2,Temp3;
+ LVM_INT16 ii;
+ LVM_FLOAT Current1Short;
+ LVM_FLOAT Current2Short;
+ Current1Short = (pInstance->Current1);
+ Current2Short = (pInstance->Current2);
+
+ for (ii = n; ii != 0; ii--){
+ Temp1 = *src1++;
+ Temp3 = Temp1 * Current1Short;
+ Temp2 = *src2++;
+ Temp1 = Temp2 * Current2Short;
+ Temp2 = (Temp1 / 2.0f) + (Temp3 / 2.0f);
+ if (Temp2 > 0.5f)
+ Temp2 = 1.0f;
+ else if (Temp2 < -0.5f )
+ Temp2 = -1.0f;
+ else
+ Temp2 = (Temp2 * 2);
+ *dst++ = Temp2;
+ }
+}
+#else
void Core_MixHard_2St_D32C31_SAT( Mix_2St_Cll_t *pInstance,
const LVM_INT32 *src1,
const LVM_INT32 *src2,
@@ -55,6 +85,5 @@
*dst++ = Temp2;
}
}
-
-
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Core_MixInSoft_D32C31_SAT.c b/media/libeffects/lvm/lib/Common/src/Core_MixInSoft_D32C31_SAT.c
index 3471f05..2814f19 100644
--- a/media/libeffects/lvm/lib/Common/src/Core_MixInSoft_D32C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/Core_MixInSoft_D32C31_SAT.c
@@ -26,6 +26,70 @@
FUNCTION CORE_MIXSOFT_1ST_D32C31_WRA
***********************************************************************************/
+#ifdef BUILD_FLOAT /* BUILD_FLOAT */
+void Core_MixInSoft_D32C31_SAT( Mix_1St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_FLOAT Temp1,Temp2,Temp3;
+ LVM_INT16 OutLoop;
+ LVM_INT16 InLoop;
+ LVM_FLOAT TargetTimesOneMinAlpha;
+ LVM_FLOAT CurrentTimesAlpha;
+ LVM_INT16 ii,jj;
+
+
+ InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
+ OutLoop = (LVM_INT16)(n - (InLoop << 2));
+
+ TargetTimesOneMinAlpha = ((1.0f -pInstance->Alpha) * pInstance->Target);
+ if (pInstance->Target >= pInstance->Current){
+ TargetTimesOneMinAlpha +=(LVM_FLOAT)(2.0f / 2147483647.0f); /* Ceil*/
+ }
+
+ if (OutLoop){
+
+ CurrentTimesAlpha = pInstance->Current * pInstance->Alpha;
+ pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha;
+
+ for (ii = OutLoop; ii != 0; ii--){
+ Temp1 = *src++;
+ Temp2 = *dst;
+
+ Temp3 = Temp1 * (pInstance->Current);
+ Temp1 = Temp2 + Temp3;
+
+ if (Temp1 > 1.0f)
+ Temp1 = 1.0f;
+ else if (Temp1 < -1.0f)
+ Temp1 = -1.0f;
+
+ *dst++ = Temp1;
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--){
+
+ CurrentTimesAlpha = pInstance->Current * pInstance->Alpha;
+ pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha;
+
+ for (jj = 4; jj!=0 ; jj--){
+ Temp1 = *src++;
+ Temp2 = *dst;
+
+ Temp3 = Temp1 * (pInstance->Current);
+ Temp1 = Temp2 + Temp3;
+
+ if (Temp1 > 1.0f)
+ Temp1 = 1.0f;
+ else if (Temp1 < -1.0f)
+ Temp1 = -1.0f;
+ *dst++ = Temp1;
+ }
+ }
+}
+#else
void Core_MixInSoft_D32C31_SAT( Mix_1St_Cll_t *pInstance,
const LVM_INT32 *src,
LVM_INT32 *dst,
@@ -89,6 +153,5 @@
}
}
}
-
-
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Core_MixSoft_1St_D32C31_WRA.c b/media/libeffects/lvm/lib/Common/src/Core_MixSoft_1St_D32C31_WRA.c
index 709c304..814ccee 100644
--- a/media/libeffects/lvm/lib/Common/src/Core_MixSoft_1St_D32C31_WRA.c
+++ b/media/libeffects/lvm/lib/Common/src/Core_MixSoft_1St_D32C31_WRA.c
@@ -25,7 +25,79 @@
/**********************************************************************************
FUNCTION CORE_MIXSOFT_1ST_D32C31_WRA
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void Core_MixSoft_1St_D32C31_WRA( Mix_1St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_FLOAT Temp1,Temp2;
+ LVM_INT16 OutLoop;
+ LVM_INT16 InLoop;
+ LVM_FLOAT TargetTimesOneMinAlpha;
+ LVM_FLOAT CurrentTimesAlpha;
+ LVM_INT16 ii;
+
+ InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
+ OutLoop = (LVM_INT16)(n - (InLoop << 2));
+
+ TargetTimesOneMinAlpha = (1.0f - pInstance->Alpha) * pInstance->Target; /* float * float in float */
+ if (pInstance->Target >= pInstance->Current)
+ {
+ TargetTimesOneMinAlpha += (LVM_FLOAT)(2.0f / 2147483647.0f); /* Ceil*/
+ }
+
+ if (OutLoop != 0)
+ {
+ CurrentTimesAlpha = (pInstance->Current * pInstance->Alpha);
+ pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha;
+
+ for (ii = OutLoop; ii != 0; ii--)
+ {
+ Temp1 = *src;
+ src++;
+
+ Temp2 = Temp1 * (pInstance->Current);
+ *dst = Temp2;
+ dst++;
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--)
+ {
+ CurrentTimesAlpha = pInstance->Current * pInstance->Alpha;
+ pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha;
+
+ Temp1 = *src;
+ src++;
+
+ Temp2 = Temp1 * (pInstance->Current);
+ *dst = Temp2;
+ dst++;
+
+ Temp1 = *src;
+ src++;
+
+ Temp2 = Temp1 * (pInstance->Current);
+ *dst = Temp2;
+ dst++;
+
+ Temp1 = *src;
+ src++;
+
+ Temp2 = Temp1 * (pInstance->Current);
+ *dst = Temp2;
+ dst++;
+
+ Temp1 = *src;
+ src++;
+ Temp2 = Temp1 * (pInstance->Current);
+ *dst = Temp2;
+ dst++;
+ }
+}
+#else
void Core_MixSoft_1St_D32C31_WRA( Mix_1St_Cll_t *pInstance,
const LVM_INT32 *src,
LVM_INT32 *dst,
@@ -98,6 +170,5 @@
dst++;
}
}
-
-
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.c
index 49fa184..d261c9e 100644
--- a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.c
@@ -18,7 +18,53 @@
#include "BIQUAD.h"
#include "DC_2I_D16_TRC_WRA_01_Private.h"
#include "LVM_Macros.h"
+#ifdef BUILD_FLOAT
+void DC_2I_D16_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT LeftDC,RightDC;
+ LVM_FLOAT Diff;
+ LVM_INT32 j;
+ PFilter_FLOAT_State pBiquadState = (PFilter_FLOAT_State) pInstance;
+ LeftDC = pBiquadState->LeftDC;
+ RightDC = pBiquadState->RightDC;
+ for(j = NrSamples-1; j >= 0; j--)
+ {
+ /* Subtract DC an saturate */
+ Diff =* (pDataIn++) - (LeftDC);
+ if (Diff > 1.0f) {
+ Diff = 1.0f; }
+ else if (Diff < -1.0f) {
+ Diff = -1.0f; }
+ *(pDataOut++) = (LVM_FLOAT)Diff;
+ if (Diff < 0) {
+ LeftDC -= DC_FLOAT_STEP; }
+ else {
+ LeftDC += DC_FLOAT_STEP; }
+
+
+ /* Subtract DC an saturate */
+ Diff =* (pDataIn++) - (RightDC);
+ if (Diff > 1.0f) {
+ Diff = 1.0f; }
+ else if (Diff < -1.0f) {
+ Diff = -1.0f; }
+ *(pDataOut++) = (LVM_FLOAT)Diff;
+ if (Diff < 0) {
+ RightDC -= DC_FLOAT_STEP; }
+ else {
+ RightDC += DC_FLOAT_STEP; }
+
+ }
+ pBiquadState->LeftDC = LeftDC;
+ pBiquadState->RightDC = RightDC;
+
+
+ }
+#else
void DC_2I_D16_TRC_WRA_01( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
@@ -64,4 +110,4 @@
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.c
index 468a88d..4f4fcd8 100644
--- a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.c
@@ -17,11 +17,18 @@
#include "BIQUAD.h"
#include "DC_2I_D16_TRC_WRA_01_Private.h"
-
+#ifdef BUILD_FLOAT
+void DC_2I_D16_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t *pInstance)
+{
+ PFilter_FLOAT_State pBiquadState = (PFilter_FLOAT_State) pInstance;
+ pBiquadState->LeftDC = 0.0f;
+ pBiquadState->RightDC = 0.0f;
+}
+#else
void DC_2I_D16_TRC_WRA_01_Init(Biquad_Instance_t *pInstance)
{
PFilter_State pBiquadState = (PFilter_State) pInstance;
pBiquadState->LeftDC = 0;
pBiquadState->RightDC = 0;
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h
index 89a4e68..fa6b729 100644
--- a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h
@@ -18,11 +18,23 @@
#ifndef _DC_2I_D16_TRC_WRA_01_PRIVATE_H_
#define _DC_2I_D16_TRC_WRA_01_PRIVATE_H_
+#ifdef BUILD_FLOAT
+#define DC_FLOAT_STEP 0.0000002384f;
+#else
#define DC_D16_STEP 0x200;
+#endif
/* The internal state variables are implemented in a (for the user) hidden structure */
/* In this (private) file, the internal structure is declared fro private use.*/
+#ifdef BUILD_FLOAT
+typedef struct _Filter_FLOAT_State_
+{
+ LVM_FLOAT LeftDC; /* LeftDC */
+ LVM_FLOAT RightDC; /* RightDC */
+}Filter_FLOAT_State;
+typedef Filter_FLOAT_State * PFilter_FLOAT_State ;
+#else
typedef struct _Filter_State_
{
LVM_INT32 LeftDC; /* LeftDC */
@@ -30,5 +42,5 @@
}Filter_State;
typedef Filter_State * PFilter_State ;
-
+#endif
#endif /* _DC_2I_D16_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.c b/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.c
index 7e3182d..f502716 100644
--- a/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.c
+++ b/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.c
@@ -36,10 +36,55 @@
LVM_INT16 Offset = *pOffset;
LVM_INT16 temp;
+ for (i = 0; i < n; i++)
+ {
+ /* Left channel */
+ temp = (LVM_INT16)((LVM_UINT32)((LVM_INT32)(*dst) + (LVM_INT32)delay[Offset]) >> 1);
+ *dst = temp;
+ dst++;
+
+ delay[Offset] = *src;
+ Offset++;
+ src++;
+
+
+ /* Right channel */
+ temp = (LVM_INT16)((LVM_UINT32)((LVM_INT32)(*dst) - (LVM_INT32)delay[Offset]) >> 1);
+ *dst = temp;
+ dst++;
+
+ delay[Offset] = *src;
+ Offset++;
+ src++;
+
+ /* Make the reverb delay buffer a circular buffer */
+ if (Offset >= size)
+ {
+ Offset = 0;
+ }
+ }
+
+ /* Update the offset */
+ *pOffset = Offset;
+
+ return;
+}
+#ifdef BUILD_FLOAT
+void DelayMix_Float(const LVM_FLOAT *src, /* Source 1, to be delayed */
+ LVM_FLOAT *delay, /* Delay buffer */
+ LVM_INT16 size, /* Delay size */
+ LVM_FLOAT *dst, /* Source/destination */
+ LVM_INT16 *pOffset, /* Delay offset */
+ LVM_INT16 n) /* Number of stereo samples */
+{
+ LVM_INT16 i;
+ LVM_INT16 Offset = *pOffset;
+ LVM_FLOAT temp;
+
for (i=0; i<n; i++)
{
/* Left channel */
- temp = (LVM_INT16)((LVM_UINT32)((LVM_INT32)(*dst) + (LVM_INT32)delay[Offset]) >> 1);
+ temp = (LVM_FLOAT)((LVM_FLOAT)(*dst + (LVM_FLOAT)delay[Offset]) / 2.0f);
*dst = temp;
dst++;
@@ -49,7 +94,7 @@
/* Right channel */
- temp = (LVM_INT16)((LVM_UINT32)((LVM_INT32)(*dst) - (LVM_INT32)delay[Offset]) >> 1);
+ temp = (LVM_FLOAT)((LVM_FLOAT)(*dst - (LVM_FLOAT)delay[Offset]) / 2.0f);
*dst = temp;
dst++;
@@ -69,5 +114,5 @@
return;
}
-
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16C15_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16C15_TRC_WRA_01.c
index de77361..039c88c 100644
--- a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16C15_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16C15_TRC_WRA_01.c
@@ -31,6 +31,46 @@
pBiquadState->pDelays[1] is y(n-1)L in Q0 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void FO_1I_D16F16C15_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL=A1 * x(n-1)L
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[0];
+
+ // ynL+=A0 * x(n)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * (*pDataIn);
+
+ // ynL+= (-B1 * y(n-1)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * pBiquadState->pDelays[1];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[1] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output
+
+ }
+
+ }
+#else
void FO_1I_D16F16C15_TRC_WRA_01( Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
@@ -71,4 +111,4 @@
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.c
index 96252cc..b21b8a4 100644
--- a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.c
@@ -38,6 +38,22 @@
/* RETURNS: */
/* void return code */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+void FO_1I_D16F16Css_TRC_WRA_01_Init( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order1_FLOAT_Taps_t *pTaps,
+ FO_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *)pTaps;
+ temp = pCoef->A1;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[2] = temp;
+}
+#else
void FO_1I_D16F16Css_TRC_WRA_01_Init( Biquad_Instance_t *pInstance,
Biquad_1I_Order1_Taps_t *pTaps,
FO_C16_Coefs_t *pCoef)
@@ -53,6 +69,7 @@
temp=pCoef->B1;
pBiquadState->coefs[2]=temp;
}
+#endif
/*------------------------------------------------*/
/* End Of File: FO_1I_D16F16Css_TRC_WRA_01_Init.c */
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Private.h
index 516ca83..6fdb039 100644
--- a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Private.h
@@ -28,4 +28,14 @@
typedef Filter_State * PFilter_State ;
+#ifdef BUILD_FLOAT
+typedef struct _Filter_State_FLOAT
+{
+ LVM_FLOAT * pDelays; /* pointer to the delayed samples \
+ (data of 32 bits) */
+ LVM_FLOAT coefs[3]; /* pointer to the filter coefficients */
+}Filter_State_FLOAT;
+
+typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
+#endif
#endif /* _FO_1I_D16F16CSS_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32C31_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32C31_TRC_WRA_01.c
index 0f1d5bc..416e8eb 100644
--- a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32C31_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32C31_TRC_WRA_01.c
@@ -31,7 +31,47 @@
pBiquadState->pDelays[0] is x(n-1)L in Q0 format
pBiquadState->pDelays[1] is y(n-1)L in Q0 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void FO_1I_D32F32C31_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,templ;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL=A1 * x(n-1)L
+ ynL = pBiquadState->coefs[0] * pBiquadState->pDelays[0];
+
+ // ynL+=A0 * x(n)L
+ templ = pBiquadState->coefs[1] * (*pDataIn);
+ ynL += templ;
+
+ // ynL+= (-B1 * y(n-1)L
+ templ = pBiquadState->coefs[2] * pBiquadState->pDelays[1];
+ ynL += templ;
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[1] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output in Q0
+ }
+
+ }
+#else
void FO_1I_D32F32C31_TRC_WRA_01( Biquad_Instance_t *pInstance,
LVM_INT32 *pDataIn,
LVM_INT32 *pDataOut,
@@ -71,4 +111,4 @@
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.c
index 136e4f6..f33d24d 100644
--- a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.c
@@ -37,6 +37,23 @@
/* RETURNS: */
/* void return code */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+void FO_1I_D32F32Cll_TRC_WRA_01_Init( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order1_FLOAT_Taps_t *pTaps,
+ FO_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
+
+ temp = pCoef->A1;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[2] = temp;
+}
+#else
void FO_1I_D32F32Cll_TRC_WRA_01_Init( Biquad_Instance_t *pInstance,
Biquad_1I_Order1_Taps_t *pTaps,
FO_C32_Coefs_t *pCoef)
@@ -52,6 +69,7 @@
temp=pCoef->B1;
pBiquadState->coefs[2]=temp;
}
+#endif
/*------------------------------------------------*/
/* End Of File: FO_1I_D32F32Cll_TRC_WRA_01_Init.c */
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Private.h
index 94ad48c..fdb528b 100644
--- a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Private.h
@@ -29,4 +29,13 @@
typedef Filter_State * PFilter_State ;
+#ifdef BUILD_FLOAT
+typedef struct _Filter_State_FLOAT_
+{
+ LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
+ LVM_FLOAT coefs[3]; /* pointer to the filter coefficients */
+}Filter_State_FLOAT;
+
+typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
+#endif
#endif /* _FO_1I_D32F32CLL_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c
index 8388050..192927c 100644
--- a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c
@@ -32,7 +32,92 @@
pBiquadState->pDelays[2] is x(n-1)R in Q15 format
pBiquadState->pDelays[3] is y(n-1)R in Q30 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void FO_2I_D16F32C15_LShx_TRC_WRA_01(Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR;
+ LVM_FLOAT Temp;
+ LVM_FLOAT NegSatValue;
+ LVM_INT16 ii;
+ PFilter_Float_State pBiquadState = (PFilter_Float_State) pInstance;
+
+ NegSatValue = -1.0f;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+
+ // ynL =A1 * x(n-1)L
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[0];
+ // ynR =A1 * x(n-1)R
+ ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+
+ // ynL+=A0 * x(n)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * (*pDataIn);
+ // ynR+=A0 * x(n)L
+ ynR += (LVM_FLOAT)pBiquadState->coefs[1] * (*(pDataIn+1));
+
+
+ // ynL += (-B1 * y(n-1)L )
+ Temp = pBiquadState->pDelays[1] * pBiquadState->coefs[2];
+ ynL += Temp;
+ // ynR += (-B1 * y(n-1)R ) )
+ Temp = pBiquadState->pDelays[3] * pBiquadState->coefs[2];
+ ynR += Temp;
+
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[1] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ pBiquadState->pDelays[3] = ynR; // Update y(n-1)R
+ pBiquadState->pDelays[2] = (*pDataIn++); // Update x(n-1)R
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+
+ /*Saturate results*/
+ if(ynL > 1.0f)
+ {
+ ynL = 1.0f;
+ }
+ else
+ {
+ if(ynL < NegSatValue)
+ {
+ ynL = NegSatValue;
+ }
+ }
+
+ if(ynR > 1.0f)
+ {
+ ynR = 1.0f;
+ }
+ else
+ {
+ if(ynR < NegSatValue)
+ {
+ ynR = NegSatValue;
+ }
+ }
+
+ *pDataOut++ = (LVM_FLOAT)ynL;
+ *pDataOut++ = (LVM_FLOAT)ynR;
+ }
+
+ }
+#else
void FO_2I_D16F32C15_LShx_TRC_WRA_01(Biquad_Instance_t *pInstance,
LVM_INT16 *pDataIn,
LVM_INT16 *pDataOut,
@@ -125,4 +210,4 @@
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.c
index a19c32c..33ca6cf 100644
--- a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.c
@@ -37,6 +37,23 @@
/* RETURNS: */
/* void return code */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+void FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order1_FLOAT_Taps_t *pTaps,
+ FO_FLOAT_LShx_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_Float_State pBiquadState = (PFilter_Float_State) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps ;
+
+ temp = pCoef->A1;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[2] = temp;
+}
+#else
void FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(Biquad_Instance_t *pInstance,
Biquad_2I_Order1_Taps_t *pTaps,
FO_C16_LShx_Coefs_t *pCoef)
@@ -55,6 +72,7 @@
temp=pCoef->Shift;
pBiquadState->Shift = temp;
}
+#endif
/*-------------------------------------------------------------------------*/
/* End Of File: FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.c */
diff --git a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Private.h
index 4640743..368bfce 100644
--- a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Private.h
@@ -20,6 +20,15 @@
/* The internal state variables are implemented in a (for the user) hidden structure */
/* In this (private) file, the internal structure is declared fro private use. */
+#ifdef BUILD_FLOAT
+typedef struct _Filter_State_
+{
+ LVM_FLOAT *pDelays; /* pointer to the delayed samples (data of 32 bits) */
+ LVM_FLOAT coefs[3]; /* pointer to the filter coefficients */
+}Filter_Float_State;
+
+typedef Filter_Float_State * PFilter_Float_State ;
+#else
typedef struct _Filter_State_
{
LVM_INT32 *pDelays; /* pointer to the delayed samples (data of 32 bits) */
@@ -28,5 +37,5 @@
}Filter_State;
typedef Filter_State * PFilter_State ;
-
+#endif
#endif /* _FO_2I_D16F32CSS_LSHX_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/Filters.h b/media/libeffects/lvm/lib/Common/src/Filters.h
index 4d32df1..b1fde0c 100644
--- a/media/libeffects/lvm/lib/Common/src/Filters.h
+++ b/media/libeffects/lvm/lib/Common/src/Filters.h
@@ -34,6 +34,7 @@
* Biquad with coefficients A0, A1, A2, B1 and B2 coefficients
*/
/* Single precision (16-bit) Biquad section coefficients */
+#ifndef BUILD_FLOAT
typedef struct
{
LVM_INT16 A0;
@@ -43,12 +44,22 @@
LVM_INT16 B2;
LVM_UINT16 Scale;
} BiquadA012B12CoefsSP_t;
-
-
+#else
+typedef struct
+{
+ LVM_FLOAT A0;
+ LVM_FLOAT A1;
+ LVM_FLOAT A2;
+ LVM_FLOAT B1;
+ LVM_FLOAT B2;
+ LVM_UINT16 Scale;
+} BiquadA012B12CoefsSP_t;
+#endif
/*
* Biquad with coefficients A0, A1 and B1 coefficients
*/
/* Single precision (16-bit) Biquad section coefficients */
+#ifndef BUILD_FLOAT
typedef struct
{
LVM_INT16 A0;
@@ -56,8 +67,15 @@
LVM_INT16 B1;
LVM_UINT16 Scale;
} BiquadA01B1CoefsSP_t;
-
-
+#else
+typedef struct
+{
+ LVM_FLOAT A0;
+ LVM_FLOAT A1;
+ LVM_FLOAT B1;
+ LVM_UINT16 Scale;
+} BiquadA01B1CoefsSP_t;
+#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/media/libeffects/lvm/lib/Common/src/From2iToMS_16x16.c b/media/libeffects/lvm/lib/Common/src/From2iToMS_16x16.c
index 7975e8b..2c6e6c3 100644
--- a/media/libeffects/lvm/lib/Common/src/From2iToMS_16x16.c
+++ b/media/libeffects/lvm/lib/Common/src/From2iToMS_16x16.c
@@ -53,5 +53,34 @@
return;
}
+#ifdef BUILD_FLOAT
+void From2iToMS_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dstM,
+ LVM_FLOAT *dstS,
+ LVM_INT16 n )
+{
+ LVM_FLOAT temp1,left,right;
+ LVM_INT16 ii;
+ for (ii = n; ii != 0; ii--)
+ {
+ left = (LVM_FLOAT)*src;
+ src++;
+ right = (LVM_FLOAT)*src;
+ src++;
+
+ /* Compute M signal*/
+ temp1 = (left + right) / 2.0f;
+ *dstM = (LVM_FLOAT)temp1;
+ dstM++;
+
+ /* Compute S signal*/
+ temp1 = (left - right) / 2.0f;
+ *dstS = (LVM_FLOAT)temp1;
+ dstS++;
+ }
+
+ return;
+}
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/From2iToMono_32.c b/media/libeffects/lvm/lib/Common/src/From2iToMono_32.c
index 8bb292f..ac1eea8 100644
--- a/media/libeffects/lvm/lib/Common/src/From2iToMono_32.c
+++ b/media/libeffects/lvm/lib/Common/src/From2iToMono_32.c
@@ -46,5 +46,27 @@
return;
}
+#ifdef BUILD_FLOAT
+void From2iToMono_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 ii;
+ LVM_FLOAT Temp;
+ for (ii = n; ii != 0; ii--)
+ {
+ Temp = (*src);
+ src++;
+
+ Temp += (*src);
+ src++;
+
+ *dst = Temp / 2.0f;
+ dst++;
+ }
+
+ return;
+}
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/JoinTo2i_32x32.c b/media/libeffects/lvm/lib/Common/src/JoinTo2i_32x32.c
index 9b938bd..ebc477e 100644
--- a/media/libeffects/lvm/lib/Common/src/JoinTo2i_32x32.c
+++ b/media/libeffects/lvm/lib/Common/src/JoinTo2i_32x32.c
@@ -49,6 +49,31 @@
return;
}
+#ifdef BUILD_FLOAT
+void JoinTo2i_Float( const LVM_FLOAT *srcL,
+ const LVM_FLOAT *srcR,
+ LVM_FLOAT *dst,
+ LVM_INT16 n )
+{
+ LVM_INT16 ii;
+ srcL += n - 1;
+ srcR += n - 1;
+ dst += ((2 * n) - 1);
+
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = *srcR;
+ dst--;
+ srcR--;
+
+ *dst = *srcL;
+ dst--;
+ srcL--;
+ }
+
+ return;
+}
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c
index 3d39b93..eb5755e 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c
@@ -27,7 +27,39 @@
/**********************************************************************************
FUNCTION LVC_Core_MixHard_1St_2i_D16C31_SAT
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_Core_MixHard_1St_2i_D16C31_SAT( LVMixer3_FLOAT_st *ptrInstance1,
+ LVMixer3_FLOAT_st *ptrInstance2,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_FLOAT Temp;
+ LVM_INT16 ii;
+ Mix_Private_FLOAT_st *pInstance1 = (Mix_Private_FLOAT_st *)(ptrInstance1->PrivateParams);
+ Mix_Private_FLOAT_st *pInstance2 = (Mix_Private_FLOAT_st *)(ptrInstance2->PrivateParams);
+ for (ii = n; ii != 0; ii--)
+ {
+ Temp = ((LVM_FLOAT)*(src++) * (LVM_FLOAT)pInstance1->Current);
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+ Temp = ((LVM_FLOAT)*(src++) * (LVM_FLOAT)pInstance2->Current);
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+ }
+
+
+}
+#else
void LVC_Core_MixHard_1St_2i_D16C31_SAT( LVMixer3_st *ptrInstance1,
LVMixer3_st *ptrInstance2,
const LVM_INT16 *src,
@@ -66,4 +98,5 @@
}
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_2St_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_2St_D16C31_SAT.c
index 2daf74a..ec0baaf 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_2St_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_2St_D16C31_SAT.c
@@ -24,7 +24,37 @@
/**********************************************************************************
FUNCTION LVCore_MIXHARD_2ST_D16C31_SAT
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_Core_MixHard_2St_D16C31_SAT( LVMixer3_FLOAT_st *ptrInstance1,
+ LVMixer3_FLOAT_st *ptrInstance2,
+ const LVM_FLOAT *src1,
+ const LVM_FLOAT *src2,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_FLOAT Temp;
+ LVM_INT16 ii;
+ LVM_FLOAT Current1;
+ LVM_FLOAT Current2;
+ Mix_Private_FLOAT_st *pInstance1 = (Mix_Private_FLOAT_st *)(ptrInstance1->PrivateParams);
+ Mix_Private_FLOAT_st *pInstance2 = (Mix_Private_FLOAT_st *)(ptrInstance2->PrivateParams);
+
+ Current1 = (pInstance1->Current);
+ Current2 = (pInstance2->Current);
+
+ for (ii = n; ii != 0; ii--){
+ Temp = (((LVM_FLOAT)*(src1++) * (LVM_FLOAT)Current1)) +
+ (((LVM_FLOAT)*(src2++) * (LVM_FLOAT)Current2));
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = Temp;
+ }
+}
+#else
void LVC_Core_MixHard_2St_D16C31_SAT( LVMixer3_st *ptrInstance1,
LVMixer3_st *ptrInstance2,
const LVM_INT16 *src1,
@@ -54,6 +84,5 @@
*dst++ = (LVM_INT16)Temp;
}
}
-
-
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.c
index caa0951..d2694cc 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.c
@@ -25,7 +25,96 @@
/**********************************************************************************
FUNCTION LVCore_MIXSOFT_1ST_D16C31_WRA
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_Core_MixInSoft_D16C31_SAT( LVMixer3_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 OutLoop;
+ LVM_INT16 InLoop;
+ LVM_INT32 ii,jj;
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)(ptrInstance->PrivateParams);
+ LVM_FLOAT Delta = pInstance->Delta;
+ LVM_FLOAT Current = pInstance->Current;
+ LVM_FLOAT Target = pInstance->Target;
+ LVM_FLOAT Temp;
+
+ InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
+ OutLoop = (LVM_INT16)(n - (InLoop << 2));
+
+ if(Current < Target){
+ if (OutLoop){
+ Temp = Current + Delta;
+ Current = Temp;
+ if (Current > Target)
+ Current = Target;
+
+ for (ii = OutLoop; ii != 0; ii--){
+ Temp = ((LVM_FLOAT)*dst) + (((LVM_FLOAT)*(src++) * Current));
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--){
+ Temp = Current + Delta;
+ Current = Temp;
+ if (Current > Target)
+ Current = Target;
+
+ for (jj = 4; jj != 0 ; jj--){
+ Temp = ((LVM_FLOAT)*dst) + (((LVM_FLOAT)*(src++) * Current));
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+ }
+ }
+ }
+ else{
+ if (OutLoop){
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+
+ for (ii = OutLoop; ii != 0; ii--){
+ Temp = ((LVM_FLOAT)*dst) + (((LVM_FLOAT)*(src++) * Current));
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--){
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+
+ for (jj = 4; jj != 0 ; jj--){
+ Temp = ((LVM_FLOAT)*dst) + (((LVM_FLOAT)*(src++) * Current));
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+ }
+ }
+ }
+ pInstance->Current = Current;
+}
+#else
void LVC_Core_MixInSoft_D16C31_SAT( LVMixer3_st *ptrInstance,
const LVM_INT16 *src,
LVM_INT16 *dst,
@@ -123,6 +212,5 @@
}
pInstance->Current=Current;
}
-
-
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c
index 09ec427..656a117 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c
@@ -26,7 +26,127 @@
/**********************************************************************************
FUNCTION LVC_Core_MixSoft_1St_2i_D16C31_WRA
***********************************************************************************/
+#ifdef BUILD_FLOAT
+static LVM_FLOAT ADD2_SAT_FLOAT(LVM_FLOAT a,
+ LVM_FLOAT b,
+ LVM_FLOAT c)
+{
+ LVM_FLOAT temp;
+ temp = a + b ;
+ if (temp < -1.0f)
+ c = -1.0f;
+ else if (temp > 1.0f)
+ c = 1.0f;
+ else
+ c = temp;
+ return c;
+}
+void LVC_Core_MixSoft_1St_2i_D16C31_WRA( LVMixer3_FLOAT_st *ptrInstance1,
+ LVMixer3_FLOAT_st *ptrInstance2,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 OutLoop;
+ LVM_INT16 InLoop;
+ LVM_INT32 ii;
+ Mix_Private_FLOAT_st *pInstanceL = (Mix_Private_FLOAT_st *)(ptrInstance1->PrivateParams);
+ Mix_Private_FLOAT_st *pInstanceR = (Mix_Private_FLOAT_st *)(ptrInstance2->PrivateParams);
+ LVM_FLOAT DeltaL = pInstanceL->Delta;
+ LVM_FLOAT CurrentL = pInstanceL->Current;
+ LVM_FLOAT TargetL = pInstanceL->Target;
+
+ LVM_FLOAT DeltaR = pInstanceR->Delta;
+ LVM_FLOAT CurrentR = pInstanceR->Current;
+ LVM_FLOAT TargetR = pInstanceR->Target;
+
+ LVM_FLOAT Temp = 0;
+
+ InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
+ OutLoop = (LVM_INT16)(n - (InLoop << 2));
+
+ if (OutLoop)
+ {
+ if(CurrentL < TargetL)
+ {
+ ADD2_SAT_FLOAT(CurrentL, DeltaL, Temp);
+ CurrentL = Temp;
+ if (CurrentL > TargetL)
+ CurrentL = TargetL;
+ }
+ else
+ {
+ CurrentL -= DeltaL;
+ if (CurrentL < TargetL)
+ CurrentL = TargetL;
+ }
+
+ if(CurrentR < TargetR)
+ {
+ ADD2_SAT_FLOAT(CurrentR, DeltaR, Temp);
+ CurrentR = Temp;
+ if (CurrentR > TargetR)
+ CurrentR = TargetR;
+ }
+ else
+ {
+ CurrentR -= DeltaR;
+ if (CurrentR < TargetR)
+ CurrentR = TargetR;
+ }
+
+ for (ii = OutLoop * 2; ii != 0; ii -= 2)
+ {
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
+ }
+ }
+
+ for (ii = InLoop * 2; ii != 0; ii-=2)
+ {
+ if(CurrentL < TargetL)
+ {
+ ADD2_SAT_FLOAT(CurrentL, DeltaL, Temp);
+ CurrentL = Temp;
+ if (CurrentL > TargetL)
+ CurrentL = TargetL;
+ }
+ else
+ {
+ CurrentL -= DeltaL;
+ if (CurrentL < TargetL)
+ CurrentL = TargetL;
+ }
+
+ if(CurrentR < TargetR)
+ {
+ ADD2_SAT_FLOAT(CurrentR, DeltaR, Temp);
+ CurrentR = Temp;
+ if (CurrentR > TargetR)
+ CurrentR = TargetR;
+ }
+ else
+ {
+ CurrentR -= DeltaR;
+ if (CurrentR < TargetR)
+ CurrentR = TargetR;
+ }
+
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
+ }
+ pInstanceL->Current = CurrentL;
+ pInstanceR->Current = CurrentR;
+
+}
+#else
void LVC_Core_MixSoft_1St_2i_D16C31_WRA( LVMixer3_st *ptrInstance1,
LVMixer3_st *ptrInstance2,
const LVM_INT16 *src,
@@ -140,4 +260,5 @@
pInstanceR->Current=CurrentR;
}
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c
index f1a9ca3..b5e7f5c 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c
@@ -26,7 +26,86 @@
/**********************************************************************************
FUNCTION LVCore_MIXSOFT_1ST_D16C31_WRA
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_Core_MixSoft_1St_D16C31_WRA( LVMixer3_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 OutLoop;
+ LVM_INT16 InLoop;
+ LVM_INT32 ii;
+ Mix_Private_FLOAT_st *pInstance=(Mix_Private_FLOAT_st *)(ptrInstance->PrivateParams);
+ LVM_FLOAT Delta= (LVM_FLOAT)pInstance->Delta;
+ LVM_FLOAT Current = (LVM_FLOAT)pInstance->Current;
+ LVM_FLOAT Target= (LVM_FLOAT)pInstance->Target;
+ LVM_FLOAT Temp;
+ InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
+ OutLoop = (LVM_INT16)(n - (InLoop << 2));
+
+ if(Current<Target){
+ if (OutLoop){
+
+ Temp = Current + Delta;
+ if (Temp > 1.0f)
+ Temp = 1.0f;
+ else if (Temp < -1.0f)
+ Temp = -1.0f;
+
+ Current=Temp;
+ if (Current > Target)
+ Current = Target;
+
+ for (ii = OutLoop; ii != 0; ii--){
+ *(dst++) = (((LVM_FLOAT)*(src++) * (LVM_FLOAT)Current));
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--){
+
+ Temp = Current + Delta;
+
+ if (Temp > 1.0f)
+ Temp = 1.0f;
+ else if (Temp < -1.0f)
+ Temp = -1.0f;
+
+ Current=Temp;
+ if (Current > Target)
+ Current = Target;
+
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current) );
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current) );
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current) );
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current) );
+ }
+ }
+ else{
+ if (OutLoop){
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+
+ for (ii = OutLoop; ii != 0; ii--){
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--){
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ }
+ }
+ pInstance->Current=Current;
+}
+#else
void LVC_Core_MixSoft_1St_D16C31_WRA( LVMixer3_st *ptrInstance,
const LVM_INT16 *src,
LVM_INT16 *dst,
@@ -101,6 +180,5 @@
}
pInstance->Current=Current;
}
-
-
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.c
index 0052dd7..192f126 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.c
@@ -33,7 +33,80 @@
/**********************************************************************************
FUNCTION MIXINSOFT_D16C31_SAT
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_MixInSoft_D16C31_SAT( LVMixer3_1St_FLOAT_st *ptrInstance,
+ LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ char HardMixing = TRUE;
+ LVM_FLOAT TargetGain;
+ Mix_Private_FLOAT_st *pInstance = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if (pInstance->Current != pInstance->Target)
+ {
+ if(pInstance->Delta == 1.0f){
+ pInstance->Current = pInstance->Target;
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }else if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }else{
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ LVC_Core_MixInSoft_D16C31_SAT(&(ptrInstance->MixerStream[0]), src, dst, n);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing){
+ if (pInstance->Target != 0){ /* Nothing to do in case Target = 0 */
+ if ((pInstance->Target) == 1.0f){
+ Add2_Sat_Float(src, dst, n);
+ }
+ else{
+ Mac3s_Sat_Float(src, (pInstance->Target), dst, n);
+ /* In case the LVCore function would have changed the Current value */
+ pInstance->Current = pInstance->Target;
+ }
+ }
+ }
+
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+
+ if (ptrInstance->MixerStream[0].CallbackSet){
+ if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(ptrInstance->MixerStream, TargetGain);
+ ptrInstance->MixerStream[0].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[0].pCallBack != 0){
+ (*ptrInstance->MixerStream[0].pCallBack) ( \
+ ptrInstance->MixerStream[0].pCallbackHandle,
+ ptrInstance->MixerStream[0].pGeneralPurpose,
+ ptrInstance->MixerStream[0].CallbackParam );
+ }
+ }
+ }
+
+}
+#else
void LVC_MixInSoft_D16C31_SAT( LVMixer3_1St_st *ptrInstance,
LVM_INT16 *src,
LVM_INT16 *dst,
@@ -108,5 +181,5 @@
}
}
-
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c
index f443c8f..bd5a925 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c
@@ -33,7 +33,138 @@
/**********************************************************************************
FUNCTION LVC_MixSoft_1St_2i_D16C31_SAT
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ char HardMixing = TRUE;
+ LVM_FLOAT TargetGain;
+ Mix_Private_FLOAT_st *pInstance1 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+ Mix_Private_FLOAT_st *pInstance2 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if ((pInstance1->Current != pInstance1->Target) || (pInstance2->Current != pInstance2->Target))
+ {
+ if(pInstance1->Delta == 1.0f)
+ {
+ pInstance1->Current = pInstance1->Target;
+ TargetGain = pInstance1->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }
+ else if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
+ {
+ pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance1->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }
+ else
+ {
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ }
+
+ if(HardMixing == TRUE)
+ {
+ if(pInstance2->Delta == 1.0f)
+ {
+ pInstance2->Current = pInstance2->Target;
+ TargetGain = pInstance2->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
+ }
+ else if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
+ {
+ pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance2->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
+ }
+ else
+ {
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ }
+ }
+
+ if(HardMixing == FALSE)
+ {
+ LVC_Core_MixSoft_1St_2i_D16C31_WRA( &(ptrInstance->MixerStream[0]),
+ &(ptrInstance->MixerStream[1]),
+ src, dst, n);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing)
+ {
+ if ((pInstance1->Target == 1.0f) && (pInstance2->Target == 1.0f))
+ {
+ if(src != dst)
+ {
+ Copy_Float(src, dst, n);
+ }
+ }
+ else
+ {
+ LVC_Core_MixHard_1St_2i_D16C31_SAT(&(ptrInstance->MixerStream[0]),
+ &(ptrInstance->MixerStream[1]),
+ src, dst, n);
+ }
+ }
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+
+ if (ptrInstance->MixerStream[0].CallbackSet)
+ {
+ if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
+ {
+ pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance1->Target;
+ LVC_Mixer_SetTarget(&ptrInstance->MixerStream[0], TargetGain);
+ ptrInstance->MixerStream[0].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[0].pCallBack != 0)
+ {
+ (*ptrInstance->MixerStream[0].pCallBack) ( \
+ ptrInstance->MixerStream[0].pCallbackHandle,
+ ptrInstance->MixerStream[0].pGeneralPurpose,
+ ptrInstance->MixerStream[0].CallbackParam );
+ }
+ }
+ }
+ if (ptrInstance->MixerStream[1].CallbackSet)
+ {
+ if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
+ {
+ pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore.
+ Make them equal. */
+ TargetGain = pInstance2->Target;
+ LVC_Mixer_SetTarget(&ptrInstance->MixerStream[1], TargetGain);
+ ptrInstance->MixerStream[1].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[1].pCallBack != 0)
+ {
+ (*ptrInstance->MixerStream[1].pCallBack) (
+ ptrInstance->MixerStream[1].pCallbackHandle,
+ ptrInstance->MixerStream[1].pGeneralPurpose,
+ ptrInstance->MixerStream[1].CallbackParam );
+ }
+ }
+ }
+}
+#else
void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_st *ptrInstance,
const LVM_INT16 *src,
LVM_INT16 *dst,
@@ -148,5 +279,5 @@
}
}
}
-
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.c
index c8dcad7..1017de3 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.c
@@ -33,7 +33,77 @@
/**********************************************************************************
FUNCTION LVMixer3_MIXSOFT_1ST_D16C31_SAT
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_MixSoft_1St_D16C31_SAT( LVMixer3_1St_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ char HardMixing = TRUE;
+ LVM_FLOAT TargetGain;
+ Mix_Private_FLOAT_st *pInstance = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if (pInstance->Current != pInstance->Target)
+ {
+ if(pInstance->Delta == 1.0f){
+ pInstance->Current = pInstance->Target;
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }else if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }else{
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ LVC_Core_MixSoft_1St_D16C31_WRA(&(ptrInstance->MixerStream[0]), src, dst, n);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing){
+ if (pInstance->Target == 0)
+ LoadConst_Float(0.0, dst, n);
+ else {
+ if ((pInstance->Target) != 1.0f)
+ Mult3s_Float(src, (pInstance->Target), dst, n);
+ else if(src != dst)
+ Copy_Float(src, dst, n);
+ }
+
+ }
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+
+ if (ptrInstance->MixerStream[0].CallbackSet){
+ if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(ptrInstance->MixerStream, TargetGain);
+ ptrInstance->MixerStream[0].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[0].pCallBack != 0){
+ (*ptrInstance->MixerStream[0].pCallBack) ( \
+ ptrInstance->MixerStream[0].pCallbackHandle,
+ ptrInstance->MixerStream[0].pGeneralPurpose,
+ ptrInstance->MixerStream[0].CallbackParam );
+ }
+ }
+ }
+}
+#else
void LVC_MixSoft_1St_D16C31_SAT( LVMixer3_1St_st *ptrInstance,
const LVM_INT16 *src,
LVM_INT16 *dst,
@@ -107,5 +177,5 @@
}
}
}
-
+#endif/*BUILD_FLOAT*/
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.c
index 7240705..3c90071 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.c
@@ -25,7 +25,49 @@
/**********************************************************************************
FUNCTION LVC_MixSoft_2St_D16C31_SAT.c
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_MixSoft_2St_D16C31_SAT( LVMixer3_2St_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src1,
+ LVM_FLOAT *src2,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ Mix_Private_FLOAT_st *pInstance1 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+ Mix_Private_FLOAT_st *pInstance2 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if ((pInstance1->Current == pInstance1->Target) && (pInstance1->Current == 0)){
+ LVC_MixSoft_1St_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[1]),
+ src2, dst, n);
+ }
+ else if ((pInstance2->Current == pInstance2->Target) && (pInstance2->Current == 0)){
+ LVC_MixSoft_1St_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[0]),
+ src1, dst, n);
+ }
+ else if ((pInstance1->Current != pInstance1->Target) || \
+ (pInstance2->Current != pInstance2->Target))
+ {
+ LVC_MixSoft_1St_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[0]),
+ src1, dst, n);
+ LVC_MixInSoft_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[1]),
+ src2, dst, n);
+ }
+ else{
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+ LVC_Core_MixHard_2St_D16C31_SAT( &ptrInstance->MixerStream[0],
+ &ptrInstance->MixerStream[1],
+ src1, src2, dst, n);
+ }
+}
+#else
void LVC_MixSoft_2St_D16C31_SAT( LVMixer3_2St_st *ptrInstance,
const LVM_INT16 *src1,
LVM_INT16 *src2,
@@ -66,5 +108,5 @@
LVC_Core_MixHard_2St_D16C31_SAT( &ptrInstance->MixerStream[0], &ptrInstance->MixerStream[1], src1, src2, dst, n);
}
}
-
+#endif /*BUILD_FLOAT*/
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h b/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
index 980c783..f904915 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
@@ -31,6 +31,19 @@
***********************************************************************************/
/* LVMixer3_st structure stores Instance parameters for one audio stream */
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVM_FLOAT PrivateParams[3]; /* Private Instance params for \
+ Audio Stream shift parameter */
+ LVM_INT16 CallbackSet; /* Boolean. Should be set by calling application \
+ each time the target value is updated */
+ LVM_INT16 CallbackParam; /* Parameter that will be used in the calback function */
+ void *pCallbackHandle; /* Pointer to the instance of the callback function */
+ void *pGeneralPurpose; /* Pointer for general purpose usage */
+ LVM_Callback pCallBack; /* Pointer to the callback function */
+} LVMixer3_FLOAT_st;
+#else
typedef struct
{
LVM_INT32 PrivateParams[4]; /* Private Instance params for Audio Stream */
@@ -40,22 +53,35 @@
void *pGeneralPurpose; /* Pointer for general purpose usage */
LVM_Callback pCallBack; /* Pointer to the callback function */
} LVMixer3_st;
-
+#endif
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVMixer3_FLOAT_st MixerStream[1]; /* Instance Params for one Audio Stream */
+} LVMixer3_1St_FLOAT_st;
+#else
typedef struct
{
LVMixer3_st MixerStream[1]; /* Instance Params for one Audio Stream */
} LVMixer3_1St_st;
-
+#endif
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVMixer3_FLOAT_st MixerStream[2]; /* Instance Params for two Audio Streams */
+} LVMixer3_2St_FLOAT_st;
+#else
typedef struct
{
LVMixer3_st MixerStream[2]; /* Instance Params for two Audio Streams */
} LVMixer3_2St_st;
-
+#endif
+#ifndef BUILD_FLOAT
typedef struct
{
LVMixer3_st MixerStream[3]; /* Instance Params for three Audio Streams */
} LVMixer3_3St_st;
-
+#endif
/**********************************************************************************
FUNCTION PROTOTYPES (HIGH LEVEL FUNCTIONS)
***********************************************************************************/
@@ -75,57 +101,115 @@
/* then the calculation will give an incorrect value for alpha, see the mixer */
/* documentation for further details. */
/* ********************************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_Mixer_SetTarget( LVMixer3_FLOAT_st *pStream,
+ LVM_FLOAT TargetGain);
+#else
void LVC_Mixer_SetTarget( LVMixer3_st *pStream,
LVM_INT32 TargetGain);
-
+#endif
+#ifdef BUILD_FLOAT
+LVM_FLOAT LVC_Mixer_GetTarget( LVMixer3_FLOAT_st *pStream);
+#else
LVM_INT32 LVC_Mixer_GetTarget( LVMixer3_st *pStream);
+#endif
+#ifdef BUILD_FLOAT
+LVM_FLOAT LVC_Mixer_GetCurrent( LVMixer3_FLOAT_st *pStream);
+#else
LVM_INT32 LVC_Mixer_GetCurrent( LVMixer3_st *pStream);
+#endif
+#ifdef BUILD_FLOAT
+void LVC_Mixer_Init( LVMixer3_FLOAT_st *pStream,
+ LVM_FLOAT TargetGain,
+ LVM_FLOAT CurrentGain);
+#else
void LVC_Mixer_Init( LVMixer3_st *pStream,
LVM_INT32 TargetGain,
LVM_INT32 CurrentGain);
+#endif
+#ifdef BUILD_FLOAT
+void LVC_Mixer_SetTimeConstant( LVMixer3_FLOAT_st *pStream,
+ LVM_INT32 Tc_millisec,
+ LVM_Fs_en Fs,
+ LVM_INT16 NumChannels);
+#else
void LVC_Mixer_SetTimeConstant( LVMixer3_st *pStream,
LVM_INT32 Tc_millisec,
LVM_Fs_en Fs,
LVM_INT16 NumChannels);
+#endif
+#ifdef BUILD_FLOAT
+void LVC_Mixer_VarSlope_SetTimeConstant( LVMixer3_FLOAT_st *pStream,
+ LVM_INT32 Tc_millisec,
+ LVM_Fs_en Fs,
+ LVM_INT16 NumChannels);
+#else
void LVC_Mixer_VarSlope_SetTimeConstant( LVMixer3_st *pStream,
LVM_INT32 Tc_millisec,
LVM_Fs_en Fs,
LVM_INT16 NumChannels);
+#endif
/*** 16 bit functions *************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_MixSoft_1St_D16C31_SAT( LVMixer3_1St_FLOAT_st *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
void LVC_MixSoft_1St_D16C31_SAT( LVMixer3_1St_st *pInstance,
const LVM_INT16 *src,
LVM_INT16 *dst,
LVM_INT16 n);
+#endif
+#ifdef BUILD_FLOAT
+void LVC_MixInSoft_D16C31_SAT( LVMixer3_1St_FLOAT_st *pInstance,
+ LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
void LVC_MixInSoft_D16C31_SAT( LVMixer3_1St_st *pInstance,
LVM_INT16 *src,
LVM_INT16 *dst,
LVM_INT16 n);
+#endif
+#ifdef BUILD_FLOAT
+void LVC_MixSoft_2St_D16C31_SAT( LVMixer3_2St_FLOAT_st *pInstance,
+ const LVM_FLOAT *src1,
+ LVM_FLOAT *src2,
+ LVM_FLOAT *dst, /* dst cannot be equal to src2 */
+ LVM_INT16 n);
+#else
void LVC_MixSoft_2St_D16C31_SAT( LVMixer3_2St_st *pInstance,
const LVM_INT16 *src1,
LVM_INT16 *src2,
LVM_INT16 *dst, /* dst cannot be equal to src2 */
LVM_INT16 n);
-
+#endif
/**********************************************************************************/
/* For applying different gains to Left and right chennals */
/* MixerStream[0] applies to Left channel */
/* MixerStream[1] applies to Right channel */
/* Gain values should not be more that 1.0 */
/**********************************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_FLOAT_st *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst, /* dst can be equal to src */
+ LVM_INT16 n); /* Number of stereo samples */
+#else
void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_st *pInstance,
const LVM_INT16 *src,
LVM_INT16 *dst, /* dst can be equal to src */
LVM_INT16 n); /* Number of stereo samples */
-
-
+#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetCurrent.c b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetCurrent.c
index b5ae264..5990412 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetCurrent.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetCurrent.c
@@ -31,7 +31,15 @@
/* CurrentGain - CurrentGain value in Q 16.15 format */
/* */
/************************************************************************/
-
+#ifdef BUILD_FLOAT
+LVM_FLOAT LVC_Mixer_GetCurrent( LVMixer3_FLOAT_st *pStream)
+{
+ LVM_FLOAT CurrentGain;
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
+ CurrentGain = pInstance->Current; // CurrentGain
+ return CurrentGain;
+}
+#else
LVM_INT32 LVC_Mixer_GetCurrent( LVMixer3_st *pStream)
{
LVM_INT32 CurrentGain;
@@ -39,3 +47,4 @@
CurrentGain=pInstance->Current>>(16-pInstance->Shift); // CurrentGain in Q16.15 format
return CurrentGain;
}
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.c b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.c
index dc2f8e9..c67455a 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.c
@@ -30,7 +30,16 @@
/* TargetGain - TargetGain value in Q 16.15 format */
/* */
/************************************************************************/
-
+#ifdef BUILD_FLOAT
+LVM_FLOAT LVC_Mixer_GetTarget( LVMixer3_FLOAT_st *pStream)
+{
+ LVM_FLOAT TargetGain;
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
+
+ TargetGain = pInstance->Target; // TargetGain
+ return TargetGain;
+}
+#else
LVM_INT32 LVC_Mixer_GetTarget( LVMixer3_st *pStream)
{
LVM_INT32 TargetGain;
@@ -40,3 +49,4 @@
return TargetGain;
}
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Init.c b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Init.c
index 449e7b1..737e26b 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Init.c
@@ -44,7 +44,19 @@
/* void */
/* */
/************************************************************************/
-
+#ifdef BUILD_FLOAT
+void LVC_Mixer_Init( LVMixer3_FLOAT_st *pStream,
+ LVM_FLOAT TargetGain,
+ LVM_FLOAT CurrentGain)
+{
+ LVM_FLOAT MaxGain = TargetGain;
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
+ if(CurrentGain > MaxGain)
+ MaxGain = CurrentGain;
+ pInstance->Target = TargetGain; // Update fractional gain Target
+ pInstance->Current = CurrentGain; // Update fractional gain Current
+}
+#else
void LVC_Mixer_Init( LVMixer3_st *pStream,
LVM_INT32 TargetGain,
LVM_INT32 CurrentGain)
@@ -64,4 +76,4 @@
pInstance->Current=CurrentGain<<(16-Shift); // Update fractional gain Current
pInstance->Shift=Shift; // Update Shift
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
index 294e05c..d0d0e1f 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
@@ -26,6 +26,15 @@
#include "VectorArithmetic.h"
/* Instance parameter structure */
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ /* General */
+ LVM_FLOAT Target; /*number specifying value of Target Gain */
+ LVM_FLOAT Current; /*number specifying value of Current Gain */
+ LVM_FLOAT Delta; /*number specifying value of Delta Gain */
+} Mix_Private_FLOAT_st;
+#else
typedef struct
{
/* General */
@@ -34,8 +43,7 @@
LVM_INT32 Shift; /* Left Shift for Integer part of Gain */
LVM_INT32 Delta; /* 32 bit number specifying the fractional value of Delta Gain */
} Mix_Private_st;
-
-
+#endif
/**********************************************************************************
DEFINITIONS
@@ -49,23 +57,43 @@
***********************************************************************************/
/*** 16 bit functions *************************************************************/
-
+#ifdef BUILD_FLOAT
+void LVC_Core_MixInSoft_D16C31_SAT( LVMixer3_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
void LVC_Core_MixInSoft_D16C31_SAT( LVMixer3_st *pInstance,
const LVM_INT16 *src,
LVM_INT16 *dst,
LVM_INT16 n);
-
+#endif
+#ifdef BUILD_FLOAT
+void LVC_Core_MixSoft_1St_D16C31_WRA( LVMixer3_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
void LVC_Core_MixSoft_1St_D16C31_WRA( LVMixer3_st *pInstance,
const LVM_INT16 *src,
LVM_INT16 *dst,
LVM_INT16 n);
-
+#endif
+#ifdef BUILD_FLOAT
+void LVC_Core_MixHard_2St_D16C31_SAT( LVMixer3_FLOAT_st *pInstance1,
+ LVMixer3_FLOAT_st *pInstance2,
+ const LVM_FLOAT *src1,
+ const LVM_FLOAT *src2,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
void LVC_Core_MixHard_2St_D16C31_SAT( LVMixer3_st *pInstance1,
LVMixer3_st *pInstance2,
const LVM_INT16 *src1,
const LVM_INT16 *src2,
LVM_INT16 *dst,
LVM_INT16 n);
+#endif
/**********************************************************************************/
/* For applying different gains to Left and right chennals */
@@ -73,12 +101,19 @@
/* ptrInstance2 applies to Right channel */
/* Gain values should not be more that 1.0 */
/**********************************************************************************/
-
+#ifdef BUILD_FLOAT
+void LVC_Core_MixSoft_1St_2i_D16C31_WRA( LVMixer3_FLOAT_st *ptrInstance1,
+ LVMixer3_FLOAT_st *ptrInstance2,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
void LVC_Core_MixSoft_1St_2i_D16C31_WRA( LVMixer3_st *ptrInstance1,
LVMixer3_st *ptrInstance2,
const LVM_INT16 *src,
LVM_INT16 *dst, /* dst can be equal to src */
LVM_INT16 n); /* Number of stereo samples */
+#endif
/**********************************************************************************/
/* For applying different gains to Left and right chennals */
@@ -86,16 +121,22 @@
/* ptrInstance2 applies to Right channel */
/* Gain values should not be more that 1.0 */
/**********************************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_Core_MixHard_1St_2i_D16C31_SAT( LVMixer3_FLOAT_st *ptrInstance1,
+ LVMixer3_FLOAT_st *ptrInstance2,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n);
+#else
void LVC_Core_MixHard_1St_2i_D16C31_SAT( LVMixer3_st *ptrInstance1,
LVMixer3_st *ptrInstance2,
const LVM_INT16 *src,
LVM_INT16 *dst, /* dst can be equal to src */
LVM_INT16 n); /* Number of stereo samples */
-
-
+#endif
/*** 32 bit functions *************************************************************/
-
+#ifndef BUILD_FLOAT
void LVC_Core_MixInSoft_D32C31_SAT( LVMixer3_st *pInstance,
const LVM_INT32 *src,
LVM_INT32 *dst,
@@ -112,7 +153,7 @@
const LVM_INT32 *src2,
LVM_INT32 *dst,
LVM_INT16 n);
-
+#endif
/**********************************************************************************/
#endif //#ifndef __LVC_MIXER_PRIVATE_H__
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTarget.c b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTarget.c
index 5efa501..577179d 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTarget.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTarget.c
@@ -43,7 +43,14 @@
/* void */
/* */
/************************************************************************/
-
+#ifdef BUILD_FLOAT
+void LVC_Mixer_SetTarget(LVMixer3_FLOAT_st *pStream,
+ LVM_FLOAT TargetGain)
+{
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
+ pInstance->Target = TargetGain; // Update gain Target
+}
+#else
void LVC_Mixer_SetTarget(LVMixer3_st *pStream,
LVM_INT32 TargetGain)
{
@@ -64,3 +71,4 @@
pInstance->Current=CurrentGain<<(16-Shift); // Update fractional gain Current
pInstance->Shift=Shift; // Update Shift
}
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTimeConstant.c b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTimeConstant.c
index 4c1c8b2..48f5d54 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTimeConstant.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTimeConstant.c
@@ -44,7 +44,51 @@
/* RETURNS: */
/* void */
/************************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_Mixer_SetTimeConstant(LVMixer3_FLOAT_st *pStream,
+ LVM_INT32 Tc_millisec,
+ LVM_Fs_en Fs,
+ LVM_INT16 NumChannels)
+{
+#ifdef HIGHER_FS
+ LVM_FLOAT DeltaTable[11] = {0.500000f,/*8000*/
+ 0.362812f,/*11025*/
+ 0.333333f,/*12000*/
+ 0.250000f,/*16000*/
+ 0.181406f,/*22050*/
+ 0.166666f,/*24000*/
+ 0.125000f,/*32000*/
+ 0.090703f,/*44100*/
+ 0.083333f,/*48000*/
+ 0.041667f,/*96000*/
+ 0.020833f};/*192000*/
+#else
+ LVM_FLOAT DeltaTable[9] = {0.500000f,/*8000*/
+ 0.362812f,/*11025*/
+ 0.333333f,/*12000*/
+ 0.250000f,/*16000*/
+ 0.181406f,/*22050*/
+ 0.166666f,/*24000*/
+ 0.125000f,/*32000*/
+ 0.090703f,/*44100*/
+ 0.083333f};/*48000*/
+#endif
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
+ LVM_FLOAT Delta = DeltaTable[Fs];
+ Delta = Delta / (NumChannels);
+
+ if(Tc_millisec == 0)
+ Delta = 1.000000f;
+ else
+ Delta = Delta / Tc_millisec;
+
+ if(Delta == 0)
+ Delta = 0.0000000005f; /* If Time Constant is so large that Delta is 0, \
+ assign minimum value to Delta */
+ pInstance->Delta = Delta; // Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec)
+}
+#else
void LVC_Mixer_SetTimeConstant(LVMixer3_st *pStream,
LVM_INT32 Tc_millisec,
LVM_Fs_en Fs,
@@ -73,3 +117,4 @@
pInstance->Delta=Delta; // Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec) in Q 0.31 format
}
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_VarSlope_SetTimeConstant.c b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_VarSlope_SetTimeConstant.c
index 8d5304e..9dc7d21 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_VarSlope_SetTimeConstant.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_VarSlope_SetTimeConstant.c
@@ -45,7 +45,72 @@
/* RETURNS: */
/* void */
/************************************************************************/
+#ifdef BUILD_FLOAT
+void LVC_Mixer_VarSlope_SetTimeConstant( LVMixer3_FLOAT_st *pStream,
+ LVM_INT32 Tc_millisec,
+ LVM_Fs_en Fs,
+ LVM_INT16 NumChannels)
+{
+#ifdef HIGHER_FS
+ LVM_FLOAT DeltaTable[11] = {0.500000f,/*8000*/
+ 0.362812f,/*11025*/
+ 0.333333f,/*12000*/
+ 0.250000f,/*16000*/
+ 0.181406f,/*22050*/
+ 0.166666f,/*24000*/
+ 0.125000f,/*32000*/
+ 0.090703f,/*44100*/
+ 0.083333f,/*48000*/
+ 0.041666f,/*96000*/
+ 0.020833f};/*192000*/
+#else
+ LVM_FLOAT DeltaTable[9] = {0.500000f,/*8000*/
+ 0.362812f,/*11025*/
+ 0.333333f,/*12000*/
+ 0.250000f,/*16000*/
+ 0.181406f,/*22050*/
+ 0.166666f,/*24000*/
+ 0.125000f,/*32000*/
+ 0.090703f,/*44100*/
+ 0.083333f};/*48000*/
+#endif
+ LVM_FLOAT Tc_millisec_float;
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
+ LVM_FLOAT Delta = DeltaTable[Fs];
+ LVM_FLOAT Current;
+ LVM_FLOAT Target;
+
+ Delta=Delta / (NumChannels);
+
+ /* Get gain values */
+ Current = pInstance->Current;
+ Target = pInstance->Target;
+
+ if (Current != Target)
+ {
+ Tc_millisec_float = (LVM_FLOAT)(Tc_millisec) / (Current - Target);
+ if (Tc_millisec_float < 0)
+ Tc_millisec_float = -Tc_millisec_float;
+
+ if(Tc_millisec == 0)
+ Delta = 1.000000f;
+ else
+ Delta = Delta / Tc_millisec_float;
+
+ if(Delta == 0)
+ Delta = 0.0000000005f; /* If Time Constant is so large that Delta is 0, \
+ assign minimum value to Delta */
+ }
+ else
+ {
+ Delta = 0.0000000005f; /* Minimum value for proper call-backs \
+ (setting it to zero has some problems, to be corrected) */
+ }
+
+ pInstance->Delta = Delta; // Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec)
+}
+#else
void LVC_Mixer_VarSlope_SetTimeConstant( LVMixer3_st *pStream,
LVM_INT32 Tc_millisec,
LVM_Fs_en Fs,
@@ -93,3 +158,4 @@
pInstance->Delta=Delta; // Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec) in Q 0.31 format
}
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_FO_HPF.c b/media/libeffects/lvm/lib/Common/src/LVM_FO_HPF.c
index 6d8fe46..9094622 100644
--- a/media/libeffects/lvm/lib/Common/src/LVM_FO_HPF.c
+++ b/media/libeffects/lvm/lib/Common/src/LVM_FO_HPF.c
@@ -53,7 +53,7 @@
/* A9 194669577 */
/* A10 8 */
/* */
-/* Y = (A0 + A1*X + A2*X2 + A3*X3 + Â….. + AN*xN) << AN+1 */
+/* Y = (A0 + A1*X + A2*X2 + A3*X3 + �.. + AN*xN) << AN+1 */
/* */
/* */
/* PARAMETERS: */
@@ -68,7 +68,36 @@
/* RETURNS: */
/* */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+LVM_FLOAT LVM_FO_HPF( LVM_FLOAT w,
+ FO_FLOAT_Coefs_t *pCoeffs)
+{
+ LVM_FLOAT Y,Coefficients[13] = {-0.999996f,
+ 0.999801f,
+ -0.497824f,
+ 0.322937f,
+ -0.180880f,
+ 0.087658f,
+ -0.032102f,
+ 0.008163f,
+ -0.001252f,
+ 0.000089f,
+ 0,
+ 0,
+ 0};
+ Y=LVM_Polynomial((LVM_UINT16)9, Coefficients, w);
+ pCoeffs->B1 = -Y; /* Store -B1 in filter structure instead of B1!*/
+ /* A0=(1-B1)/2= B1/2 - 0.5*/
+ Y = Y / 2.0f; /* A0=Y=B1/2*/
+ Y = Y - 0.5f; /* A0=Y=(B1/2 - 0.5)*/
+
+ pCoeffs->A0 = Y * FILTER_LOSS_FLOAT; /* Apply loss to avoid overflow*/
+ pCoeffs->A1 = -pCoeffs->A0; /* Store A1=-A0*/
+
+ return 1;
+}
+#else
LVM_INT32 LVM_FO_HPF( LVM_INT32 w,
FO_C32_Coefs_t *pCoeffs)
{
@@ -97,4 +126,4 @@
return 1;
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_FO_LPF.c b/media/libeffects/lvm/lib/Common/src/LVM_FO_LPF.c
index 86ec951..9fe67f8 100644
--- a/media/libeffects/lvm/lib/Common/src/LVM_FO_LPF.c
+++ b/media/libeffects/lvm/lib/Common/src/LVM_FO_LPF.c
@@ -53,7 +53,7 @@
/* A9 194669577 */
/* A10 8 */
/* */
-/* Y = (A0 + A1*X + A2*X2 + A3*X3 + Â….. + AN*xN) << AN+1 */
+/* Y = (A0 + A1*X + A2*X2 + A3*X3 + �.. + AN*xN) << AN+1 */
/* */
/* */
/* PARAMETERS: */
@@ -68,7 +68,33 @@
/* RETURNS: */
/* */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+LVM_FLOAT LVM_FO_LPF( LVM_FLOAT w,
+ FO_FLOAT_Coefs_t *pCoeffs)
+{
+ LVM_FLOAT Y,Coefficients[13] = {-0.999996f,
+ 0.999801f,
+ -0.497824f,
+ 0.322937f,
+ -0.180880f,
+ 0.087658f,
+ -0.032102f,
+ 0.008163f,
+ -0.001252f,
+ 0.000089f,
+ 0};
+ Y=LVM_Polynomial((LVM_UINT16)9, Coefficients, w);
+ pCoeffs->B1 = -Y; // Store -B1 in filter structure instead of B1!
+ // A0=(1+B1)/2= B1/2 + 0.5
+ Y = Y / 2.0f; // A0=Y=B1/2
+ Y = Y + 0.5f; // A0=Y=(B1/2 + 0.5)
+ pCoeffs->A0 = Y * FILTER_LOSS_FLOAT;
+ pCoeffs->A1 = pCoeffs->A0;
+
+ return 1;
+}
+#else
LVM_INT32 LVM_FO_LPF( LVM_INT32 w,
FO_C32_Coefs_t *pCoeffs)
{
@@ -94,4 +120,4 @@
pCoeffs->A1=pCoeffs->A0;
return 1;
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_GetOmega.c b/media/libeffects/lvm/lib/Common/src/LVM_GetOmega.c
index f3b9b3c..7846ca0 100644
--- a/media/libeffects/lvm/lib/Common/src/LVM_GetOmega.c
+++ b/media/libeffects/lvm/lib/Common/src/LVM_GetOmega.c
@@ -32,16 +32,45 @@
#define LVVDL_2PiByFs_SHIFT1 12 /* Qformat shift for 8kHz, 11.025kHz and 12kHz i.e. 12=41-29 */
#define LVVDL_2PiByFs_SHIFT2 13 /* Qformat shift for 16kHz, 22.050kHz and 24kHz i.e. 13=42-29 */
#define LVVDL_2PiByFs_SHIFT3 14 /* Qformat shift for 32kHz, 44.1kHz and 48kHz i.e. 14=43-29 */
-
+#ifndef BUILD_FLOAT
const LVM_INT32 LVVDL_2PiOnFsTable[] = {LVVDL_2PiBy_8000 , /* 8kHz in Q41, 16kHz in Q42, 32kHz in Q43 */
LVVDL_2PiBy_11025, /* 11025 Hz in Q41, 22050Hz in Q42, 44100 Hz in Q43*/
LVVDL_2PiBy_12000}; /* 12kHz in Q41, 24kHz in Q42, 48kHz in Q43 */
-
+#endif
const LVM_INT32 LVVDL_2PiOnFsShiftTable[]={LVVDL_2PiByFs_SHIFT1 , /* 8kHz, 11025Hz, 12kHz */
LVVDL_2PiByFs_SHIFT2, /* 16kHz, 22050Hz, 24kHz*/
LVVDL_2PiByFs_SHIFT3}; /* 32kHz, 44100Hz, 48kHz */
+#ifdef BUILD_FLOAT
+#define LVVDL_2PiBy_8000_f 0.000785398f
+#define LVVDL_2PiBy_11025_f 0.000569903f
+#define LVVDL_2PiBy_12000_f 0.000523599f
+#define LVVDL_2PiBy_16000_f 0.000392700f
+#define LVVDL_2PiBy_22050_f 0.000284952f
+#define LVVDL_2PiBy_24000_f 0.000261800f
+#define LVVDL_2PiBy_32000_f 0.000196350f
+#define LVVDL_2PiBy_44100_f 0.000142476f
+#define LVVDL_2PiBy_48000_f 0.000130900f
+#ifdef HIGHER_FS
+#define LVVDL_2PiBy_96000_f 0.000065450f
+#define LVVDL_2PiBy_192000_f 0.000032725f
+#endif
+const LVM_FLOAT LVVDL_2PiOnFsTable[] = {LVVDL_2PiBy_8000_f,
+ LVVDL_2PiBy_11025_f,
+ LVVDL_2PiBy_12000_f,
+ LVVDL_2PiBy_16000_f,
+ LVVDL_2PiBy_22050_f,
+ LVVDL_2PiBy_24000_f,
+ LVVDL_2PiBy_32000_f,
+ LVVDL_2PiBy_44100_f,
+ LVVDL_2PiBy_48000_f
+#ifdef HIGHER_FS
+ ,LVVDL_2PiBy_96000_f
+ ,LVVDL_2PiBy_192000_f
+#endif
+ };
+#endif
/*-------------------------------------------------------------------------*/
/* FUNCTION: */
/* LVM_GetOmega */
@@ -59,7 +88,20 @@
/* RETURNS: */
/* w=2*pi*Fc/Fs in Q2.29 format */
/*-------------------------------------------------------------------------*/
-
+#ifdef BUILD_FLOAT
+#ifdef HIGHER_FS
+LVM_FLOAT LVM_GetOmega(LVM_UINT32 Fc,
+ LVM_Fs_en Fs)
+#else
+LVM_FLOAT LVM_GetOmega(LVM_UINT16 Fc,
+ LVM_Fs_en Fs)
+#endif
+{
+ LVM_FLOAT w;
+ w = (LVM_FLOAT)Fc * LVVDL_2PiOnFsTable[Fs];
+ return w;
+}
+#else
LVM_INT32 LVM_GetOmega(LVM_UINT16 Fc,
LVM_Fs_en Fs)
{
@@ -67,4 +109,4 @@
MUL32x32INTO32((LVM_INT32)Fc,LVVDL_2PiOnFsTable[Fs%3],w,LVVDL_2PiOnFsShiftTable[Fs/3])
return w;
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Mixer_FilterCoeffs.h b/media/libeffects/lvm/lib/Common/src/LVM_Mixer_FilterCoeffs.h
index 6846d49..f1e45fa 100644
--- a/media/libeffects/lvm/lib/Common/src/LVM_Mixer_FilterCoeffs.h
+++ b/media/libeffects/lvm/lib/Common/src/LVM_Mixer_FilterCoeffs.h
@@ -87,5 +87,58 @@
#define ALPHA_49 0 /* Floating point Alpha = 0.000000 */
#define ALPHA_50 0 /* Floating point Alpha = 0.000000 */
+#ifdef BUILD_FLOAT /* BUILD_FLOAT */
+#define ALPHA_Float_0 0.999999f
+#define ALPHA_Float_1 0.999998f
+#define ALPHA_Float_2 0.999997f
+#define ALPHA_Float_3 0.999996f
+#define ALPHA_Float_4 0.999995f
+#define ALPHA_Float_5 0.999992f
+#define ALPHA_Float_6 0.999989f
+#define ALPHA_Float_7 0.999985f
+#define ALPHA_Float_8 0.999979f
+#define ALPHA_Float_9 0.999970f
+#define ALPHA_Float_10 0.999957f
+#define ALPHA_Float_11 0.999939f
+#define ALPHA_Float_12 0.999914f
+#define ALPHA_Float_13 0.999879f
+#define ALPHA_Float_14 0.999829f
+#define ALPHA_Float_15 0.999758f
+#define ALPHA_Float_16 0.999658f
+#define ALPHA_Float_17 0.999516f
+#define ALPHA_Float_18 0.999316f
+#define ALPHA_Float_19 0.999033f
+#define ALPHA_Float_20 0.998633f
+#define ALPHA_Float_21 0.998067f
+#define ALPHA_Float_22 0.997268f
+#define ALPHA_Float_23 0.996139f
+#define ALPHA_Float_24 0.994545f
+#define ALPHA_Float_25 0.992295f
+#define ALPHA_Float_26 0.989123f
+#define ALPHA_Float_27 0.984654f
+#define ALPHA_Float_28 0.978370f
+#define ALPHA_Float_29 0.969553f
+#define ALPHA_Float_30 0.957221f
+#define ALPHA_Float_31 0.940051f
+#define ALPHA_Float_32 0.916297f
+#define ALPHA_Float_33 0.883729f
+#define ALPHA_Float_34 0.839645f
+#define ALPHA_Float_35 0.781036f
+#define ALPHA_Float_36 0.705078f
+#define ALPHA_Float_37 0.610108f
+#define ALPHA_Float_38 0.497239f
+#define ALPHA_Float_39 0.372343f
+#define ALPHA_Float_40 0.247351f
+#define ALPHA_Float_41 0.138722f
+#define ALPHA_Float_42 0.061234f
+#define ALPHA_Float_43 0.019267f
+#define ALPHA_Float_44 0.003756f
+#define ALPHA_Float_45 0.000372f
+#define ALPHA_Float_46 0.000014f
+#define ALPHA_Float_47 0.000000f
+#define ALPHA_Float_48 0.000000f
+#define ALPHA_Float_49 0.000000f
+#define ALPHA_Float_50 0.000000f
+#endif
#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Mixer_TimeConstant.c b/media/libeffects/lvm/lib/Common/src/LVM_Mixer_TimeConstant.c
index 809d904..18b2782 100644
--- a/media/libeffects/lvm/lib/Common/src/LVM_Mixer_TimeConstant.c
+++ b/media/libeffects/lvm/lib/Common/src/LVM_Mixer_TimeConstant.c
@@ -57,7 +57,110 @@
/* Alpha - the filter coefficient Q31 format */
/* */
/************************************************************************/
+#ifdef BUILD_FLOAT
+LVM_FLOAT LVM_Mixer_TimeConstant(LVM_UINT32 tc,
+#ifdef HIGHER_FS
+ LVM_UINT32 Fs,
+#else
+ LVM_UINT16 Fs,
+#endif
+ LVM_UINT16 NumChannels)
+{
+ LVM_UINT32 Product;
+ LVM_FLOAT ProductFloat;
+ LVM_INT16 InterpolateShort;
+ LVM_FLOAT Interpolate;
+ LVM_UINT16 Shift;
+ LVM_FLOAT Diff;
+ LVM_FLOAT Table[] = {ALPHA_Float_0, /* Log spaced look-up table */
+ ALPHA_Float_1,
+ ALPHA_Float_2,
+ ALPHA_Float_3,
+ ALPHA_Float_4,
+ ALPHA_Float_5,
+ ALPHA_Float_6,
+ ALPHA_Float_7,
+ ALPHA_Float_8,
+ ALPHA_Float_9,
+ ALPHA_Float_10,
+ ALPHA_Float_11,
+ ALPHA_Float_12,
+ ALPHA_Float_13,
+ ALPHA_Float_14,
+ ALPHA_Float_15,
+ ALPHA_Float_16,
+ ALPHA_Float_17,
+ ALPHA_Float_18,
+ ALPHA_Float_19,
+ ALPHA_Float_20,
+ ALPHA_Float_21,
+ ALPHA_Float_22,
+ ALPHA_Float_23,
+ ALPHA_Float_24,
+ ALPHA_Float_25,
+ ALPHA_Float_26,
+ ALPHA_Float_27,
+ ALPHA_Float_28,
+ ALPHA_Float_29,
+ ALPHA_Float_30,
+ ALPHA_Float_31,
+ ALPHA_Float_32,
+ ALPHA_Float_33,
+ ALPHA_Float_34,
+ ALPHA_Float_35,
+ ALPHA_Float_36,
+ ALPHA_Float_37,
+ ALPHA_Float_38,
+ ALPHA_Float_39,
+ ALPHA_Float_40,
+ ALPHA_Float_41,
+ ALPHA_Float_42,
+ ALPHA_Float_43,
+ ALPHA_Float_44,
+ ALPHA_Float_45,
+ ALPHA_Float_46,
+ ALPHA_Float_47,
+ ALPHA_Float_48,
+ ALPHA_Float_49,
+ ALPHA_Float_50};
+
+ /* Calculate the product of the time constant and the sample rate */
+ Product = ((tc >> 16) * (LVM_UINT32)Fs) << 13; /* Stereo value */
+ Product = Product + (((tc & 0x0000FFFF) * (LVM_UINT32)Fs) >> 3);
+
+ if (NumChannels == 1)
+ {
+ Product = Product >> 1; /* Mono value */
+ }
+
+ /* Normalize to get the table index and interpolation factor */
+ for (Shift = 0; Shift < ((Alpha_TableSize - 1) / 2); Shift++)
+ {
+ if ((Product & 0x80000000) != 0)
+ {
+ break;
+ }
+
+ Product = Product << 1;
+ }
+ Shift = (LVM_UINT16)((Shift << 1));
+
+ if ((Product & 0x40000000)==0)
+ {
+ Shift++;
+ }
+
+ InterpolateShort = (LVM_INT16)((Product >> 15) & 0x00007FFF);
+ Interpolate = (LVM_FLOAT)InterpolateShort / 32768.0f;
+
+ Diff = (Table[Shift] - Table[Shift + 1]);
+ Diff = Diff * Interpolate;
+ ProductFloat = Table[Shift + 1] + Diff;
+
+ return ProductFloat;
+}
+#else
LVM_UINT32 LVM_Mixer_TimeConstant(LVM_UINT32 tc,
LVM_UINT16 Fs,
LVM_UINT16 NumChannels)
@@ -154,3 +257,4 @@
return Product;
}
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Polynomial.c b/media/libeffects/lvm/lib/Common/src/LVM_Polynomial.c
index a6d7db2..cd57767 100644
--- a/media/libeffects/lvm/lib/Common/src/LVM_Polynomial.c
+++ b/media/libeffects/lvm/lib/Common/src/LVM_Polynomial.c
@@ -25,7 +25,7 @@
/* */
/* DESCRIPTION: */
/* This function performs polynomial expansion */
-/* Y = (A0 + A1*X + A2*X2 + A3*X3 + Â….. + AN*xN) << AN+1 */
+/* Y = (A0 + A1*X + A2*X2 + A3*X3 + �.. + AN*xN) << AN+1 */
/* */
/* LVM_INT32 LVM_Polynomial(LVM_UINT16 N, */
/* LVM_INT32 *pCoefficients, */
@@ -40,7 +40,48 @@
/* RETURNS: */
/* The result of the polynomial expansion in Q1.31 format */
/*-------------------------------------------------------------------------*/
+#ifdef BUILD_FLOAT
+LVM_FLOAT LVM_Polynomial(LVM_UINT16 N,
+ LVM_FLOAT *pCoefficients,
+ LVM_FLOAT X)
+{
+ LVM_INT32 i;
+ LVM_FLOAT Y,A,XTemp,Temp,sign;
+ Y = *pCoefficients; /* Y=A0*/
+ pCoefficients++;
+
+ if(X == -1.0f)
+ {
+ Temp = -1;
+ sign = Temp;
+ for(i = 1; i <= N; i++)
+ {
+ Y += ((*pCoefficients) * sign);
+ pCoefficients++;
+ sign *= Temp;
+ }
+
+
+ }
+ else
+ {
+ XTemp = X;
+ for(i = N-1; i >= 0; i--)
+ {
+ A = *pCoefficients;
+ pCoefficients++;
+
+ Temp = A * XTemp;
+ Y += Temp;
+
+ Temp = XTemp * X;
+ XTemp = Temp;
+ }
+ }
+ return Y;
+}
+#else
LVM_INT32 LVM_Polynomial(LVM_UINT16 N,
LVM_INT32 *pCoefficients,
LVM_INT32 X)
@@ -93,4 +134,4 @@
}
return Y;
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Power10.c b/media/libeffects/lvm/lib/Common/src/LVM_Power10.c
index 6ca1077..8785594 100644
--- a/media/libeffects/lvm/lib/Common/src/LVM_Power10.c
+++ b/media/libeffects/lvm/lib/Common/src/LVM_Power10.c
@@ -44,7 +44,7 @@
/* A11 50477244 */
/* A12 -2 */
/* */
-/* Y = (A0 + A1*X + A2*X2 + A3*X3 + Â….. + AN*xN) << AN+1 */
+/* Y = (A0 + A1*X + A2*X2 + A3*X3 + �.. + AN*xN) << AN+1 */
/* */
/* */
/* PARAMETERS: */
@@ -54,7 +54,28 @@
/* RETURNS: */
/* The result of the 10x expansion in Q8.24 format */
/*-------------------------------------------------------------------------*/
-
+#ifdef BUILD_FLOAT
+LVM_FLOAT LVM_Power10(LVM_FLOAT X)
+{
+ LVM_FLOAT Y,Coefficients[13]={0.999906f,
+ 2.302475f,
+ 2.652765f,
+ 2.035494f,
+ 1.165667f,
+ 0.537676f,
+ 0.213192f,
+ 0.069603f,
+ 0.016553f,
+ 0.004373f,
+ 0.001817f,
+ 0.000367f,
+ 0};
+ Y=LVM_Polynomial((LVM_UINT16)11,
+ Coefficients,
+ X);
+ return Y;
+}
+#else
LVM_INT32 LVM_Power10(LVM_INT32 X)
{
LVM_INT32 Y,Coefficients[13]={ 16775636,
@@ -75,4 +96,4 @@
X);
return Y;
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LoadConst_32.c b/media/libeffects/lvm/lib/Common/src/LoadConst_32.c
index 2f1e591..9e14c3b 100644
--- a/media/libeffects/lvm/lib/Common/src/LoadConst_32.c
+++ b/media/libeffects/lvm/lib/Common/src/LoadConst_32.c
@@ -24,7 +24,22 @@
/**********************************************************************************
FUNCTION LoadConst_32
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void LoadConst_Float(const LVM_FLOAT val,
+ LVM_FLOAT *dst,
+ LVM_INT16 n )
+{
+ LVM_INT16 ii;
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = val;
+ dst++;
+ }
+
+ return;
+}
+#else
void LoadConst_32(const LVM_INT32 val,
LVM_INT32 *dst,
LVM_INT16 n )
@@ -39,5 +54,6 @@
return;
}
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/MSTo2i_Sat_16x16.c b/media/libeffects/lvm/lib/Common/src/MSTo2i_Sat_16x16.c
index 26297e7..02c906a 100644
--- a/media/libeffects/lvm/lib/Common/src/MSTo2i_Sat_16x16.c
+++ b/media/libeffects/lvm/lib/Common/src/MSTo2i_Sat_16x16.c
@@ -77,4 +77,58 @@
return;
}
+#ifdef BUILD_FLOAT
+void MSTo2i_Sat_Float(const LVM_FLOAT *srcM,
+ const LVM_FLOAT *srcS,
+ LVM_FLOAT *dst,
+ LVM_INT16 n )
+{
+ LVM_FLOAT temp,mVal,sVal;
+ LVM_INT16 ii;
+
+
+ for (ii = n; ii != 0; ii--)
+ {
+ mVal = (LVM_FLOAT)*srcM;
+ srcM++;
+
+ sVal = (LVM_FLOAT)*srcS;
+ srcS++;
+
+ temp = mVal + sVal;
+
+ if (temp > 1.0f)
+ {
+ *dst = 1.0f;
+ }
+ else if (temp < -1.0f)
+ {
+ *dst = -1.0f;
+ }
+ else
+ {
+ *dst = (LVM_FLOAT)temp;
+ }
+ dst++;
+
+ temp = mVal - sVal;
+
+ if (temp > 1.0f)
+ {
+ *dst = 1.0f;
+ }
+ else if (temp < -1.0f)
+ {
+ *dst = - 1.0f;
+ }
+ else
+ {
+ *dst = (LVM_FLOAT)temp;
+ }
+ dst++;
+ }
+
+ return;
+}
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_32x16.c b/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_32x16.c
index f28f366..e3fb40d 100644
--- a/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_32x16.c
+++ b/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_32x16.c
@@ -64,7 +64,44 @@
return;
}
+#ifdef BUILD_FLOAT
+void Mac3s_Sat_Float(const LVM_FLOAT *src,
+ const LVM_FLOAT val,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 ii;
+ LVM_FLOAT srcval;
+ LVM_FLOAT Temp,dInVal;
+ for (ii = n; ii != 0; ii--)
+ {
+ srcval = *src;
+ src++;
+
+ Temp = srcval * val;
+
+ dInVal = (LVM_FLOAT)*dst;
+ Temp = Temp + dInVal;
+
+ if (Temp > 1.000000f)
+ {
+ *dst = 1.000000f;
+ }
+ else if (Temp < -1.000000f)
+ {
+ *dst = -1.000000f;
+ }
+ else
+ {
+ *dst = Temp;
+ }
+ dst++;
+ }
+
+ return;
+}
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/MixInSoft_D32C31_SAT.c b/media/libeffects/lvm/lib/Common/src/MixInSoft_D32C31_SAT.c
index 73c26ed..16e367b 100644
--- a/media/libeffects/lvm/lib/Common/src/MixInSoft_D32C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/MixInSoft_D32C31_SAT.c
@@ -32,7 +32,71 @@
/**********************************************************************************
FUNCTION MIXINSOFT_D32C31_SAT
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void MixInSoft_D32C31_SAT( Mix_1St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ char HardMixing = TRUE;
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if (pInstance->Current != pInstance->Target)
+ {
+ if(pInstance->Alpha == 0){
+ pInstance->Current = pInstance->Target;
+ }else if ((pInstance->Current-pInstance->Target < POINT_ZERO_ONE_DB_FLOAT) &&
+ (pInstance->Current-pInstance->Target > -POINT_ZERO_ONE_DB_FLOAT)){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ }else{
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ Core_MixInSoft_D32C31_SAT(pInstance, src, dst, n);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing){
+ if (pInstance->Target != 0){ /* Nothing to do in case Target = 0 */
+ if ((pInstance->Target) == 1.0f)
+ Add2_Sat_Float(src, dst, n);
+ else{
+ Core_MixInSoft_D32C31_SAT(pInstance, src, dst, n);
+ pInstance->Current = pInstance->Target; /* In case the core function would \
+ have changed the Current value */
+ }
+ }
+ }
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+ /* Call back before the hard mixing, because in this case, hard mixing makes
+ use of the core soft mix function which can change the Current value! */
+
+ if (pInstance->CallbackSet){
+ if ((pInstance->Current - pInstance->Target < POINT_ZERO_ONE_DB_FLOAT) &&
+ (pInstance->Current - pInstance->Target > -POINT_ZERO_ONE_DB_FLOAT)){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ pInstance->CallbackSet = FALSE;
+ if (pInstance->pCallBack != 0){
+ (*pInstance->pCallBack) ( pInstance->pCallbackHandle,
+ pInstance->pGeneralPurpose,
+ pInstance->CallbackParam );
+ }
+ }
+ }
+}
+#else
void MixInSoft_D32C31_SAT( Mix_1St_Cll_t *pInstance,
const LVM_INT32 *src,
LVM_INT32 *dst,
@@ -91,5 +155,5 @@
}
}
}
-
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/MixSoft_1St_D32C31_WRA.c b/media/libeffects/lvm/lib/Common/src/MixSoft_1St_D32C31_WRA.c
index ca88b04..869293b 100644
--- a/media/libeffects/lvm/lib/Common/src/MixSoft_1St_D32C31_WRA.c
+++ b/media/libeffects/lvm/lib/Common/src/MixSoft_1St_D32C31_WRA.c
@@ -34,7 +34,68 @@
/**********************************************************************************
FUNCTION MIXSOFT_1ST_D32C31_WRA
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void MixSoft_1St_D32C31_WRA( Mix_1St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ char HardMixing = TRUE;
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if (pInstance->Current != pInstance->Target)
+ {
+ if(pInstance->Alpha == 0){
+ pInstance->Current = pInstance->Target;
+ }else if ((pInstance->Current - pInstance->Target < POINT_ZERO_ONE_DB_FLOAT) &&
+ (pInstance->Current - pInstance->Target > -POINT_ZERO_ONE_DB_FLOAT)){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ }else{
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ Core_MixSoft_1St_D32C31_WRA(pInstance, src, dst, n);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing){
+ if (pInstance->Target == 0)
+ LoadConst_Float(0, dst, n);
+ else if ((pInstance->Target) == 1.0f){
+ if (src != dst)
+ Copy_Float((LVM_FLOAT*)src, (LVM_FLOAT*)dst, (LVM_INT16)(n));
+ }
+ else
+ Mult3s_Float(src, pInstance->Current, dst, n);
+ }
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+
+ if (pInstance->CallbackSet){
+ if ((pInstance->Current - pInstance->Target < POINT_ZERO_ONE_DB_FLOAT) &&
+ (pInstance->Current - pInstance->Target > -POINT_ZERO_ONE_DB_FLOAT)){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ pInstance->CallbackSet = FALSE;
+ if (pInstance->pCallBack != 0){
+ (*pInstance->pCallBack) ( pInstance->pCallbackHandle,
+ pInstance->pGeneralPurpose,
+ pInstance->CallbackParam );
+ }
+ }
+ }
+}
+#else
void MixSoft_1St_D32C31_WRA( Mix_1St_Cll_t *pInstance,
const LVM_INT32 *src,
LVM_INT32 *dst,
@@ -91,5 +152,5 @@
}
}
}
-
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/MixSoft_2St_D32C31_SAT.c b/media/libeffects/lvm/lib/Common/src/MixSoft_2St_D32C31_SAT.c
index 2e0a099..6fc1b92 100644
--- a/media/libeffects/lvm/lib/Common/src/MixSoft_2St_D32C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/MixSoft_2St_D32C31_SAT.c
@@ -26,7 +26,44 @@
/**********************************************************************************
FUNCTION MIXSOFT_2ST_D32C31_SAT
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void MixSoft_2St_D32C31_SAT( Mix_2St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src1,
+ const LVM_FLOAT *src2,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if ((pInstance->Current1 != pInstance->Target1) || (pInstance->Current2 != pInstance->Target2))
+ {
+ MixSoft_1St_D32C31_WRA((Mix_1St_Cll_FLOAT_t*)pInstance, src1, dst, n);
+ MixInSoft_D32C31_SAT((void *)&pInstance->Alpha2, /* Cast to void: \
+ no dereferencing in function*/
+ src2, dst, n);
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ else
+ {
+ if (pInstance->Current1 == 0)
+ MixSoft_1St_D32C31_WRA((void *) &pInstance->Alpha2, /* Cast to void: no \
+ dereferencing in function*/
+ src2, dst, n);
+ else if (pInstance->Current2 == 0)
+ MixSoft_1St_D32C31_WRA((Mix_1St_Cll_FLOAT_t*) pInstance, src1, dst, n);
+ else
+ Core_MixHard_2St_D32C31_SAT(pInstance, src1, src2, dst, n);
+ }
+}
+#else
void MixSoft_2St_D32C31_SAT( Mix_2St_Cll_t *pInstance,
const LVM_INT32 *src1,
const LVM_INT32 *src2,
@@ -61,5 +98,6 @@
Core_MixHard_2St_D32C31_SAT( pInstance, src1, src2, dst, n);
}
}
-
+#endif
/**********************************************************************************/
+
diff --git a/media/libeffects/lvm/lib/Common/src/Mixer_private.h b/media/libeffects/lvm/lib/Common/src/Mixer_private.h
index 607073c..00d55ed 100644
--- a/media/libeffects/lvm/lib/Common/src/Mixer_private.h
+++ b/media/libeffects/lvm/lib/Common/src/Mixer_private.h
@@ -26,6 +26,10 @@
#define POINT_ZERO_ONE_DB 2473805 /* 0.01 dB on a full scale signal = (10^(0.01/20) -1) * 2^31 */
+#ifdef BUILD_FLOAT
+#define POINT_ZERO_ONE_DB_FLOAT 0.001152 /* 0.01 dB on a full scale \
+ signal = (10^(0.01/20) -1) * 2^31 */
+#endif
/**********************************************************************************
DEFINITIONS
***********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/MonoTo2I_32.c b/media/libeffects/lvm/lib/Common/src/MonoTo2I_32.c
index c09ec0f..796a15c 100644
--- a/media/libeffects/lvm/lib/Common/src/MonoTo2I_32.c
+++ b/media/libeffects/lvm/lib/Common/src/MonoTo2I_32.c
@@ -45,5 +45,26 @@
return;
}
+#ifdef BUILD_FLOAT
+void MonoTo2I_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 ii;
+ src += (n - 1);
+ dst += ((n * 2) - 1);
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = *src;
+ dst--;
+
+ *dst = *src;
+ dst--;
+ src--;
+ }
+
+ return;
+}
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Mult3s_32x16.c b/media/libeffects/lvm/lib/Common/src/Mult3s_32x16.c
index a5dc50f..c758560 100644
--- a/media/libeffects/lvm/lib/Common/src/Mult3s_32x16.c
+++ b/media/libeffects/lvm/lib/Common/src/Mult3s_32x16.c
@@ -47,5 +47,23 @@
return;
}
+#ifdef BUILD_FLOAT
+void Mult3s_Float( const LVM_FLOAT *src,
+ const LVM_FLOAT val,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 ii;
+ LVM_FLOAT temp;
+ for (ii = n; ii != 0; ii--)
+ {
+ temp = (*src) * val;
+ src++;
+ *dst = temp;
+ dst++;
+ }
+ return;
+}
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/NonLinComp_D16.c b/media/libeffects/lvm/lib/Common/src/NonLinComp_D16.c
index 73343cd..5156edc 100644
--- a/media/libeffects/lvm/lib/Common/src/NonLinComp_D16.c
+++ b/media/libeffects/lvm/lib/Common/src/NonLinComp_D16.c
@@ -114,4 +114,54 @@
}
}
+#ifdef BUILD_FLOAT
+void NonLinComp_Float(LVM_FLOAT Gain,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT32 BlockLength)
+{
+ LVM_FLOAT Sample; /* Input samples */
+ LVM_INT32 SampleNo; /* Sample index */
+ LVM_FLOAT Temp;
+
+
+ /*
+ * Process a block of samples
+ */
+ for(SampleNo = 0; SampleNo < BlockLength; SampleNo++)
+ {
+ /*
+ * Read the input
+ */
+ Sample = *pDataIn;
+ pDataIn++;
+
+
+ /*
+ * Apply the compander, this compresses the signal at the expense of
+ * harmonic distortion. The amount of compression is control by the
+ * gain factor
+ */
+ if (Sample != -1.0f)
+ {
+ Temp = ((Sample * Sample));
+ if(Sample > 0)
+ {
+ Sample = (Sample + ((Gain * (Sample - Temp)) ));
+ }
+ else
+ {
+ Sample = (Sample + ((Gain * (Sample + Temp)) ));
+ }
+ }
+
+
+ /*
+ * Save the output
+ */
+ *pDataOut = Sample;
+ pDataOut++;
+ }
+}
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c
index c8c1527..9c17a05 100644
--- a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c
@@ -38,6 +38,88 @@
pBiquadState->pDelays[6] is y(n-2)L in Q0 format
pBiquadState->pDelays[7] is y(n-2)R in Q0 format
***************************************************************************/
+#ifdef BUILD_FLOAT
+void PK_2I_D32F32C14G11_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR,ynLO,ynRO,templ;
+ LVM_INT16 ii;
+ PFilter_State_Float pBiquadState = (PFilter_State_Float) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ /* ynL= (A0 * (x(n)L - x(n-2)L ) )*/
+ templ = (*pDataIn) - pBiquadState->pDelays[2];
+ ynL = templ * pBiquadState->coefs[0];
+
+ /* ynL+= ((-B2 * y(n-2)L )) */
+ templ = pBiquadState->pDelays[6] * pBiquadState->coefs[1];
+ ynL += templ;
+
+ /* ynL+= ((-B1 * y(n-1)L ) ) */
+ templ = pBiquadState->pDelays[4] * pBiquadState->coefs[2];
+ ynL += templ;
+
+ /* ynLO= ((Gain * ynL )) */
+ ynLO = ynL * pBiquadState->coefs[3];
+
+ /* ynLO=( ynLO + x(n)L )*/
+ ynLO += (*pDataIn);
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ /* ynR= (A0 * (x(n)R - x(n-2)R ) ) */
+ templ = (*(pDataIn + 1)) - pBiquadState->pDelays[3];
+ ynR = templ * pBiquadState->coefs[0];
+
+ /* ynR+= ((-B2 * y(n-2)R ) ) */
+ templ = pBiquadState->pDelays[7] * pBiquadState->coefs[1];
+ ynR += templ;
+
+ /* ynR+= ((-B1 * y(n-1)R ) ) */
+ templ = pBiquadState->pDelays[5] * pBiquadState->coefs[2];
+ ynR += templ;
+
+ /* ynRO= ((Gain * ynR )) */
+ ynRO = ynR * pBiquadState->coefs[3];
+
+ /* ynRO=( ynRO + x(n)R )*/
+ ynRO += (*(pDataIn+1));
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
+ pBiquadState->pDelays[5] = ynR; /* Update y(n-1)R */
+ pBiquadState->pDelays[4] = ynL; /* Update y(n-1)L */
+ pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L */
+ pDataIn++;
+ pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R */
+ pDataIn++;
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut = ynLO; /* Write Left output*/
+ pDataOut++;
+ *pDataOut = ynRO; /* Write Right ouput*/
+ pDataOut++;
+
+ }
+
+ }
+#else
void PK_2I_D32F32C14G11_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT32 *pDataIn,
LVM_INT32 *pDataOut,
@@ -118,4 +200,4 @@
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.c
index 67a570b..f705cbf 100644
--- a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.c
@@ -38,6 +38,7 @@
pBiquadState->pDelays[6] is y(n-2)L in Q0 format
pBiquadState->pDelays[7] is y(n-2)R in Q0 format
***************************************************************************/
+#ifndef BUILD_FLOAT
void PK_2I_D32F32C30G11_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
LVM_INT32 *pDataIn,
LVM_INT32 *pDataOut,
@@ -116,4 +117,4 @@
}
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.c
index 1d6142c..65475a3 100644
--- a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.c
@@ -18,7 +18,7 @@
#include "BIQUAD.h"
#include "PK_2I_D32F32CllGss_TRC_WRA_01_Private.h"
-
+#ifndef BUILD_FLOAT
void PK_2I_D32F32CllGss_TRC_WRA_01_Init(Biquad_Instance_t *pInstance,
Biquad_2I_Order2_Taps_t *pTaps,
PK_C32_Coefs_t *pCoef)
@@ -35,4 +35,4 @@
pBiquadState->coefs[3]=pCoef->G;
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.c
index b9f64e6..a36330e 100644
--- a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.c
@@ -17,7 +17,23 @@
#include "BIQUAD.h"
#include "PK_2I_D32F32CssGss_TRC_WRA_01_Private.h"
+#ifdef BUILD_FLOAT
+void PK_2I_D32F32CssGss_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
+ PK_FLOAT_Coefs_t *pCoef)
+{
+ PFilter_State_Float pBiquadState = (PFilter_State_Float) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
+ pBiquadState->coefs[0] = pCoef->A0;
+
+ pBiquadState->coefs[1] = pCoef->B2;
+
+ pBiquadState->coefs[2] = pCoef->B1;
+
+ pBiquadState->coefs[3] = pCoef->G;
+}
+#else
void PK_2I_D32F32CssGss_TRC_WRA_01_Init(Biquad_Instance_t *pInstance,
Biquad_2I_Order2_Taps_t *pTaps,
PK_C16_Coefs_t *pCoef)
@@ -34,4 +50,4 @@
pBiquadState->coefs[3]=pCoef->G;
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Private.h
index e2050e0..1e32062 100644
--- a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Private.h
@@ -21,6 +21,16 @@
/* The internal state variables are implemented in a (for the user) hidden structure */
/* In this (private) file, the internal structure is declared fro private use. */
+
+#ifdef BUILD_FLOAT
+typedef struct _Filter_State_Float_
+{
+ LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
+ LVM_FLOAT coefs[5]; /* pointer to the filter coefficients */
+}Filter_State_Float;
+
+typedef Filter_State_Float * PFilter_State_Float ;
+#endif
typedef struct _Filter_State_
{
LVM_INT32 * pDelays; /* pointer to the delayed samples (data of 32 bits) */
diff --git a/media/libeffects/lvm/lib/Common/src/Shift_Sat_v16xv16.c b/media/libeffects/lvm/lib/Common/src/Shift_Sat_v16xv16.c
index 8363270..28fea65 100644
--- a/media/libeffects/lvm/lib/Common/src/Shift_Sat_v16xv16.c
+++ b/media/libeffects/lvm/lib/Common/src/Shift_Sat_v16xv16.c
@@ -24,7 +24,7 @@
/**********************************************************************************
FUNCTION Shift_Sat_v16xv16
***********************************************************************************/
-
+#ifndef BUILD_FLOAT
void Shift_Sat_v16xv16 (const LVM_INT16 val,
const LVM_INT16 *src,
LVM_INT16 *dst,
@@ -77,5 +77,5 @@
}
return;
}
-
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Shift_Sat_v32xv32.c b/media/libeffects/lvm/lib/Common/src/Shift_Sat_v32xv32.c
index fbd132e..fac9de7 100644
--- a/media/libeffects/lvm/lib/Common/src/Shift_Sat_v32xv32.c
+++ b/media/libeffects/lvm/lib/Common/src/Shift_Sat_v32xv32.c
@@ -24,7 +24,62 @@
/**********************************************************************************
FUNCTION Shift_Sat_v32xv32
***********************************************************************************/
+#ifdef BUILD_FLOAT
+void Shift_Sat_Float (const LVM_INT16 val,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_FLOAT temp;
+ LVM_INT32 ii,ij;
+ LVM_INT16 RShift;
+ if(val > 0)
+ {
+ for (ii = n; ii != 0; ii--)
+ {
+ temp = (LVM_FLOAT)*src;
+ src++;
+ for(ij = 0; ij < val; ij++)
+ {
+ temp = temp * 2;
+ }
+
+ if(temp > 1.0)
+ temp = 1.0;
+ if(temp < -1.0)
+ temp = -1.0;
+
+ *dst = (LVM_FLOAT)temp;
+ dst++;
+ }
+ }
+ else if(val < 0)
+ {
+ RShift=(LVM_INT16)(-val);
+
+ for (ii = n; ii != 0; ii--)
+ {
+ temp = (LVM_FLOAT)*src;
+ src++;
+ for(ij = 0; ij < RShift; ij++)
+ {
+ temp = temp / 2;
+ }
+ *dst = (LVM_FLOAT)temp;
+ dst++;
+ }
+ }
+ else
+ {
+ if(src != dst)
+ {
+ Copy_Float(src, dst, n);
+ }
+ }
+ return;
+}
+#else
void Shift_Sat_v32xv32 (const LVM_INT16 val,
const LVM_INT32 *src,
LVM_INT32 *dst,
@@ -79,5 +134,5 @@
}
return;
}
-
+#endif
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/dB_to_Lin32.c b/media/libeffects/lvm/lib/Common/src/dB_to_Lin32.c
index ac0343f..9a726f2 100644
--- a/media/libeffects/lvm/lib/Common/src/dB_to_Lin32.c
+++ b/media/libeffects/lvm/lib/Common/src/dB_to_Lin32.c
@@ -29,6 +29,9 @@
/*######################################################################################*/
#include "ScalarArithmetic.h"
+#ifdef BUILD_FLOAT
+#include <math.h>
+#endif
/****************************************************************************************
@@ -64,6 +67,18 @@
#define SECOND_COEF 38836
#define MAX_VALUE 1536 /* 96 * 16 */
+#ifdef BUILD_FLOAT
+LVM_FLOAT dB_to_LinFloat(LVM_INT16 db_fix)
+{
+ LVM_FLOAT dB_Float;
+ LVM_FLOAT LinFloat;
+
+ dB_Float = (LVM_FLOAT)((LVM_FLOAT)db_fix / 16.0f);
+ LinFloat = pow(10, dB_Float / 20.0);
+
+ return LinFloat;
+}
+#else
LVM_INT32 dB_to_Lin32(LVM_INT16 db_fix)
{
LVM_INT32 Lin_val_32;
@@ -106,4 +121,4 @@
return Lin_val_32; /* format 1.16.15 */
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h b/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
index db6aabe..8e0b738 100644
--- a/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
+++ b/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
@@ -200,6 +200,10 @@
#define LVEQNB_CAP_FS_32000 64
#define LVEQNB_CAP_FS_44100 128
#define LVEQNB_CAP_FS_48000 256
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+#define LVEQNB_CAP_FS_96000 512
+#define LVEQNB_CAP_FS_192000 1024
+#endif
typedef enum
{
@@ -212,6 +216,10 @@
LVEQNB_FS_32000 = 6,
LVEQNB_FS_44100 = 7,
LVEQNB_FS_48000 = 8,
+#ifdef HIGHER_FS
+ LVEQNB_FS_96000 = 9,
+ LVEQNB_FS_192000 = 10,
+#endif
LVEQNB_FS_MAX = LVM_MAXINT_32
} LVEQNB_Fs_en;
@@ -268,6 +276,7 @@
{
/* General parameters */
LVM_UINT16 SampleRate;
+
LVM_UINT16 SourceFormat;
LVM_UINT16 MaxBlockSize;
LVM_UINT16 MaxBands;
@@ -460,11 +469,17 @@
/* NOTES: */
/* */
/****************************************************************************************/
-
+#ifdef BUILD_FLOAT
+LVEQNB_ReturnStatus_en LVEQNB_Process(LVEQNB_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples);
+#else
LVEQNB_ReturnStatus_en LVEQNB_Process(LVEQNB_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 *pOutData,
LVM_UINT16 NumSamples);
+#endif
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_CalcCoef.c b/media/libeffects/lvm/lib/Eq/src/LVEQNB_CalcCoef.c
index fddedb9..ff52b7f 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_CalcCoef.c
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_CalcCoef.c
@@ -22,7 +22,9 @@
/****************************************************************************************/
#include "LVEQNB_Private.h"
-
+#ifdef BUILD_FLOAT
+#include <math.h>
+#endif
/****************************************************************************************/
/* */
@@ -77,6 +79,7 @@
/****************************************************************************************/
+#ifndef BUILD_FLOAT
LVEQNB_ReturnStatus_en LVEQNB_DoublePrecCoefs(LVM_UINT16 Fs,
LVEQNB_BandDef_t *pFilterDefinition,
PK_C32_Coefs_t *pCoefficients)
@@ -168,7 +171,7 @@
return(LVEQNB_SUCCESS);
}
-
+#endif
/****************************************************************************************/
/* */
@@ -205,7 +208,67 @@
/* */
/****************************************************************************************/
+#ifdef BUILD_FLOAT
+LVEQNB_ReturnStatus_en LVEQNB_SinglePrecCoefs(LVM_UINT16 Fs,
+ LVEQNB_BandDef_t *pFilterDefinition,
+ PK_FLOAT_Coefs_t *pCoefficients)
+{
+ extern LVM_FLOAT LVEQNB_GainTable[];
+ extern LVM_FLOAT LVEQNB_TwoPiOnFsTable[];
+ extern LVM_FLOAT LVEQNB_DTable[];
+
+
+ /*
+ * Get the filter definition
+ */
+ LVM_INT16 Gain = pFilterDefinition->Gain;
+ LVM_UINT16 Frequency = pFilterDefinition->Frequency;
+ /* As mentioned in effectbundle.h */
+ LVM_FLOAT QFactor = (LVM_FLOAT)pFilterDefinition->QFactor / 100.0f;
+
+
+ /*
+ * Intermediate variables and temporary values
+ */
+ LVM_FLOAT T0;
+ LVM_FLOAT D;
+ LVM_FLOAT A0;
+ LVM_FLOAT B1;
+ LVM_FLOAT B2;
+
+ /*
+ * Calculating the intermediate values
+ */
+ T0 = Frequency * LVEQNB_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
+ if (Gain >= 0)
+ {
+ D = LVEQNB_DTable[15]; /* D = 1 if GaindB >= 0 */
+ }
+ else
+ {
+ D = LVEQNB_DTable[Gain + 15]; /* D = 1 / (1 + G) if GaindB < 0 */
+ }
+
+ /*
+ * Calculate the B2,B1,A0 coefficients
+ */
+ B2 = -0.5 * (2 * QFactor - D * T0) / (2 * QFactor + D * T0);
+ B1 = (0.5 - B2) * cos(T0);
+ A0 = (0.5 + B2) / 2.0;
+
+ /*
+ * Write coeff into the data structure
+ */
+ /* all the coefficients are multiplied with 2 to make them align with fixed point values*/
+ pCoefficients->A0 = 2 * A0;
+ pCoefficients->B1 = 2 * B1;
+ pCoefficients->B2 = 2 * B2;
+ pCoefficients->G = LVEQNB_GainTable[Gain + 15];
+
+ return(LVEQNB_SUCCESS);
+}
+#else
LVEQNB_ReturnStatus_en LVEQNB_SinglePrecCoefs(LVM_UINT16 Fs,
LVEQNB_BandDef_t *pFilterDefinition,
PK_C16_Coefs_t *pCoefficients)
@@ -296,3 +359,4 @@
return(LVEQNB_SUCCESS);
}
+#endif
\ No newline at end of file
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Coeffs.h b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Coeffs.h
index 95212f2..f0deb6c 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Coeffs.h
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Coeffs.h
@@ -25,7 +25,39 @@
/* Gain table for (10^(Gain/20) - 1) */
/* */
/************************************************************************************/
-
+#ifdef BUILD_FLOAT
+#define LVEQNB_Gain_Neg15_dB -0.822172f
+#define LVEQNB_Gain_Neg14_dB -0.800474f
+#define LVEQNB_Gain_Neg13_dB -0.776128f
+#define LVEQNB_Gain_Neg12_dB -0.748811f
+#define LVEQNB_Gain_Neg11_dB -0.718162f
+#define LVEQNB_Gain_Neg10_dB -0.683772f
+#define LVEQNB_Gain_Neg9_dB -0.645187f
+#define LVEQNB_Gain_Neg8_dB -0.601893f
+#define LVEQNB_Gain_Neg7_dB -0.553316f
+#define LVEQNB_Gain_Neg6_dB -0.498813f
+#define LVEQNB_Gain_Neg5_dB -0.437659f
+#define LVEQNB_Gain_Neg4_dB -0.369043f
+#define LVEQNB_Gain_Neg3_dB -0.292054f
+#define LVEQNB_Gain_Neg2_dB -0.205672f
+#define LVEQNB_Gain_Neg1_dB -0.108749f
+#define LVEQNB_Gain_0_dB 0.000000f
+#define LVEQNB_Gain_1_dB 0.122018f
+#define LVEQNB_Gain_2_dB 0.258925f
+#define LVEQNB_Gain_3_dB 0.412538f
+#define LVEQNB_Gain_4_dB 0.584893f
+#define LVEQNB_Gain_5_dB 0.778279f
+#define LVEQNB_Gain_6_dB 0.995262f
+#define LVEQNB_Gain_7_dB 1.238721f
+#define LVEQNB_Gain_8_dB 1.511886f
+#define LVEQNB_Gain_9_dB 1.818383f
+#define LVEQNB_Gain_10_dB 2.162278f
+#define LVEQNB_Gain_11_dB 2.548134f
+#define LVEQNB_Gain_12_dB 2.981072f
+#define LVEQNB_Gain_13_dB 3.466836f
+#define LVEQNB_Gain_14_dB 4.011872f
+#define LVEQNB_Gain_15_dB 4.623413f
+#else
#define LVEQNB_GAINSHIFT 11 /* As a power of 2 */
#define LVEQNB_Gain_Neg15_dB (-1684) /* Floating point value -0.822172 */
#define LVEQNB_Gain_Neg14_dB (-1639) /* Floating point value -0.800474 */
@@ -58,14 +90,30 @@
#define LVEQNB_Gain_13_dB 7100 /* Floating point value 3.466836 */
#define LVEQNB_Gain_14_dB 8216 /* Floating point value 4.011872 */
#define LVEQNB_Gain_15_dB 9469 /* Floating point value 4.623413 */
-
+#endif
/************************************************************************************/
/* */
/* Frequency table for 2*Pi/Fs */
/* */
/************************************************************************************/
+#ifdef BUILD_FLOAT
+#define LVEQNB_2PiOn_8000 0.000785f
+#define LVEQNB_2PiOn_11025 0.000570f
+#define LVEQNB_2PiOn_12000 0.000524f
+#define LVEQNB_2PiOn_16000 0.000393f
+#define LVEQNB_2PiOn_22050 0.000285f
+#define LVEQNB_2PiOn_24000 0.000262f
+#define LVEQNB_2PiOn_32000 0.000196f
+#define LVEQNB_2PiOn_44100 0.000142f
+#define LVEQNB_2PiOn_48000 0.000131f
+#ifdef HIGHER_FS
+#define LVEQNB_2PiOn_96000 0.000065f
+#define LVEQNB_2PiOn_192000 0.000033f
+#endif
+
+#else
#define LVEQNB_FREQSHIFT 25 /* As a power of 2 */
#define LVEQNB_2PiOn_8000 26354 /* Floating point value 0.000785 */
#define LVEQNB_2PiOn_11025 19123 /* Floating point value 0.000570 */
@@ -76,14 +124,31 @@
#define LVEQNB_2PiOn_32000 6588 /* Floating point value 0.000196 */
#define LVEQNB_2PiOn_44100 4781 /* Floating point value 0.000142 */
#define LVEQNB_2PiOn_48000 4392 /* Floating point value 0.000131 */
-
+#endif
/************************************************************************************/
/* */
/* 50D table for 50 / ( 1 + Gain ) */
/* */
/************************************************************************************/
-
+#ifdef BUILD_FLOAT
+#define LVEQNB_100D_Neg15_dB 5.623413f
+#define LVEQNB_100D_Neg14_dB 5.011872f
+#define LVEQNB_100D_Neg13_dB 4.466836f
+#define LVEQNB_100D_Neg12_dB 3.981072f
+#define LVEQNB_100D_Neg11_dB 3.548134f
+#define LVEQNB_100D_Neg10_dB 3.162278f
+#define LVEQNB_100D_Neg9_dB 2.818383f
+#define LVEQNB_100D_Neg8_dB 2.511886f
+#define LVEQNB_100D_Neg7_dB 2.238721f
+#define LVEQNB_100D_Neg6_dB 1.995262f
+#define LVEQNB_100D_Neg5_dB 1.778279f
+#define LVEQNB_100D_Neg4_dB 1.584893f
+#define LVEQNB_100D_Neg3_dB 1.412538f
+#define LVEQNB_100D_Neg2_dB 1.258925f
+#define LVEQNB_100D_Neg1_dB 1.122018f
+#define LVEQNB_100D_0_dB 1.000000f
+#else
#define LVEQNB_100DSHIFT 5 /* As a power of 2 */
#define LVEQNB_100D_Neg15_dB 17995 /* Floating point value 5.623413 */
#define LVEQNB_100D_Neg14_dB 16038 /* Floating point value 5.011872 */
@@ -101,6 +166,6 @@
#define LVEQNB_100D_Neg2_dB 4029 /* Floating point value 1.258925 */
#define LVEQNB_100D_Neg1_dB 3590 /* Floating point value 1.122018 */
#define LVEQNB_100D_0_dB 3200 /* Floating point value 1.000000 */
-
+#endif
#endif
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.c b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.c
index 10e7d74..c290aec 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.c
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.c
@@ -140,8 +140,12 @@
void LVEQNB_SetFilters(LVEQNB_Instance_t *pInstance,
LVEQNB_Params_t *pParams)
{
-
+#ifdef HIGHER_FS
+ extern const LVM_UINT32 LVEQNB_SampleRateTab[]; /* Sample rate table */
+#else
extern const LVM_UINT16 LVEQNB_SampleRateTab[]; /* Sample rate table */
+#endif
+
LVM_UINT16 i; /* Filter band index */
LVM_UINT32 fs = (LVM_UINT32)LVEQNB_SampleRateTab[(LVM_UINT16)pParams->SampleRate]; /* Sample rate */
LVM_UINT32 fc; /* Filter centre frequency */
@@ -158,11 +162,15 @@
fc = (LVM_UINT32)pParams->pBandDefinition[i].Frequency; /* Get the band centre frequency */
QFactor = (LVM_INT16)pParams->pBandDefinition[i].QFactor; /* Get the band Q factor */
-
+#ifdef BUILD_FLOAT
+ pInstance->pBiquadType[i] = LVEQNB_SinglePrecision_Float; /* Default to single precision */
+#else
/*
* For each filter set the type of biquad required
*/
pInstance->pBiquadType[i] = LVEQNB_SinglePrecision; /* Default to single precision */
+#endif
+#ifndef BUILD_FLOAT
if ((fc << 15) <= (LOW_FREQ * fs))
{
/*
@@ -177,7 +185,7 @@
*/
pInstance->pBiquadType[i] = LVEQNB_DoublePrecision;
}
-
+#endif
/*
* Check for out of range frequencies
@@ -230,6 +238,25 @@
BiquadType = pInstance->pBiquadType[i];
switch (BiquadType)
{
+#ifdef BUILD_FLOAT
+ case LVEQNB_SinglePrecision_Float:
+ {
+ PK_FLOAT_Coefs_t Coefficients;
+ /*
+ * Calculate the single precision coefficients
+ */
+ LVEQNB_SinglePrecCoefs((LVM_UINT16)pInstance->Params.SampleRate,
+ &pInstance->pBandDefinitions[i],
+ &Coefficients);
+ /*
+ * Set the coefficients
+ */
+ PK_2I_D32F32CssGss_TRC_WRA_01_Init(&pInstance->pEQNB_FilterState_Float[i],
+ &pInstance->pEQNB_Taps_Float[i],
+ &Coefficients);
+ break;
+ }
+#else
case LVEQNB_DoublePrecision:
{
PK_C32_Coefs_t Coefficients;
@@ -269,6 +296,7 @@
&Coefficients);
break;
}
+#endif
default:
break;
}
@@ -288,7 +316,7 @@
/* pInstance Pointer to the instance */
/* */
/************************************************************************************/
-
+#ifndef BUILD_FLOAT
void LVEQNB_ClearFilterHistory(LVEQNB_Instance_t *pInstance)
{
LVM_INT16 *pTapAddress;
@@ -305,8 +333,24 @@
NumTaps); /* Number of words */
}
}
+#else
+void LVEQNB_ClearFilterHistory(LVEQNB_Instance_t *pInstance)
+{
+ LVM_FLOAT *pTapAddress;
+ LVM_INT16 NumTaps;
+ pTapAddress = (LVM_FLOAT *)pInstance->pEQNB_Taps_Float;
+ NumTaps = (LVM_INT16)((pInstance->Capabilities.MaxBands * \
+ sizeof(Biquad_2I_Order2_FLOAT_Taps_t)) / sizeof(LVM_FLOAT));
+ if (NumTaps != 0)
+ {
+ LoadConst_Float(0, /* Clear the history, value 0 */
+ pTapAddress, /* Destination */
+ NumTaps); /* Number of words */
+ }
+}
+#endif
/****************************************************************************************/
/* */
/* FUNCTION: LVEQNB_Control */
@@ -422,9 +466,13 @@
{
if(pParams->OperatingMode == LVEQNB_ON)
{
+#ifdef BUILD_FLOAT
+ LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0], 1.0f);
+ LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1], 0.0f);
+#else
LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0],LVM_MAXINT_16);
LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1],0);
-
+#endif
pInstance->BypassMixer.MixerStream[0].CallbackSet = 1;
pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
}
@@ -432,15 +480,18 @@
{
/* Stay on the ON operating mode until the transition is done */
pInstance->Params.OperatingMode = LVEQNB_ON;
-
+#ifdef BUILD_FLOAT
+ LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0], 0.0f);
+ LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1], 1.0f);
+#else
LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0],0);
LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1],LVM_MAXINT_16);
+#endif
pInstance->BypassMixer.MixerStream[0].CallbackSet = 1;
pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
}
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
-
pInstance->bInOperatingModeTransition = LVM_TRUE;
}
@@ -470,8 +521,13 @@
/*
* Send an ALGOFF event if the ON->OFF switch transition is finished
*/
+#ifdef BUILD_FLOAT
+ if((LVC_Mixer_GetTarget(&pInstance->BypassMixer.MixerStream[0]) == 0) &&
+ (CallbackParam == 0)){
+#else
if((LVC_Mixer_GetTarget(&pInstance->BypassMixer.MixerStream[0]) == 0x00000000) &&
(CallbackParam == 0)){
+#endif
pInstance->Params.OperatingMode = LVEQNB_BYPASS;
if (CallBack != LVM_NULL){
CallBack(pInstance->Capabilities.pBundleInstance, LVM_NULL, ALGORITHM_EQNB_ID|LVEQNB_EVENT_ALGOFF);
@@ -485,9 +541,3 @@
return 1;
}
-
-
-
-
-
-
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.c b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.c
index e01c1c5..de1bbb7 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.c
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.c
@@ -97,6 +97,21 @@
*/
InstAlloc_Init(&AllocMem,
LVM_NULL);
+#ifdef BUILD_FLOAT
+ InstAlloc_AddMember(&AllocMem, /* Low pass filter */
+ sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
+ InstAlloc_AddMember(&AllocMem, /* High pass filter */
+ sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
+ /* Equaliser Biquad Taps */
+ InstAlloc_AddMember(&AllocMem,
+ (pCapabilities->MaxBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t)));
+ /* Filter definitions */
+ InstAlloc_AddMember(&AllocMem,
+ (pCapabilities->MaxBands * sizeof(LVEQNB_BandDef_t)));
+ /* Biquad types */
+ InstAlloc_AddMember(&AllocMem,
+ (pCapabilities->MaxBands * sizeof(LVEQNB_BiquadType_en)));
+#else
InstAlloc_AddMember(&AllocMem, /* Low pass filter */
sizeof(Biquad_2I_Order2_Taps_t));
InstAlloc_AddMember(&AllocMem, /* High pass filter */
@@ -107,6 +122,7 @@
(pCapabilities->MaxBands * sizeof(LVEQNB_BandDef_t))); /* Filter definitions */
InstAlloc_AddMember(&AllocMem,
(pCapabilities->MaxBands * sizeof(LVEQNB_BiquadType_en))); /* Biquad types */
+#endif
pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Size = InstAlloc_GetTotal(&AllocMem);
pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Alignment = LVEQNB_DATA_ALIGN;
pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Type = LVEQNB_PERSISTENT_DATA;
@@ -117,12 +133,22 @@
*/
InstAlloc_Init(&AllocMem,
LVM_NULL);
+#ifdef BUILD_FLOAT
+ InstAlloc_AddMember(&AllocMem, /* Low pass filter */
+ sizeof(Biquad_FLOAT_Instance_t));
+ InstAlloc_AddMember(&AllocMem, /* High pass filter */
+ sizeof(Biquad_FLOAT_Instance_t));
+ /* Equaliser Biquad Instance */
+ InstAlloc_AddMember(&AllocMem,
+ pCapabilities->MaxBands * sizeof(Biquad_FLOAT_Instance_t));
+#else
InstAlloc_AddMember(&AllocMem, /* Low pass filter */
sizeof(Biquad_Instance_t));
InstAlloc_AddMember(&AllocMem, /* High pass filter */
sizeof(Biquad_Instance_t));
InstAlloc_AddMember(&AllocMem,
pCapabilities->MaxBands * sizeof(Biquad_Instance_t)); /* Equaliser Biquad Instance */
+#endif
pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Size = InstAlloc_GetTotal(&AllocMem);
pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Alignment = LVEQNB_COEF_ALIGN;
pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Type = LVEQNB_PERSISTENT_COEF;
@@ -133,8 +159,14 @@
*/
InstAlloc_Init(&AllocMem,
LVM_NULL);
+#ifdef BUILD_FLOAT
+ InstAlloc_AddMember(&AllocMem, /* Low pass filter */
+ LVEQNB_SCRATCHBUFFERS * sizeof(LVM_FLOAT) * \
+ pCapabilities->MaxBlockSize);
+#else
InstAlloc_AddMember(&AllocMem, /* Low pass filter */
LVEQNB_SCRATCHBUFFERS*sizeof(LVM_INT16)*pCapabilities->MaxBlockSize);
+#endif
pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Size = InstAlloc_GetTotal(&AllocMem);
pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Alignment = LVEQNB_SCRATCH_ALIGN;
pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Type = LVEQNB_SCRATCH;
@@ -248,8 +280,15 @@
InstAlloc_Init(&AllocMem,
pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].pBaseAddress);
+#ifdef BUILD_FLOAT
+ /* Equaliser Biquad Instance */
+ pInstance->pEQNB_FilterState_Float = InstAlloc_AddMember(&AllocMem,
+ pCapabilities->MaxBands * \
+ sizeof(Biquad_FLOAT_Instance_t));
+#else
pInstance->pEQNB_FilterState = InstAlloc_AddMember(&AllocMem,
pCapabilities->MaxBands * sizeof(Biquad_Instance_t)); /* Equaliser Biquad Instance */
+#endif
@@ -259,9 +298,15 @@
InstAlloc_Init(&AllocMem,
pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].pBaseAddress);
+#ifdef BUILD_FLOAT
+ MemSize = (pCapabilities->MaxBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
+ pInstance->pEQNB_Taps_Float = (Biquad_2I_Order2_FLOAT_Taps_t *)InstAlloc_AddMember(&AllocMem,
+ MemSize);
+#else
MemSize = (pCapabilities->MaxBands * sizeof(Biquad_2I_Order2_Taps_t));
pInstance->pEQNB_Taps = (Biquad_2I_Order2_Taps_t *)InstAlloc_AddMember(&AllocMem,
MemSize);
+#endif
MemSize = (pCapabilities->MaxBands * sizeof(LVEQNB_BandDef_t));
pInstance->pBandDefinitions = (LVEQNB_BandDef_t *)InstAlloc_AddMember(&AllocMem,
MemSize);
@@ -279,8 +324,13 @@
InstAlloc_Init(&AllocMem,
pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].pBaseAddress);
+#ifdef BUILD_FLOAT
+ pInstance->pFastTemporary = (LVM_FLOAT *)InstAlloc_AddMember(&AllocMem,
+ sizeof(LVM_FLOAT));
+#else
pInstance->pFastTemporary = (LVM_INT16 *)InstAlloc_AddMember(&AllocMem,
sizeof(LVM_INT16));
+#endif
/*
* Update the instance parameters
@@ -308,15 +358,22 @@
pInstance->BypassMixer.MixerStream[0].CallbackParam = 0;
pInstance->BypassMixer.MixerStream[0].pCallbackHandle = (void*)pInstance;
pInstance->BypassMixer.MixerStream[0].pCallBack = LVEQNB_BypassMixerCallBack;
+
LVC_Mixer_Init(&pInstance->BypassMixer.MixerStream[0],0,0);
LVC_Mixer_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],0,LVM_FS_8000,2);
+
pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
pInstance->BypassMixer.MixerStream[1].CallbackParam = 0;
pInstance->BypassMixer.MixerStream[1].pCallbackHandle = LVM_NULL;
pInstance->BypassMixer.MixerStream[1].pCallBack = LVM_NULL;
+#ifdef BUILD_FLOAT
+ LVC_Mixer_Init(&pInstance->BypassMixer.MixerStream[1], 0, 1.0f);
+ LVC_Mixer_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1], 0, LVM_FS_8000, 2);
+#else
LVC_Mixer_Init(&pInstance->BypassMixer.MixerStream[1],0,LVM_MAXINT_16);
LVC_Mixer_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1],0,LVM_FS_8000,2);
+#endif
pInstance->bInOperatingModeTransition = LVM_FALSE;
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
index 9df980c..56b02e0 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
@@ -60,6 +60,9 @@
/* Filter biquad types */
typedef enum
{
+#ifdef BUILD_FLOAT
+ LVEQNB_SinglePrecision_Float = -1,
+#endif
LVEQNB_SinglePrecision = 0,
LVEQNB_DoublePrecision = 1,
LVEQNB_OutOfRange = 2,
@@ -84,11 +87,20 @@
LVEQNB_Capabilities_t Capabilities; /* Instance capabilities */
/* Aligned memory pointers */
+#ifdef BUILD_FLOAT
+ LVM_FLOAT *pFastTemporary; /* Fast temporary data base address */
+#else
LVM_INT16 *pFastTemporary; /* Fast temporary data base address */
+#endif
+#ifdef BUILD_FLOAT
+ Biquad_2I_Order2_FLOAT_Taps_t *pEQNB_Taps_Float; /* Equaliser Taps */
+ Biquad_FLOAT_Instance_t *pEQNB_FilterState_Float; /* State for each filter band */
+#else
/* Process variables */
Biquad_2I_Order2_Taps_t *pEQNB_Taps; /* Equaliser Taps */
Biquad_Instance_t *pEQNB_FilterState; /* State for each filter band */
+#endif
/* Filter definitions and call back */
LVM_UINT16 NBands; /* Number of bands */
@@ -96,7 +108,12 @@
LVEQNB_BiquadType_en *pBiquadType; /* Filter biquad types */
/* Bypass variable */
+#ifdef BUILD_FLOAT
+ LVMixer3_2St_FLOAT_st BypassMixer;
+#else
LVMixer3_2St_st BypassMixer; /* Bypass mixer used in transitions */
+#endif
+
LVM_INT16 bInOperatingModeTransition; /* Operating mode transition flag */
} LVEQNB_Instance_t;
@@ -114,7 +131,11 @@
void LVEQNB_SetCoefficients(LVEQNB_Instance_t *pInstance);
void LVEQNB_ClearFilterHistory(LVEQNB_Instance_t *pInstance);
-
+#ifdef BUILD_FLOAT
+LVEQNB_ReturnStatus_en LVEQNB_SinglePrecCoefs(LVM_UINT16 Fs,
+ LVEQNB_BandDef_t *pFilterDefinition,
+ PK_FLOAT_Coefs_t *pCoefficients);
+#else
LVEQNB_ReturnStatus_en LVEQNB_SinglePrecCoefs(LVM_UINT16 Fs,
LVEQNB_BandDef_t *pFilterDefinition,
PK_C16_Coefs_t *pCoefficients);
@@ -122,6 +143,7 @@
LVEQNB_ReturnStatus_en LVEQNB_DoublePrecCoefs(LVM_UINT16 Fs,
LVEQNB_BandDef_t *pFilterDefinition,
PK_C32_Coefs_t *pCoefficients);
+#endif
LVM_INT32 LVEQNB_BypassMixerCallBack (void* hInstance, void *pGeneralPurpose, LVM_INT16 CallbackParam);
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c
index 58f58ed..6328181 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c
@@ -57,7 +57,121 @@
/* NOTES: */
/* */
/****************************************************************************************/
+#ifdef BUILD_FLOAT
+LVEQNB_ReturnStatus_en LVEQNB_Process(LVEQNB_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples)
+{
+ LVM_UINT16 i;
+ Biquad_FLOAT_Instance_t *pBiquad;
+ LVEQNB_Instance_t *pInstance = (LVEQNB_Instance_t *)hInstance;
+ LVM_FLOAT *pScratch;
+
+
+ /* Check for NULL pointers */
+ if((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
+ {
+ return LVEQNB_NULLADDRESS;
+ }
+
+ /* Check if the input and output data buffers are 32-bit aligned */
+ if ((((uintptr_t)pInData % 4) != 0) || (((uintptr_t)pOutData % 4) != 0))
+ {
+ return LVEQNB_ALIGNMENTERROR;
+ }
+
+ pScratch = (LVM_FLOAT *)pInstance->pFastTemporary;
+
+ /*
+ * Check the number of samples is not too large
+ */
+ if (NumSamples > pInstance->Capabilities.MaxBlockSize)
+ {
+ return(LVEQNB_TOOMANYSAMPLES);
+ }
+
+ if (pInstance->Params.OperatingMode == LVEQNB_ON)
+ {
+ /*
+ * Copy input data in to scratch buffer
+ */
+
+ Copy_Float((LVM_FLOAT *)pInData, /* Source */
+ pScratch, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Left and Right */
+ /*
+ * For each section execte the filter unless the gain is 0dB
+ */
+ if (pInstance->NBands != 0)
+ {
+ for (i = 0; i < pInstance->NBands; i++)
+ {
+ /*
+ * Check if band is non-zero dB gain
+ */
+ if (pInstance->pBandDefinitions[i].Gain != 0)
+ {
+ /*
+ * Get the address of the biquad instance
+ */
+ pBiquad = &pInstance->pEQNB_FilterState_Float[i];
+
+
+ /*
+ * Select single or double precision as required
+ */
+ switch (pInstance->pBiquadType[i])
+ {
+ case LVEQNB_SinglePrecision_Float:
+ {
+ PK_2I_D32F32C14G11_TRC_WRA_01(pBiquad,
+ (LVM_FLOAT *)pScratch,
+ (LVM_FLOAT *)pScratch,
+ (LVM_INT16)NumSamples);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+
+ if(pInstance->bInOperatingModeTransition == LVM_TRUE){
+ LVC_MixSoft_2St_D16C31_SAT(&pInstance->BypassMixer,
+ (LVM_FLOAT *)pScratch,
+ (LVM_FLOAT *)pInData,
+ (LVM_FLOAT *)pScratch,
+ (LVM_INT16)(2 * NumSamples));
+ Copy_Float((LVM_FLOAT*)pScratch, /* Source */
+ pOutData, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Left and Right samples */
+ }
+ else{
+ Copy_Float(pScratch, /* Source */
+ pOutData, /* Destination */
+ (LVM_INT16 )(2 * NumSamples)); /* Left and Right */
+ }
+ }
+ else
+ {
+ /*
+ * Mode is OFF so copy the data if necessary
+ */
+ if (pInData != pOutData)
+ {
+ Copy_Float(pInData, /* Source */
+ pOutData, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Left and Right samples */
+ }
+ }
+ return(LVEQNB_SUCCESS);
+
+}
+#else
LVEQNB_ReturnStatus_en LVEQNB_Process(LVEQNB_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 *pOutData,
@@ -198,3 +312,4 @@
return(LVEQNB_SUCCESS);
}
+#endif
\ No newline at end of file
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Tables.c b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Tables.c
index 8e2e0e8..563181c 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Tables.c
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Tables.c
@@ -36,6 +36,20 @@
* Sample rate table for converting between the enumerated type and the actual
* frequency
*/
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+const LVM_UINT32 LVEQNB_SampleRateTab[] = {8000, /* 8kS/s */
+ 11025,
+ 12000,
+ 16000,
+ 22050,
+ 24000,
+ 32000,
+ 44100,
+ 48000,
+ 96000,
+ 192000
+};
+#else
const LVM_UINT16 LVEQNB_SampleRateTab[] = {8000, /* 8kS/s */
11025,
12000,
@@ -44,8 +58,9 @@
24000,
32000,
44100,
- 48000}; /* 48kS/s */
-
+ 48000
+};
+#endif
/************************************************************************************/
/* */
@@ -56,6 +71,22 @@
/*
* Table for 2 * Pi / Fs
*/
+#ifdef BUILD_FLOAT
+const LVM_FLOAT LVEQNB_TwoPiOnFsTable[] = {LVEQNB_2PiOn_8000, /* 8kS/s */
+ LVEQNB_2PiOn_11025,
+ LVEQNB_2PiOn_12000,
+ LVEQNB_2PiOn_16000,
+ LVEQNB_2PiOn_22050,
+ LVEQNB_2PiOn_24000,
+ LVEQNB_2PiOn_32000,
+ LVEQNB_2PiOn_44100,
+ LVEQNB_2PiOn_48000
+#ifdef HIGHER_FS
+ ,LVEQNB_2PiOn_96000
+ ,LVEQNB_2PiOn_192000
+#endif
+ };
+#else
const LVM_INT16 LVEQNB_TwoPiOnFsTable[] = {LVEQNB_2PiOn_8000, /* 8kS/s */
LVEQNB_2PiOn_11025,
LVEQNB_2PiOn_12000,
@@ -65,10 +96,44 @@
LVEQNB_2PiOn_32000,
LVEQNB_2PiOn_44100,
LVEQNB_2PiOn_48000}; /* 48kS/s */
+#endif
/*
* Gain table
*/
+#ifdef BUILD_FLOAT
+const LVM_FLOAT LVEQNB_GainTable[] = {LVEQNB_Gain_Neg15_dB, /* -15dB gain */
+ LVEQNB_Gain_Neg14_dB,
+ LVEQNB_Gain_Neg13_dB,
+ LVEQNB_Gain_Neg12_dB,
+ LVEQNB_Gain_Neg11_dB,
+ LVEQNB_Gain_Neg10_dB,
+ LVEQNB_Gain_Neg9_dB,
+ LVEQNB_Gain_Neg8_dB,
+ LVEQNB_Gain_Neg7_dB,
+ LVEQNB_Gain_Neg6_dB,
+ LVEQNB_Gain_Neg5_dB,
+ LVEQNB_Gain_Neg4_dB,
+ LVEQNB_Gain_Neg3_dB,
+ LVEQNB_Gain_Neg2_dB,
+ LVEQNB_Gain_Neg1_dB,
+ LVEQNB_Gain_0_dB, /* 0dB gain */
+ LVEQNB_Gain_1_dB,
+ LVEQNB_Gain_2_dB,
+ LVEQNB_Gain_3_dB,
+ LVEQNB_Gain_4_dB,
+ LVEQNB_Gain_5_dB,
+ LVEQNB_Gain_6_dB,
+ LVEQNB_Gain_7_dB,
+ LVEQNB_Gain_8_dB,
+ LVEQNB_Gain_9_dB,
+ LVEQNB_Gain_10_dB,
+ LVEQNB_Gain_11_dB,
+ LVEQNB_Gain_12_dB,
+ LVEQNB_Gain_13_dB,
+ LVEQNB_Gain_14_dB,
+ LVEQNB_Gain_15_dB}; /* +15dB gain */
+#else
const LVM_INT16 LVEQNB_GainTable[] = {LVEQNB_Gain_Neg15_dB, /* -15dB gain */
LVEQNB_Gain_Neg14_dB,
LVEQNB_Gain_Neg13_dB,
@@ -101,10 +166,28 @@
LVEQNB_Gain_14_dB,
LVEQNB_Gain_15_dB}; /* +15dB gain */
-
+#endif
/*
* D table for 100 / (Gain + 1)
*/
+#ifdef BUILD_FLOAT
+const LVM_FLOAT LVEQNB_DTable[] = {LVEQNB_100D_Neg15_dB, /* -15dB gain */
+ LVEQNB_100D_Neg14_dB,
+ LVEQNB_100D_Neg13_dB,
+ LVEQNB_100D_Neg12_dB,
+ LVEQNB_100D_Neg11_dB,
+ LVEQNB_100D_Neg10_dB,
+ LVEQNB_100D_Neg9_dB,
+ LVEQNB_100D_Neg8_dB,
+ LVEQNB_100D_Neg7_dB,
+ LVEQNB_100D_Neg6_dB,
+ LVEQNB_100D_Neg5_dB,
+ LVEQNB_100D_Neg4_dB,
+ LVEQNB_100D_Neg3_dB,
+ LVEQNB_100D_Neg2_dB,
+ LVEQNB_100D_Neg1_dB,
+ LVEQNB_100D_0_dB}; /* 0dB gain */
+#else
const LVM_INT16 LVEQNB_DTable[] = {LVEQNB_100D_Neg15_dB, /* -15dB gain */
LVEQNB_100D_Neg14_dB,
LVEQNB_100D_Neg13_dB,
@@ -122,7 +205,7 @@
LVEQNB_100D_Neg1_dB,
LVEQNB_100D_0_dB}; /* 0dB gain */
-
+#endif
/************************************************************************************/
/* */
/* Filter polynomial coefficients */
diff --git a/media/libeffects/lvm/lib/Reverb/lib/LVREV.h b/media/libeffects/lvm/lib/Reverb/lib/LVREV.h
index 28e3369..9c2e297 100644
--- a/media/libeffects/lvm/lib/Reverb/lib/LVREV.h
+++ b/media/libeffects/lvm/lib/Reverb/lib/LVREV.h
@@ -107,8 +107,14 @@
/* Parameters for REV */
LVM_UINT16 Level; /* Level, 0 to 100 representing percentage of reverb */
+#ifndef HIGHER_FS
LVM_UINT16 LPF; /* Low pass filter, in Hz */
LVM_UINT16 HPF; /* High pass filter, in Hz */
+#else
+ LVM_UINT32 LPF; /* Low pass filter, in Hz */
+ LVM_UINT32 HPF; /* High pass filter, in Hz */
+#endif
+
LVM_UINT16 T60; /* Decay time constant, in ms */
LVM_UINT16 Density; /* Echo density, 0 to 100 for minimum to maximum density */
LVM_UINT16 Damping; /* Damping */
@@ -297,11 +303,17 @@
/* 1. The input and output buffers must be 32-bit aligned */
/* */
/****************************************************************************************/
+#ifdef BUILD_FLOAT
+LVREV_ReturnStatus_en LVREV_Process(LVREV_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ const LVM_UINT16 NumSamples);
+#else
LVREV_ReturnStatus_en LVREV_Process(LVREV_Handle_t hInstance,
const LVM_INT32 *pInData,
LVM_INT32 *pOutData,
const LVM_UINT16 NumSamples);
-
+#endif
#ifdef __cplusplus
}
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c
index ac2ef9d..e710844 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c
@@ -41,6 +41,7 @@
/* */
/****************************************************************************************/
+#ifndef BUILD_FLOAT
LVREV_ReturnStatus_en LVREV_ApplyNewSettings (LVREV_Instance_st *pPrivate)
{
@@ -593,8 +594,589 @@
return LVREV_SUCCESS;
}
+#else /* BUILD_FLOAT*/
+LVREV_ReturnStatus_en LVREV_ApplyNewSettings (LVREV_Instance_st *pPrivate)
+{
+
+ LVM_Mode_en OperatingMode;
+ LVM_INT32 NumberOfDelayLines;
+ /* Check for NULL pointer */
+ if(pPrivate == LVM_NULL)
+ {
+ return LVREV_NULLADDRESS;
+ }
+
+ OperatingMode = pPrivate->NewParams.OperatingMode;
+
+ if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
+ {
+ NumberOfDelayLines = 4;
+ }
+ else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
+ {
+ NumberOfDelayLines = 2;
+ }
+ else
+ {
+ NumberOfDelayLines = 1;
+ }
+
+ /*
+ * Update the high pass filter coefficients
+ */
+ if((pPrivate->NewParams.HPF != pPrivate->CurrentParams.HPF) ||
+ (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+ LVM_FLOAT Omega;
+ FO_FLOAT_Coefs_t Coeffs;
+
+ Omega = LVM_GetOmega(pPrivate->NewParams.HPF, pPrivate->NewParams.SampleRate);
+ LVM_FO_HPF(Omega, &Coeffs);
+ FO_1I_D32F32Cll_TRC_WRA_01_Init( &pPrivate->pFastCoef->HPCoefs,
+ &pPrivate->pFastData->HPTaps, &Coeffs);
+ LoadConst_Float(0,
+ (void *)&pPrivate->pFastData->HPTaps, /* Destination Cast to void: \
+ no dereferencing in function*/
+ sizeof(Biquad_1I_Order1_FLOAT_Taps_t) / sizeof(LVM_FLOAT));
+ }
+
+
+ /*
+ * Update the low pass filter coefficients
+ */
+ if((pPrivate->NewParams.LPF != pPrivate->CurrentParams.LPF) ||
+ (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+ LVM_FLOAT Omega;
+ FO_FLOAT_Coefs_t Coeffs;
+
+ Coeffs.A0 = 1;
+ Coeffs.A1 = 0;
+ Coeffs.B1 = 0;
+ if(pPrivate->NewParams.LPF <= (LVM_FsTable[pPrivate->NewParams.SampleRate] >> 1))
+ {
+ Omega = LVM_GetOmega(pPrivate->NewParams.LPF, pPrivate->NewParams.SampleRate);
+
+ /*
+ * Do not apply filter if w =2*pi*fc/fs >= 2.9
+ */
+ if(Omega <= (LVM_FLOAT)LVREV_2_9_INQ29)
+ {
+ LVM_FO_LPF(Omega, &Coeffs);
+ }
+ }
+ FO_1I_D32F32Cll_TRC_WRA_01_Init( &pPrivate->pFastCoef->LPCoefs,
+ &pPrivate->pFastData->LPTaps, &Coeffs);
+ LoadConst_Float(0,
+ (void *)&pPrivate->pFastData->LPTaps, /* Destination Cast to void: \
+ no dereferencing in function*/
+ sizeof(Biquad_1I_Order1_FLOAT_Taps_t) / sizeof(LVM_FLOAT));
+ }
+
+
+ /*
+ * Calculate the room size parameter
+ */
+ if( pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize)
+ {
+ /* Room size range is 10ms to 200ms
+ * 0% -- 10ms
+ * 50% -- 65ms
+ * 100% -- 120ms
+ */
+ pPrivate->RoomSizeInms = 10 + (((pPrivate->NewParams.RoomSize*11) + 5) / 10);
+ }
+
+
+ /*
+ * Update the T delay number of samples and the all pass delay number of samples
+ */
+ if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
+ (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+
+ LVM_UINT32 Temp;
+ LVM_INT32 APDelaySize;
+ LVM_INT32 Fs = LVM_GetFsFromTable(pPrivate->NewParams.SampleRate);
+ LVM_UINT32 DelayLengthSamples = (LVM_UINT32)(Fs * pPrivate->RoomSizeInms);
+ LVM_INT16 i;
+ LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_minus0_on_4, LVREV_T_3_Power_minus1_on_4, \
+ LVREV_T_3_Power_minus2_on_4, LVREV_T_3_Power_minus3_on_4};
+ LVM_INT16 MaxT_Delay[] = {LVREV_MAX_T0_DELAY, LVREV_MAX_T1_DELAY, \
+ LVREV_MAX_T2_DELAY, LVREV_MAX_T3_DELAY};
+ LVM_INT16 MaxAP_Delay[] = {LVREV_MAX_AP0_DELAY, LVREV_MAX_AP1_DELAY, \
+ LVREV_MAX_AP2_DELAY, LVREV_MAX_AP3_DELAY};
+
+
+ /*
+ * For each delay line
+ */
+ for (i = 0; i < NumberOfDelayLines; i++)
+ {
+ if (i != 0)
+ {
+ LVM_FLOAT Temp1; /* to avoid QAC warning on type conversion */
+
+ Temp1=(LVM_FLOAT)DelayLengthSamples;
+ Temp = (LVM_UINT32)(Temp1 * ScaleTable[i]);
+ }
+ else
+ {
+ Temp = DelayLengthSamples;
+ }
+ APDelaySize = Temp / 1500;
+
+
+ /*
+ * Set the fixed delay
+ */
+
+#ifdef HIGHER_FS
+ Temp = (MaxT_Delay[i] - MaxAP_Delay[i]) * Fs / 192000;
+#else
+ Temp = (MaxT_Delay[i] - MaxAP_Delay[i]) * Fs / 48000;
+#endif
+ pPrivate->Delay_AP[i] = pPrivate->T[i] - Temp;
+
+
+ /*
+ * Set the tap selection
+ */
+ if (pPrivate->AB_Selection)
+ {
+ /* Smooth from tap A to tap B */
+ pPrivate->pOffsetB[i] = &pPrivate->pDelay_T[i][pPrivate->T[i] - \
+ Temp - APDelaySize];
+ pPrivate->B_DelaySize[i] = APDelaySize;
+ pPrivate->Mixer_APTaps[i].Target1 = 0;
+ pPrivate->Mixer_APTaps[i].Target2 = 1.0f;
+ }
+ else
+ {
+ /* Smooth from tap B to tap A */
+ pPrivate->pOffsetA[i] = &pPrivate->pDelay_T[i][pPrivate->T[i] - \
+ Temp - APDelaySize];
+ pPrivate->A_DelaySize[i] = APDelaySize;
+ pPrivate->Mixer_APTaps[i].Target2 = 0;
+ pPrivate->Mixer_APTaps[i].Target1 = 1.0f;
+ }
+
+ /*
+ * Set the maximum block size to the smallest delay size
+ */
+ pPrivate->MaxBlkLen = Temp;
+ if (pPrivate->MaxBlkLen > pPrivate->A_DelaySize[i])
+ {
+ pPrivate->MaxBlkLen = pPrivate->A_DelaySize[i];
+ }
+ if (pPrivate->MaxBlkLen > pPrivate->B_DelaySize[i])
+ {
+ pPrivate->MaxBlkLen = pPrivate->B_DelaySize[i];
+ }
+ }
+ if (pPrivate->AB_Selection)
+ {
+ pPrivate->AB_Selection = 0;
+ }
+ else
+ {
+ pPrivate->AB_Selection = 1;
+ }
+
+
+ /*
+ * Limit the maximum block length
+ */
+ /* Just as a precausion, but no problem if we remove this line */
+ pPrivate->MaxBlkLen = pPrivate->MaxBlkLen - 2;
+ if(pPrivate->MaxBlkLen > pPrivate->InstanceParams.MaxBlockSize)
+ {
+ pPrivate->MaxBlkLen = (LVM_INT32)pPrivate->InstanceParams.MaxBlockSize;
+ }
+ }
+
+
+
+ /*
+ * Update the low pass filter coefficient
+ */
+ if( (pPrivate->NewParams.Damping != pPrivate->CurrentParams.Damping) ||
+ (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+
+ LVM_INT32 Temp;
+ LVM_FLOAT Omega;
+ FO_FLOAT_Coefs_t Coeffs;
+ LVM_INT16 i;
+ LVM_INT16 Damping = (LVM_INT16)((pPrivate->NewParams.Damping * 100) + 1000);
+ LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_0_on_4, LVREV_T_3_Power_1_on_4,
+ LVREV_T_3_Power_2_on_4, LVREV_T_3_Power_3_on_4};
+
+
+ /*
+ * For each filter
+ */
+ for (i = 0; i < NumberOfDelayLines; i++)
+ {
+ if (i != 0)
+ {
+ Temp = (LVM_INT32)(ScaleTable[i] * Damping);
+ }
+ else
+ {
+ Temp = Damping;
+ }
+ if(Temp <= (LVM_INT32)(LVM_FsTable[pPrivate->NewParams.SampleRate] >> 1))
+ {
+ Omega = LVM_GetOmega(Temp, pPrivate->NewParams.SampleRate);
+ LVM_FO_LPF(Omega, &Coeffs);
+ }
+ else
+ {
+ Coeffs.A0 = 1;
+ Coeffs.A1 = 0;
+ Coeffs.B1 = 0;
+ }
+ FO_1I_D32F32Cll_TRC_WRA_01_Init(&pPrivate->pFastCoef->RevLPCoefs[i],
+ &pPrivate->pFastData->RevLPTaps[i], &Coeffs);
+ }
+ }
+
+
+ /*
+ * Update All-pass filter mixer time constants
+ */
+ if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
+ (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->NewParams.Density != pPrivate->CurrentParams.Density))
+ {
+ LVM_INT16 i;
+ LVM_FLOAT Alpha;
+ LVM_FLOAT AlphaTap;
+
+ Alpha = LVM_Mixer_TimeConstant(LVREV_ALLPASS_TC,
+ LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
+ 1);
+
+ AlphaTap = LVM_Mixer_TimeConstant(LVREV_ALLPASS_TAP_TC,
+ LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
+ 1);
+
+ for (i = 0; i < 4; i++)
+ {
+ pPrivate->Mixer_APTaps[i].Alpha1 = AlphaTap;
+ pPrivate->Mixer_APTaps[i].Alpha2 = AlphaTap;
+ pPrivate->Mixer_SGFeedback[i].Alpha = Alpha;
+ pPrivate->Mixer_SGFeedforward[i].Alpha = Alpha;
+ }
+ }
+
+
+ /*
+ * Update the feed back gain
+ */
+ if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
+ (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->NewParams.T60 != pPrivate->CurrentParams.T60) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+
+ LVM_FLOAT G[4]; /* Feedback gain (Q7.24) */
+
+ if(pPrivate->NewParams.T60 == 0)
+ {
+ G[3] = 0;
+ G[2] = 0;
+ G[1] = 0;
+ G[0] = 0;
+ }
+ else
+ {
+ LVM_FLOAT Temp1;
+ LVM_FLOAT Temp2;
+ LVM_INT16 i;
+ LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_minus0_on_4, LVREV_T_3_Power_minus1_on_4,
+ LVREV_T_3_Power_minus2_on_4, LVREV_T_3_Power_minus3_on_4};
+
+
+ /*
+ * For each delay line
+ */
+ for (i = 0; i < NumberOfDelayLines; i++)
+ {
+ Temp1 = (3 * pPrivate->RoomSizeInms * ScaleTable[i]) / pPrivate->NewParams.T60;
+ if(Temp1 >= (4))
+ {
+ G[i] = 0;
+ }
+ else if((Temp1 >= (2)))
+ {
+ Temp2 = LVM_Power10(-(Temp1 / 2.0f));
+ Temp1 = LVM_Power10(-(Temp1 / 2.0f));
+ Temp1 = Temp1 * Temp2;
+ }
+ else
+ {
+ Temp1 = LVM_Power10(-(Temp1));
+ }
+ if (NumberOfDelayLines == 1)
+ {
+ G[i] = Temp1;
+ }
+ else
+ {
+ LVM_FLOAT TempG;
+ TempG = Temp1 * ONE_OVER_SQRT_TWO;
+ G[i]=TempG;
+ }
+ }
+ }
+
+ /* Set up the feedback mixers for four delay lines */
+ pPrivate->FeedbackMixer[0].Target=G[0];
+ pPrivate->FeedbackMixer[1].Target=G[1];
+ pPrivate->FeedbackMixer[2].Target=G[2];
+ pPrivate->FeedbackMixer[3].Target=G[3];
+ }
+
+
+ /*
+ * Calculate the gain correction
+ */
+ if((pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
+ (pPrivate->NewParams.Level != pPrivate->CurrentParams.Level) ||
+ (pPrivate->NewParams.T60 != pPrivate->CurrentParams.T60) )
+ {
+ LVM_INT32 Index=0;
+ LVM_FLOAT Index_FLOAT;
+ LVM_INT32 i=0;
+ LVM_FLOAT Gain=0;
+ LVM_INT32 RoomSize=0;
+ LVM_FLOAT T60;
+ LVM_FLOAT Coefs[5];
+
+
+ if(pPrivate->NewParams.RoomSize == 0)
+ {
+ RoomSize = 1;
+ }
+ else
+ {
+ RoomSize = (LVM_INT32)pPrivate->NewParams.RoomSize;
+ }
+
+
+ if(pPrivate->NewParams.T60 < 100)
+ {
+ T60 = 100 * LVREV_T60_SCALE;
+ }
+ else
+ {
+ T60 = pPrivate->NewParams.T60 * LVREV_T60_SCALE;
+ }
+
+ /* Find the nearest room size in table */
+ for(i = 0; i < 24; i++)
+ {
+ if(RoomSize <= LVREV_GainPolyTable[i][0])
+ {
+ Index = i;
+ break;
+ }
+ }
+
+
+ if(RoomSize == LVREV_GainPolyTable[Index][0])
+ {
+ /* Take table values if the room size is in table */
+ for(i = 1; i < 5; i++)
+ {
+ Coefs[i-1] = LVREV_GainPolyTable[Index][i];
+ }
+ Coefs[4] = 0;
+ Gain = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
+ }
+ else
+ {
+ /* Interpolate the gain between nearest room sizes */
+
+ LVM_FLOAT Gain1,Gain2;
+ LVM_INT32 Tot_Dist,Dist;
+
+ Tot_Dist = (LVM_UINT32)LVREV_GainPolyTable[Index][0] - \
+ (LVM_UINT32)LVREV_GainPolyTable[Index-1][0];
+ Dist = RoomSize - (LVM_UINT32)LVREV_GainPolyTable[Index - 1][0];
+
+
+ /* Get gain for first */
+ for(i = 1; i < 5; i++)
+ {
+ Coefs[i-1] = LVREV_GainPolyTable[Index-1][i];
+ }
+ Coefs[4] = 0;
+
+ Gain1 = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
+
+ /* Get gain for second */
+ for(i = 1; i < 5; i++)
+ {
+ Coefs[i-1] = LVREV_GainPolyTable[Index][i];
+ }
+ Coefs[4] = 0;
+
+ Gain2 = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
+
+ /* Linear Interpolate the gain */
+ Gain = Gain1 + (((Gain2 - Gain1) * Dist) / (Tot_Dist));
+ }
+
+
+ /*
+ * Get the inverse of gain: Q.15
+ * Gain is mostly above one except few cases, take only gains above 1
+ */
+ if(Gain < 1)
+ {
+ pPrivate->Gain = 1;
+ }
+ else
+ {
+ pPrivate->Gain = 1 / Gain;
+ }
+
+ Index_FLOAT = 100.0f / (LVM_FLOAT)(100 + pPrivate->NewParams.Level);
+ pPrivate->Gain = pPrivate->Gain * Index_FLOAT;
+ pPrivate->GainMixer.Target = (pPrivate->Gain*Index_FLOAT) / 2;
+ }
+
+
+ /*
+ * Update the all pass comb filter coefficient
+ */
+ if( (pPrivate->NewParams.Density != pPrivate->CurrentParams.Density) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+ LVM_INT16 i;
+ LVM_FLOAT b = (LVM_FLOAT)pPrivate->NewParams.Density * LVREV_B_8_on_1000;
+
+ for (i = 0; i < 4; i++)
+ {
+ pPrivate->Mixer_SGFeedback[i].Target = b;
+ pPrivate->Mixer_SGFeedforward[i].Target = b;
+ }
+ }
+
+
+ /*
+ * Update the bypass mixer time constant
+ */
+ if((pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+ LVM_UINT16 NumChannels = 1; /* Assume MONO format */
+ LVM_FLOAT Alpha;
+
+ Alpha = LVM_Mixer_TimeConstant(LVREV_FEEDBACKMIXER_TC,
+ LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
+ NumChannels);
+ pPrivate->FeedbackMixer[0].Alpha = Alpha;
+ pPrivate->FeedbackMixer[1].Alpha = Alpha;
+ pPrivate->FeedbackMixer[2].Alpha = Alpha;
+ pPrivate->FeedbackMixer[3].Alpha = Alpha;
+
+ NumChannels = 2; /* Always stereo output */
+ pPrivate->BypassMixer.Alpha1 = LVM_Mixer_TimeConstant(LVREV_BYPASSMIXER_TC,
+ LVM_GetFsFromTable(pPrivate->NewParams.SampleRate), NumChannels);
+ pPrivate->BypassMixer.Alpha2 = pPrivate->BypassMixer.Alpha1;
+ pPrivate->GainMixer.Alpha = pPrivate->BypassMixer.Alpha1;
+ }
+
+
+ /*
+ * Update the bypass mixer targets
+ */
+ if( (pPrivate->NewParams.Level != pPrivate->CurrentParams.Level) &&
+ (pPrivate->NewParams.OperatingMode == LVM_MODE_ON))
+ {
+ pPrivate->BypassMixer.Target2 = (LVM_FLOAT)(pPrivate->NewParams.Level ) / 100.0f;
+ pPrivate->BypassMixer.Target1 = 0x00000000;
+ if ((pPrivate->NewParams.Level == 0) && (pPrivate->bFirstControl == LVM_FALSE))
+ {
+ pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
+ }
+ if (pPrivate->NewParams.Level != 0)
+ {
+ pPrivate->bDisableReverb = LVM_FALSE;
+ }
+ }
+
+ if(pPrivate->NewParams.OperatingMode != pPrivate->CurrentParams.OperatingMode)
+ {
+ if(pPrivate->NewParams.OperatingMode == LVM_MODE_ON)
+ {
+ pPrivate->BypassMixer.Target2 = (LVM_FLOAT)(pPrivate->NewParams.Level ) / 100.0f;
+ pPrivate->BypassMixer.Target1 = 0x00000000;
+
+ pPrivate->BypassMixer.CallbackSet2 = LVM_FALSE;
+ OperatingMode = LVM_MODE_ON;
+ if (pPrivate->NewParams.Level == 0)
+ {
+ pPrivate->bDisableReverb = LVM_TRUE;
+ }
+ else
+ {
+ pPrivate->bDisableReverb = LVM_FALSE;
+ }
+ }
+ else if (pPrivate->bFirstControl == LVM_FALSE)
+ {
+ pPrivate->BypassMixer.Target2 = 0x00000000;
+ pPrivate->BypassMixer.Target1 = 0x00000000;
+ pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
+ pPrivate->GainMixer.Target = 0.03125f;
+ OperatingMode = LVM_MODE_ON;
+ }
+ else
+ {
+ OperatingMode = LVM_MODE_OFF;
+ }
+ }
+
+
+ /* If it is the first call to ApplyNew settings force the current to the target \
+ to begin immediate playback of the effect */
+ if(pPrivate->bFirstControl == LVM_TRUE)
+ {
+ pPrivate->BypassMixer.Current1 = pPrivate->BypassMixer.Target1;
+ pPrivate->BypassMixer.Current2 = pPrivate->BypassMixer.Target2;
+ }
+
+
+ /*
+ * Copy the new parameters
+ */
+ pPrivate->CurrentParams = pPrivate->NewParams;
+ pPrivate->CurrentParams.OperatingMode = OperatingMode;
+
+
+ /*
+ * Update flag
+ */
+ if(pPrivate->bFirstControl == LVM_TRUE)
+ {
+ pPrivate->bFirstControl = LVM_FALSE;
+ }
+
+
+ return LVREV_SUCCESS;
+}
+#endif /*BUILD_FLOAT*/
/****************************************************************************************/
/* */
/* FUNCTION: BypassMixer_Callback */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.c
index 6bb1e88..9491016 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.c
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.c
@@ -61,16 +61,26 @@
* Clear all filter tap data, delay-lines and other signal related data
*/
-
+#ifdef BUILD_FLOAT
+ LoadConst_Float(0,
+ (void *)&pLVREV_Private->pFastData->HPTaps, /* Destination Cast to void: \
+ no dereferencing in function*/
+ 2);
+ LoadConst_Float(0,
+ (void *)&pLVREV_Private->pFastData->LPTaps, /* Destination Cast to void: \
+ no dereferencing in function*/
+ 2);
+#else
LoadConst_32(0,
(void *)&pLVREV_Private->pFastData->HPTaps, /* Destination Cast to void: no dereferencing in function*/
2);
LoadConst_32(0,
(void *)&pLVREV_Private->pFastData->LPTaps, /* Destination Cast to void: no dereferencing in function*/
2);
-
+#endif
if((LVM_UINT16)pLVREV_Private->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
{
+#ifndef BUILD_FLOAT
LoadConst_32(0, (LVM_INT32 *)&pLVREV_Private->pFastData->RevLPTaps[3], 2);
LoadConst_32(0, (LVM_INT32 *)&pLVREV_Private->pFastData->RevLPTaps[2], 2);
LoadConst_32(0, (LVM_INT32 *)&pLVREV_Private->pFastData->RevLPTaps[1], 2);
@@ -80,24 +90,46 @@
LoadConst_32(0,pLVREV_Private->pDelay_T[2], (LVM_INT16)LVREV_MAX_T2_DELAY);
LoadConst_32(0,pLVREV_Private->pDelay_T[1], (LVM_INT16)LVREV_MAX_T1_DELAY);
LoadConst_32(0,pLVREV_Private->pDelay_T[0], (LVM_INT16)LVREV_MAX_T0_DELAY);
+#else
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[3], 2);
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[2], 2);
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[1], 2);
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[3], LVREV_MAX_T3_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[2], LVREV_MAX_T2_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[1], LVREV_MAX_T1_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[0], LVREV_MAX_T0_DELAY);
+#endif
}
if((LVM_UINT16)pLVREV_Private->InstanceParams.NumDelays >= LVREV_DELAYLINES_2)
{
+#ifndef BUILD_FLOAT
LoadConst_32(0, (LVM_INT32 *)&pLVREV_Private->pFastData->RevLPTaps[1], 2);
LoadConst_32(0, (LVM_INT32 *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
LoadConst_32(0,pLVREV_Private->pDelay_T[1], (LVM_INT16)LVREV_MAX_T1_DELAY);
LoadConst_32(0,pLVREV_Private->pDelay_T[0], (LVM_INT16)LVREV_MAX_T0_DELAY);
+#else
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[1], 2);
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
+
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[1], LVREV_MAX_T1_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[0], LVREV_MAX_T0_DELAY);
+#endif
}
if((LVM_UINT16)pLVREV_Private->InstanceParams.NumDelays >= LVREV_DELAYLINES_1)
{
+#ifndef BUILD_FLOAT
LoadConst_32(0, (LVM_INT32 *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
LoadConst_32(0,pLVREV_Private->pDelay_T[0], (LVM_INT16)LVREV_MAX_T0_DELAY);
+#else
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[0], LVREV_MAX_T0_DELAY);
+#endif
}
-
return LVREV_SUCCESS;
}
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.c
index ffa5138..3366bcb 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.c
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.c
@@ -108,11 +108,29 @@
/*
* Zero all memory regions
*/
- LoadConst_16(0, (LVM_INT16 *)pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress, (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Size)/sizeof(LVM_INT16)));
- LoadConst_16(0, (LVM_INT16 *)pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress, (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size)/sizeof(LVM_INT16)));
- LoadConst_16(0, (LVM_INT16 *)pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress, (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Size)/sizeof(LVM_INT16)));
- LoadConst_16(0, (LVM_INT16 *)pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress, (LVM_INT16)((pMemoryTable->Region[LVM_TEMPORARY_FAST].Size)/sizeof(LVM_INT16)));
-
+#ifdef BUILD_FLOAT
+ LoadConst_Float(0,
+ (LVM_FLOAT *)pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress,
+ (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Size) / \
+ sizeof(LVM_FLOAT)));
+ LoadConst_Float(0,
+ (LVM_FLOAT *)pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress,
+ (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size) / \
+ sizeof(LVM_FLOAT)));
+ LoadConst_Float(0,
+ (LVM_FLOAT *)pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress,
+ (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Size) / \
+ sizeof(LVM_FLOAT)));
+ LoadConst_Float(0,
+ (LVM_FLOAT *)pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress,
+ (LVM_INT16)((pMemoryTable->Region[LVM_TEMPORARY_FAST].Size) / \
+ sizeof(LVM_FLOAT)));
+#else
+ LoadConst_16(0, (LVM_INT16 *)pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress, (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Size)/sizeof(LVM_INT16)));
+ LoadConst_16(0, (LVM_INT16 *)pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress, (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size)/sizeof(LVM_INT16)));
+ LoadConst_16(0, (LVM_INT16 *)pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress, (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Size)/sizeof(LVM_INT16)));
+ LoadConst_16(0, (LVM_INT16 *)pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress, (LVM_INT16)((pMemoryTable->Region[LVM_TEMPORARY_FAST].Size)/sizeof(LVM_INT16)));
+#endif
/*
* Set the instance handle if not already initialised
*/
@@ -146,7 +164,7 @@
* Set the data, coefficient and temporary memory pointers
*/
pLVREV_Private->pFastData = InstAlloc_AddMember(&FastData, sizeof(LVREV_FastData_st)); /* Fast data memory base address */
-
+#ifndef BUILD_FLOAT
if(pInstanceParams->NumDelays == LVREV_DELAYLINES_4)
{
pLVREV_Private->pDelay_T[3] = InstAlloc_AddMember(&FastData, LVREV_MAX_T3_DELAY * sizeof(LVM_INT32));
@@ -190,7 +208,67 @@
LoadConst_32(0,pLVREV_Private->pDelay_T[0] , (LVM_INT16)LVREV_MAX_T0_DELAY);
}
+#else
+ if(pInstanceParams->NumDelays == LVREV_DELAYLINES_4)
+ {
+ pLVREV_Private->pDelay_T[3] = InstAlloc_AddMember(&FastData, LVREV_MAX_T3_DELAY * \
+ sizeof(LVM_FLOAT));
+ pLVREV_Private->pDelay_T[2] = InstAlloc_AddMember(&FastData, LVREV_MAX_T2_DELAY * \
+ sizeof(LVM_FLOAT));
+ pLVREV_Private->pDelay_T[1] = InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * \
+ sizeof(LVM_FLOAT));
+ pLVREV_Private->pDelay_T[0] = InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * \
+ sizeof(LVM_FLOAT));
+ for(i = 0; i < 4; i++)
+ {
+ /* Scratch for each delay line output */
+ pLVREV_Private->pScratchDelayLine[i] = InstAlloc_AddMember(&Temporary,
+ sizeof(LVM_FLOAT) * \
+ MaxBlockSize);
+ }
+
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[3], LVREV_MAX_T3_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[2], LVREV_MAX_T2_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[1], LVREV_MAX_T1_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[0], LVREV_MAX_T0_DELAY);
+ }
+
+ if(pInstanceParams->NumDelays == LVREV_DELAYLINES_2)
+ {
+ pLVREV_Private->pDelay_T[1] = InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * \
+ sizeof(LVM_FLOAT));
+ pLVREV_Private->pDelay_T[0] = InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * \
+ sizeof(LVM_FLOAT));
+
+ for(i = 0; i < 2; i++)
+ {
+ /* Scratch for each delay line output */
+ pLVREV_Private->pScratchDelayLine[i] = InstAlloc_AddMember(&Temporary,
+ sizeof(LVM_FLOAT) * \
+ MaxBlockSize);
+ }
+
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[1], (LVM_INT16)LVREV_MAX_T1_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[0], (LVM_INT16)LVREV_MAX_T0_DELAY);
+ }
+
+ if(pInstanceParams->NumDelays == LVREV_DELAYLINES_1)
+ {
+ pLVREV_Private->pDelay_T[0] = InstAlloc_AddMember(&FastData,
+ LVREV_MAX_T0_DELAY * sizeof(LVM_FLOAT));
+
+ for(i = 0; i < 1; i++)
+ {
+ /* Scratch for each delay line output */
+ pLVREV_Private->pScratchDelayLine[i] = InstAlloc_AddMember(&Temporary,
+ sizeof(LVM_FLOAT) * \
+ MaxBlockSize);
+ }
+
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[0], (LVM_INT16)LVREV_MAX_T0_DELAY);
+ }
+#endif
/* All-pass delay buffer addresses and sizes */
pLVREV_Private->T[0] = LVREV_MAX_T0_DELAY;
pLVREV_Private->T[1] = LVREV_MAX_T1_DELAY;
@@ -200,10 +278,19 @@
pLVREV_Private->pFastCoef = InstAlloc_AddMember(&FastCoef, sizeof(LVREV_FastCoef_st)); /* Fast coefficient memory base address */
+#ifndef BUILD_FLOAT
pLVREV_Private->pScratch = InstAlloc_AddMember(&Temporary, sizeof(LVM_INT32) * MaxBlockSize); /* General purpose scratch */
pLVREV_Private->pInputSave = InstAlloc_AddMember(&Temporary, 2 * sizeof(LVM_INT32) * MaxBlockSize); /* Mono->stereo input save for end mix */
LoadConst_32(0, pLVREV_Private->pInputSave, (LVM_INT16)(MaxBlockSize*2));
-
+#else
+ /* General purpose scratch */
+ pLVREV_Private->pScratch = InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * \
+ MaxBlockSize);
+ /* Mono->stereo input save for end mix */
+ pLVREV_Private->pInputSave = InstAlloc_AddMember(&Temporary, 2 * sizeof(LVM_FLOAT) * \
+ MaxBlockSize);
+ LoadConst_Float(0, pLVREV_Private->pInputSave, (LVM_INT16)(MaxBlockSize * 2));
+#endif
/*
* Save the instance parameters in the instance structure
@@ -252,9 +339,13 @@
pLVREV_Private->GainMixer.pGeneralPurpose = LVM_NULL;
pLVREV_Private->GainMixer.pCallBack = LVM_NULL;
pLVREV_Private->GainMixer.CallbackSet = LVM_FALSE;
+#ifndef BUILD_FLOAT
pLVREV_Private->GainMixer.Current = 0x03ffffff;
pLVREV_Private->GainMixer.Target = 0x03ffffff;
-
+#else
+ pLVREV_Private->GainMixer.Current = 0.03125f;//0x03ffffff;
+ pLVREV_Private->GainMixer.Target = 0.03125f;//0x03ffffff;
+#endif
/*
* Set the All-Pass Filter mixers
@@ -277,7 +368,11 @@
pLVREV_Private->Mixer_APTaps[i].pCallBack1 = LVM_NULL;
pLVREV_Private->Mixer_APTaps[i].CallbackSet1 = LVM_FALSE;
pLVREV_Private->Mixer_APTaps[i].Current1 = 0;
+#ifndef BUILD_FLOAT
pLVREV_Private->Mixer_APTaps[i].Target1 = 0x7fffffff;
+#else
+ pLVREV_Private->Mixer_APTaps[i].Target1 = 1;
+#endif
/* Feedforward mixer */
pLVREV_Private->Mixer_SGFeedforward[i].CallbackParam = 0;
pLVREV_Private->Mixer_SGFeedforward[i].pCallbackHandle = LVM_NULL;
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetMemoryTable.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetMemoryTable.c
index 2012432..f6d446b 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetMemoryTable.c
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetMemoryTable.c
@@ -161,21 +161,37 @@
InstAlloc_AddMember(&FastData, sizeof(LVREV_FastData_st));
if(pInstanceParams->NumDelays == LVREV_DELAYLINES_4)
{
+#ifndef BUILD_FLOAT
InstAlloc_AddMember(&FastData, LVREV_MAX_T3_DELAY * sizeof(LVM_INT32));
InstAlloc_AddMember(&FastData, LVREV_MAX_T2_DELAY * sizeof(LVM_INT32));
InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * sizeof(LVM_INT32));
InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_INT32));
+#else
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T3_DELAY * sizeof(LVM_FLOAT));
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T2_DELAY * sizeof(LVM_FLOAT));
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * sizeof(LVM_FLOAT));
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_FLOAT));
+#endif
}
if(pInstanceParams->NumDelays == LVREV_DELAYLINES_2)
{
+#ifndef BUILD_FLOAT
InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * sizeof(LVM_INT32));
InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_INT32));
+#else
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * sizeof(LVM_FLOAT));
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_FLOAT));
+#endif
}
if(pInstanceParams->NumDelays == LVREV_DELAYLINES_1)
{
+#ifndef BUILD_FLOAT
InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_INT32));
+#else
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_FLOAT));
+#endif
}
pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size = InstAlloc_GetTotal(&FastData);
@@ -195,14 +211,25 @@
/*
* Temporary fast memory
*/
+#ifndef BUILD_FLOAT
InstAlloc_AddMember(&Temporary, sizeof(LVM_INT32) * MaxBlockSize); /* General purpose scratch memory */
InstAlloc_AddMember(&Temporary, 2*sizeof(LVM_INT32) * MaxBlockSize); /* Mono->stereo input saved for end mix */
-
+#else
+ /* General purpose scratch memory */
+ InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
+ /* Mono->stereo input saved for end mix */
+ InstAlloc_AddMember(&Temporary, 2 * sizeof(LVM_FLOAT) * MaxBlockSize);
+#endif
if(pInstanceParams->NumDelays == LVREV_DELAYLINES_4)
{
for(i=0; i<4; i++)
{
+#ifndef BUILD_FLOAT
InstAlloc_AddMember(&Temporary, sizeof(LVM_INT32) * MaxBlockSize); /* A Scratch buffer for each delay line */
+#else
+ /* A Scratch buffer for each delay line */
+ InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
+#endif
}
}
@@ -210,7 +237,12 @@
{
for(i=0; i<2; i++)
{
+#ifndef BUILD_FLOAT
InstAlloc_AddMember(&Temporary, sizeof(LVM_INT32) * MaxBlockSize); /* A Scratch buffer for each delay line */
+#else
+ /* A Scratch buffer for each delay line */
+ InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
+#endif
}
}
@@ -218,7 +250,12 @@
{
for(i=0; i<1; i++)
{
+#ifndef BUILD_FLOAT
InstAlloc_AddMember(&Temporary, sizeof(LVM_INT32) * MaxBlockSize); /* A Scratch buffer for each delay line */
+#else
+ /* A Scratch buffer for each delay line */
+ InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
+#endif
}
}
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Private.h b/media/libeffects/lvm/lib/Reverb/src/LVREV_Private.h
index fbfa437..ff7475e 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_Private.h
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_Private.h
@@ -42,16 +42,27 @@
/* Defines */
/* */
/****************************************************************************************/
+#ifndef BUILD_FLOAT
/* General */
#define ONE_OVER_SQRT_TWO 23170 /* 1/sqrt(2) * 2^15 */
#define LVREV_B_8_on_1000 17179869 /* 0.8 * 2^31 */
#define LVREV_HEADROOM 8192 /* -12dB * 2^15 */
#define LVREV_2_9_INQ29 1583769190L /* 2.9 in Q29 format */
#define LVREV_MIN3DB 0x5A82 /* -3dB in Q15 format */
+#else
+/* General */
+#define ONE_OVER_SQRT_TWO 0.707107f /* 1/sqrt(2) * 2^15 */
+#define LVREV_B_8_on_1000 0.008f /* 0.8 * 2^31 */
+#define LVREV_HEADROOM 0.25f /* -12dB * 2^15 */
+#define LVREV_2_9_INQ29 2.9f /* 2.9 in Q29 format */
+#define LVREV_MIN3DB 0.7079457f /* -3dB in Q15 format */
+#endif
/* Intenal constants */
#define LVREV_LP_Poly_Order 4
#define LVREV_LP_Poly_Shift 5
+
+#ifndef BUILD_FLOAT
#define LVREV_T_3_Power_0_on_4 32768
#define LVREV_T_3_Power_1_on_4 43125
#define LVREV_T_3_Power_2_on_4 56755
@@ -61,14 +72,47 @@
#define LVREV_T_3_Power_minus1_on_4 24898 /* 3^(-1/4) * 2^15 */
#define LVREV_T_3_Power_minus2_on_4 18919 /* 3^(-2/4) * 2^15 */
#define LVREV_T_3_Power_minus3_on_4 14375 /* 3^(-3/4) * 2^15 */
-#define LVREV_MAX_T3_DELAY 2527 /* ((48000 * 120 * LVREV_T_3_Power_minus3_on_4) >> 15) / 1000 */
-#define LVREV_MAX_T2_DELAY 3326 /* ((48000 * 120 * LVREV_T_3_Power_minus2_on_4) >> 15) / 1000 */
-#define LVREV_MAX_T1_DELAY 4377 /* ((48000 * 120 * LVREV_T_3_Power_minus1_on_4) >> 15) / 1000 */
-#define LVREV_MAX_T0_DELAY 5760 /* ((48000 * 120 * LVREV_T_3_Power_minus0_on_4) >> 15) / 1000 */
-#define LVREV_MAX_AP3_DELAY 1685 /* ((48000 * 120 * LVREV_T_3_Power_minus3_on_4) >> 15) / 1500 */
-#define LVREV_MAX_AP2_DELAY 2218 /* ((48000 * 120 * LVREV_T_3_Power_minus2_on_4) >> 15) / 1500 */
-#define LVREV_MAX_AP1_DELAY 2918 /* ((48000 * 120 * LVREV_T_3_Power_minus1_on_4) >> 15) / 1500 */
-#define LVREV_MAX_AP0_DELAY 3840 /* ((48000 * 120 * LVREV_T_3_Power_minus0_on_4) >> 15) / 1500 */
+#else/*BUILD_FLOAT*/
+#define LVREV_T60_SCALE 0.000142f /*(1/7000) */
+
+#define LVREV_T_3_Power_0_on_4 1.0f
+#define LVREV_T_3_Power_1_on_4 1.316074f
+#define LVREV_T_3_Power_2_on_4 1.732051f
+#define LVREV_T_3_Power_3_on_4 2.279507f
+#define LVREV_T_3_Power_minus0_on_4 1.0f /* 3^(-0/4) * 2^15 */
+#define LVREV_T_3_Power_minus1_on_4 0.759836f /* 3^(-1/4) * 2^15 */
+#define LVREV_T_3_Power_minus2_on_4 0.577350f /* 3^(-2/4) * 2^15 */
+#define LVREV_T_3_Power_minus3_on_4 0.438691f /* 3^(-3/4) * 2^15 */
+#endif
+
+#ifndef HIGHER_FS
+#define LVREV_MAX_T3_DELAY 2527 /* ((48000 * 120 * LVREV_T_3_Power_minus3_on_4) >> 15) / 1000 */
+#define LVREV_MAX_T2_DELAY 3326 /* ((48000 * 120 * LVREV_T_3_Power_minus2_on_4) >> 15) / 1000 */
+#define LVREV_MAX_T1_DELAY 4377 /* ((48000 * 120 * LVREV_T_3_Power_minus1_on_4) >> 15) / 1000 */
+#define LVREV_MAX_T0_DELAY 5760 /* ((48000 * 120 * LVREV_T_3_Power_minus0_on_4) >> 15) / 1000 */
+#define LVREV_MAX_AP3_DELAY 1685 /* ((48000 * 120 * LVREV_T_3_Power_minus3_on_4) >> 15) / 1500 */
+#define LVREV_MAX_AP2_DELAY 2218 /* ((48000 * 120 * LVREV_T_3_Power_minus2_on_4) >> 15) / 1500 */
+#define LVREV_MAX_AP1_DELAY 2918 /* ((48000 * 120 * LVREV_T_3_Power_minus1_on_4) >> 15) / 1500 */
+#define LVREV_MAX_AP0_DELAY 3840 /* ((48000 * 120 * LVREV_T_3_Power_minus0_on_4) >> 15) / 1500 */
+#else
+ /* ((192000 * 120 * LVREV_T_3_Power_minus3_on_4) >> 15) / 1000 */
+#define LVREV_MAX_T3_DELAY 10108
+ /* ((192000 * 120 * LVREV_T_3_Power_minus2_on_4) >> 15) / 1000 */
+#define LVREV_MAX_T2_DELAY 13304
+ /* ((192000 * 120 * LVREV_T_3_Power_minus1_on_4) >> 15) / 1000 */
+#define LVREV_MAX_T1_DELAY 17508
+ /* ((192000 * 120 * LVREV_T_3_Power_minus0_on_4) >> 15) / 1000 */
+#define LVREV_MAX_T0_DELAY 23040
+ /* ((192000 * 120 * LVREV_T_3_Power_minus3_on_4) >> 15) / 1500 */
+#define LVREV_MAX_AP3_DELAY 6740
+ /* ((192000 * 120 * LVREV_T_3_Power_minus2_on_4) >> 15) / 1500 */
+#define LVREV_MAX_AP2_DELAY 8872
+ /* ((192000 * 120 * LVREV_T_3_Power_minus1_on_4) >> 15) / 1500 */
+#define LVREV_MAX_AP1_DELAY 11672
+ /* ((192000 * 120 * LVREV_T_3_Power_minus0_on_4) >> 15) / 1500 */
+#define LVREV_MAX_AP0_DELAY 15360
+#endif
+
#define LVREV_BYPASSMIXER_TC 1000 /* Bypass mixer time constant*/
#define LVREV_ALLPASS_TC 1000 /* All-pass filter time constant */
#define LVREV_ALLPASS_TAP_TC 10000 /* All-pass filter dely tap change */
@@ -76,7 +120,12 @@
#define LVREV_OUTPUTGAIN_SHIFT 5 /* Bits shift for output gain correction */
/* Parameter limits */
+#ifndef HIGHER_FS
#define LVREV_NUM_FS 9 /* Number of supported sample rates */
+#else
+#define LVREV_NUM_FS 11 /* Number of supported sample rates */
+#endif
+
#define LVREV_MAXBLKSIZE_LIMIT 64 /* Maximum block size low limit */
#define LVREV_MAX_LEVEL 100 /* Maximum level, 100% */
#define LVREV_MIN_LPF_CORNER 50 /* Low pass filter limits */
@@ -95,6 +144,7 @@
/* Structures */
/* */
/****************************************************************************************/
+#ifndef BUILD_FLOAT
/* Fast data structure */
typedef struct
{
@@ -161,7 +211,81 @@
} LVREV_Instance_st;
+#else /* BUILD_FLOAT */
+/* Fast data structure */
+typedef struct
+{
+ Biquad_1I_Order1_FLOAT_Taps_t HPTaps; /* High pass filter taps */
+ Biquad_1I_Order1_FLOAT_Taps_t LPTaps; /* Low pass filter taps */
+ Biquad_1I_Order1_FLOAT_Taps_t RevLPTaps[4]; /* Reverb low pass filters taps */
+
+} LVREV_FastData_st;
+
+
+/* Fast coefficient structure */
+typedef struct
+{
+
+ Biquad_FLOAT_Instance_t HPCoefs; /* High pass filter coefficients */
+ Biquad_FLOAT_Instance_t LPCoefs; /* Low pass filter coefficients */
+ Biquad_FLOAT_Instance_t RevLPCoefs[4]; /* Reverb low pass filters coefficients */
+
+} LVREV_FastCoef_st;
+typedef struct
+{
+ /* General */
+ LVREV_InstanceParams_st InstanceParams; /* Initialisation time instance parameters */
+ LVREV_MemoryTable_st MemoryTable; /* Memory table */
+ LVREV_ControlParams_st CurrentParams; /* Parameters being used */
+ LVREV_ControlParams_st NewParams; /* New parameters from the \
+ calling application */
+ LVM_CHAR bControlPending; /* Flag to indicate new parameters \
+ are available */
+ LVM_CHAR bFirstControl; /* Flag to indicate that the control \
+ function is called for the first time */
+ LVM_CHAR bDisableReverb; /* Flag to indicate that the mix level is
+ 0% and the reverb can be disabled */
+ LVM_INT32 RoomSizeInms; /* Room size in msec */
+ LVM_INT32 MaxBlkLen; /* Maximum block size for internal
+ processing */
+
+ /* Aligned memory pointers */
+ LVREV_FastData_st *pFastData; /* Fast data memory base address */
+ LVREV_FastCoef_st *pFastCoef; /* Fast coefficient memory base address */
+ LVM_FLOAT *pScratchDelayLine[4]; /* Delay line scratch memory */
+ LVM_FLOAT *pScratch; /* Multi ussge scratch */
+ LVM_FLOAT *pInputSave; /* Reverb block input save for dry/wet
+ mixing*/
+
+ /* Feedback matrix */
+ Mix_1St_Cll_FLOAT_t FeedbackMixer[4]; /* Mixer for Pop and Click Supression \
+ caused by feedback Gain */
+
+
+ /* All-Pass Filter */
+ LVM_INT32 T[4]; /* Maximum delay size of buffer */
+ LVM_FLOAT *pDelay_T[4]; /* Pointer to delay buffers */
+ LVM_INT32 Delay_AP[4]; /* Offset to AP delay buffer start */
+ LVM_INT16 AB_Selection; /* Smooth from tap A to B when 1 \
+ otherwise B to A */
+ LVM_INT32 A_DelaySize[4]; /* A delay length in samples */
+ LVM_INT32 B_DelaySize[4]; /* B delay length in samples */
+ LVM_FLOAT *pOffsetA[4]; /* Offset for the A delay tap */
+ LVM_FLOAT *pOffsetB[4]; /* Offset for the B delay tap */
+ Mix_2St_Cll_FLOAT_t Mixer_APTaps[4]; /* Smoothed AP delay mixer */
+ Mix_1St_Cll_FLOAT_t Mixer_SGFeedback[4]; /* Smoothed SAfeedback gain */
+ Mix_1St_Cll_FLOAT_t Mixer_SGFeedforward[4]; /* Smoothed AP feedforward gain */
+
+ /* Output gain */
+ Mix_2St_Cll_FLOAT_t BypassMixer; /* Dry/wet mixer */
+ LVM_FLOAT Gain; /* Gain applied to output to maintain
+ average signal power */
+ Mix_1St_Cll_FLOAT_t GainMixer; /* Gain smoothing */
+
+} LVREV_Instance_st;
+
+#endif
/****************************************************************************************/
/* */
/* Function prototypes */
@@ -169,12 +293,17 @@
/****************************************************************************************/
LVREV_ReturnStatus_en LVREV_ApplyNewSettings(LVREV_Instance_st *pPrivate);
-
+#ifdef BUILD_FLOAT
+void ReverbBlock(LVM_FLOAT *pInput,
+ LVM_FLOAT *pOutput,
+ LVREV_Instance_st *pPrivate,
+ LVM_UINT16 NumSamples);
+#else
void ReverbBlock(LVM_INT32 *pInput,
LVM_INT32 *pOutput,
LVREV_Instance_st *pPrivate,
LVM_UINT16 NumSamples);
-
+#endif
LVM_INT32 BypassMixer_Callback(void *pCallbackData,
void *pGeneralPurpose,
LVM_INT16 GeneralPurpose );
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c
index 5c7a8a0..566d84f 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c
@@ -46,14 +46,26 @@
/* 1. The input and output buffers must be 32-bit aligned */
/* */
/****************************************************************************************/
+#ifdef BUILD_FLOAT
+LVREV_ReturnStatus_en LVREV_Process(LVREV_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ const LVM_UINT16 NumSamples)
+#else
LVREV_ReturnStatus_en LVREV_Process(LVREV_Handle_t hInstance,
const LVM_INT32 *pInData,
LVM_INT32 *pOutData,
const LVM_UINT16 NumSamples)
+#endif
{
LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)hInstance;
+#ifdef BUILD_FLOAT
+ LVM_FLOAT *pInput = (LVM_FLOAT *)pInData;
+ LVM_FLOAT *pOutput = pOutData;
+#else
LVM_INT32 *pInput = (LVM_INT32 *)pInData;
LVM_INT32 *pOutput = pOutData;
+#endif
LVM_INT32 SamplesToProcess, RemainingSamples;
LVM_INT32 format = 1;
@@ -105,7 +117,7 @@
/*
* Copy the data to the output buffer, convert to stereo is required
*/
-
+#ifndef BUILD_FLOAT
if(pLVREV_Private->CurrentParams.SourceFormat == LVM_MONO){
MonoTo2I_32(pInput, pOutput, NumSamples);
} else {
@@ -113,6 +125,15 @@
(LVM_INT16 *)pOutput,
(LVM_INT16)(NumSamples << 2)); // 32 bit data, stereo
}
+#else
+ if(pLVREV_Private->CurrentParams.SourceFormat == LVM_MONO){
+ MonoTo2I_Float(pInput, pOutput, NumSamples);
+ } else {
+ Copy_Float(pInput,
+ pOutput,
+ (LVM_INT16)(NumSamples << 1)); // 32 bit data, stereo
+ }
+#endif
}
return LVREV_SUCCESS;
@@ -143,9 +164,13 @@
}
ReverbBlock(pInput, pOutput, pLVREV_Private, (LVM_UINT16)SamplesToProcess);
-
+#ifdef BUILD_FLOAT
+ pInput = (LVM_FLOAT *)(pInput + (SamplesToProcess * format));
+ pOutput = (LVM_FLOAT *)(pOutput + (SamplesToProcess * 2)); // Always stereo output
+#else
pInput = (LVM_INT32 *)(pInput +(SamplesToProcess*format));
- pOutput = (LVM_INT32 *)(pOutput+(SamplesToProcess*2)); // Always stereo output
+ pOutput = (LVM_INT32 *)(pOutput+(SamplesToProcess*2));
+#endif
}
return LVREV_SUCCESS;
@@ -175,7 +200,7 @@
/* 1. The input and output buffers must be 32-bit aligned */
/* */
/****************************************************************************************/
-
+#ifndef BUILD_FLOAT
void ReverbBlock(LVM_INT32 *pInput, LVM_INT32 *pOutput, LVREV_Instance_st *pPrivate, LVM_UINT16 NumSamples)
{
LVM_INT16 j, size;
@@ -479,7 +504,322 @@
return;
}
+#else
+void ReverbBlock(LVM_FLOAT *pInput, LVM_FLOAT *pOutput,
+ LVREV_Instance_st *pPrivate, LVM_UINT16 NumSamples)
+{
+ LVM_INT16 j, size;
+ LVM_FLOAT *pDelayLine;
+ LVM_FLOAT *pDelayLineInput = pPrivate->pScratch;
+ LVM_FLOAT *pScratch = pPrivate->pScratch;
+ LVM_FLOAT *pIn;
+ LVM_FLOAT *pTemp = pPrivate->pInputSave;
+ LVM_INT32 NumberOfDelayLines;
+
+ /******************************************************************************
+ * All calculations will go into the buffer pointed to by pTemp, this will *
+ * then be mixed with the original input to create the final output. *
+ * *
+ * When INPLACE processing is selected this must be a temporary buffer and *
+ * hence this is the worst case, so for simplicity this will ALWAYS be so *
+ * *
+ * The input buffer will remain untouched until the output of the mixer if *
+ * INPLACE processing is selected. *
+ * *
+ * The temp buffer will always be NumSamples in size regardless of MONO or *
+ * STEREO input. In the case of stereo input all processing is done in MONO *
+ * and the final output is converted to STEREO after the mixer *
+ ******************************************************************************/
+
+ if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
+ {
+ NumberOfDelayLines = 4;
+ }
+ else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
+ {
+ NumberOfDelayLines = 2;
+ }
+ else
+ {
+ NumberOfDelayLines = 1;
+ }
+
+ if(pPrivate->CurrentParams.SourceFormat == LVM_MONO)
+ {
+ pIn = pInput;
+ }
+ else
+ {
+ /*
+ * Stereo to mono conversion
+ */
+
+ From2iToMono_Float(pInput,
+ pTemp,
+ (LVM_INT16)NumSamples);
+ pIn = pTemp;
+ }
+
+ Mult3s_Float(pIn,
+ (LVM_FLOAT)LVREV_HEADROOM,
+ pTemp,
+ (LVM_INT16)NumSamples);
+
+ /*
+ * High pass filter
+ */
+ FO_1I_D32F32C31_TRC_WRA_01(&pPrivate->pFastCoef->HPCoefs,
+ pTemp,
+ pTemp,
+ (LVM_INT16)NumSamples);
+ /*
+ * Low pass filter
+ */
+ FO_1I_D32F32C31_TRC_WRA_01(&pPrivate->pFastCoef->LPCoefs,
+ pTemp,
+ pTemp,
+ (LVM_INT16)NumSamples);
+
+ /*
+ * Process all delay lines
+ */
+
+ for(j = 0; j < NumberOfDelayLines; j++)
+ {
+ pDelayLine = pPrivate->pScratchDelayLine[j];
+
+ /*
+ * All-pass filter with pop and click suppression
+ */
+ /* Get the smoothed, delayed output. Put it in the output buffer */
+ MixSoft_2St_D32C31_SAT(&pPrivate->Mixer_APTaps[j],
+ pPrivate->pOffsetA[j],
+ pPrivate->pOffsetB[j],
+ pDelayLine,
+ (LVM_INT16)NumSamples);
+ /* Re-align the all pass filter delay buffer and copying the fixed delay data \
+ to the AP delay in the process */
+ Copy_Float(&pPrivate->pDelay_T[j][NumSamples],
+ pPrivate->pDelay_T[j],
+ (LVM_INT16)(pPrivate->T[j] - NumSamples)); /* 32-bit data */
+ /* Apply the smoothed feedback and save to fixed delay input (currently empty) */
+ MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedback[j],
+ pDelayLine,
+ &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
+ (LVM_INT16)NumSamples);
+ /* Sum into the AP delay line */
+ Mac3s_Sat_Float(&pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
+ -1.0f, /* Invert since the feedback coefficient is negative */
+ &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j] - NumSamples],
+ (LVM_INT16)NumSamples);
+ /* Apply smoothed feedforward sand save to fixed delay input (currently empty) */
+ MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedforward[j],
+ &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j] - NumSamples],
+ &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
+ (LVM_INT16)NumSamples);
+ /* Sum into the AP output */
+ Mac3s_Sat_Float(&pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
+ 1.0f,
+ pDelayLine,
+ (LVM_INT16)NumSamples);
+
+ /*
+ * Feedback gain
+ */
+ MixSoft_1St_D32C31_WRA(&pPrivate->FeedbackMixer[j], pDelayLine, pDelayLine, NumSamples);
+
+ /*
+ * Low pass filter
+ */
+ FO_1I_D32F32C31_TRC_WRA_01(&pPrivate->pFastCoef->RevLPCoefs[j],
+ pDelayLine,
+ pDelayLine,
+ (LVM_INT16)NumSamples);
+ }
+
+ /*
+ * Apply rotation matrix and delay samples
+ */
+ for(j = 0; j < NumberOfDelayLines; j++)
+ {
+
+ Copy_Float(pTemp,
+ pDelayLineInput,
+ (LVM_INT16)(NumSamples));
+ /*
+ * Rotation matrix mix
+ */
+ switch(j)
+ {
+ case 3:
+ /*
+ * Add delay line 1 and 2 contribution
+ */
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[2], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+
+ break;
+ case 2:
+
+ /*
+ * Add delay line 0 and 3 contribution
+ */
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[3], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+
+ break;
+ case 1:
+ if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
+ {
+ /*
+ * Add delay line 0 and 3 contribution
+ */
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[3], pDelayLineInput,
+ (LVM_INT16)NumSamples);
+
+ }
+ else
+ {
+ /*
+ * Add delay line 0 and 1 contribution
+ */
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+
+ }
+ break;
+ case 0:
+ if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
+ {
+ /*
+ * Add delay line 1 and 2 contribution
+ */
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[2], pDelayLineInput,
+ (LVM_INT16)NumSamples);
+
+ }
+ else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
+ {
+ /*
+ * Add delay line 0 and 1 contribution
+ */
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[0], pDelayLineInput,
+ (LVM_INT16)NumSamples);
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+
+ }
+ else
+ {
+ /*
+ * Add delay line 0 contribution
+ */
+
+ /* SOURCE DESTINATION*/
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[0], pDelayLineInput,
+ (LVM_INT16)NumSamples);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Delay samples
+ */
+ Copy_Float(pDelayLineInput,
+ &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
+ (LVM_INT16)(NumSamples)); /* 32-bit data */
+ }
+ /*
+ * Create stereo output
+ */
+ switch(pPrivate->InstanceParams.NumDelays)
+ {
+ case LVREV_DELAYLINES_4:
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[3],
+ pPrivate->pScratchDelayLine[0],
+ (LVM_INT16)NumSamples);
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[2],
+ pPrivate->pScratchDelayLine[1],
+ (LVM_INT16)NumSamples);
+
+
+ JoinTo2i_Float(pPrivate->pScratchDelayLine[0],
+ pPrivate->pScratchDelayLine[1],
+ pTemp,
+ (LVM_INT16)NumSamples);
+
+
+ break;
+ case LVREV_DELAYLINES_2:
+
+ Copy_Float(pPrivate->pScratchDelayLine[1],
+ pScratch,
+ (LVM_INT16)(NumSamples));
+
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0],
+ -1.0f,
+ pScratch,
+ (LVM_INT16)NumSamples);
+
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[1],
+ pPrivate->pScratchDelayLine[0],
+ (LVM_INT16)NumSamples);
+
+
+ JoinTo2i_Float(pPrivate->pScratchDelayLine[0],
+ pScratch,
+ pTemp,
+ (LVM_INT16)NumSamples);
+ break;
+ case LVREV_DELAYLINES_1:
+ MonoTo2I_Float(pPrivate->pScratchDelayLine[0],
+ pTemp,
+ (LVM_INT16)NumSamples);
+ break;
+ default:
+ break;
+ }
+
+
+ /*
+ * Dry/wet mixer
+ */
+
+ size = (LVM_INT16)(NumSamples << 1);
+ MixSoft_2St_D32C31_SAT(&pPrivate->BypassMixer,
+ pTemp,
+ pTemp,
+ pOutput,
+ size);
+
+ /* Apply Gain*/
+
+ Shift_Sat_Float(LVREV_OUTPUTGAIN_SHIFT,
+ pOutput,
+ pOutput,
+ size);
+
+ MixSoft_1St_D32C31_WRA(&pPrivate->GainMixer,
+ pOutput,
+ pOutput,
+ size);
+
+ return;
+}
+#endif
/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.c
index f5895a7..a719053 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.c
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.c
@@ -61,10 +61,15 @@
* Check all new control parameters are in range
*/
if( ((pNewParams->OperatingMode != LVM_MODE_OFF) && (pNewParams->OperatingMode != LVM_MODE_ON)) ||
- ((pNewParams->SampleRate != LVM_FS_8000) && (pNewParams->SampleRate != LVM_FS_11025) && (pNewParams->SampleRate != LVM_FS_12000) &&
+ (
+ (pNewParams->SampleRate != LVM_FS_8000) && (pNewParams->SampleRate != LVM_FS_11025) && (pNewParams->SampleRate != LVM_FS_12000) &&
(pNewParams->SampleRate != LVM_FS_16000) && (pNewParams->SampleRate != LVM_FS_22050) && (pNewParams->SampleRate != LVM_FS_24000) &&
- (pNewParams->SampleRate != LVM_FS_32000) && (pNewParams->SampleRate != LVM_FS_44100) && (pNewParams->SampleRate != LVM_FS_48000)) ||
- ((pNewParams->SourceFormat != LVM_STEREO) && (pNewParams->SourceFormat != LVM_MONOINSTEREO) && (pNewParams->SourceFormat != LVM_MONO)) )
+ (pNewParams->SampleRate != LVM_FS_32000) && (pNewParams->SampleRate != LVM_FS_44100) && (pNewParams->SampleRate != LVM_FS_48000)
+#ifdef HIGHER_FS
+ && (pNewParams->SampleRate != LVM_FS_96000) && (pNewParams->SampleRate != LVM_FS_192000)
+#endif
+ )
+ || ((pNewParams->SourceFormat != LVM_STEREO) && (pNewParams->SourceFormat != LVM_MONOINSTEREO) && (pNewParams->SourceFormat != LVM_MONO)) )
{
return (LVREV_OUTOFRANGE);
}
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.c
index 5a6d43d..b3edc60 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.c
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.c
@@ -29,6 +29,7 @@
/****************************************************************************************/
/* Table with supported sampling rates. The table can be indexed using LVM_Fs_en */
+#ifndef HIGHER_FS
const LVM_UINT16 LVM_FsTable[] = {
8000 ,
11025,
@@ -40,14 +41,37 @@
44100,
48000
};
-
+#else
+const LVM_UINT32 LVM_FsTable[] = {
+ 8000 ,
+ 11025,
+ 12000,
+ 16000,
+ 22050,
+ 24000,
+ 32000,
+ 44100,
+ 48000,
+ 96000,
+ 192000
+};
+#endif
/* Table with supported sampling rates. The table can be indexed using LVM_Fs_en */
+#ifndef HIGHER_FS
LVM_UINT16 LVM_GetFsFromTable(LVM_Fs_en FsIndex){
if (FsIndex > LVM_FS_48000)
return 0;
return (LVM_FsTable[FsIndex]);
}
+#else
+LVM_UINT32 LVM_GetFsFromTable(LVM_Fs_en FsIndex){
+ if (FsIndex > LVM_FS_192000)
+ return 0;
+
+ return (LVM_FsTable[FsIndex]);
+}
+#endif
/* In order to maintain consistant input and out put signal strengths
output gain/attenuation is applied. This gain depends on T60 and Rooms
@@ -69,6 +93,7 @@
*/
/* Normalizing output including Reverb Level part (only shift up)*/
+#ifndef BUILD_FLOAT
const LVM_INT32 LVREV_GainPolyTable[24][5]={{1,17547434,128867434,-120988896,50761228,},
{2,18256869,172666902,-193169292,88345744,},
{3,16591311,139250151,-149667234,66770059,},
@@ -94,6 +119,32 @@
{90,16003322,48323661,-35607378,13153872,},
{100,15955223,48558201,-33706865,11715792,},
};
-
+#else
+const LVM_FLOAT LVREV_GainPolyTable[24][5]={{1,1.045909f,7.681098f,-7.211500f,3.025605f,},
+ {2,1.088194f,10.291749f,-11.513787f,5.265817f,},
+ {3,0.988919f,8.299956f,-8.920862f,3.979806f,},
+ {4,1.035927f,10.182567f,-10.346134f,4.546533f,},
+ {5,1.130313f,12.538727f,-13.627023f,6.165208f,},
+ {6,1.060743f,8.091713f,-8.588079f,3.834230f,},
+ {7,1.040381f,10.406566f,-11.176650f,5.075132f,},
+ {8,1.026944f,8.387302f,-8.689796f,3.895863f,},
+ {9,1.013312f,9.727236f,-10.534165f,4.742272f,},
+ {10,0.996095f,8.492249f,-7.947677f,3.478917f,},
+ {13,1.079346f,8.894425f,-9.641768f,4.434442f,},
+ {15,0.994327f,7.441335f,-8.003979f,3.581177f,},
+ {17,0.991067f,7.208373f,-7.257859f,3.167774f,},
+ {20,1.033445f,7.476371f,-7.546960f,3.369703f,},
+ {25,0.982830f,5.913867f,-5.638448f,2.420932f,},
+ {30,0.928782f,5.035343f,-4.492104f,1.844904f,},
+ {40,0.953714f,5.060232f,-4.472204f,1.829642f,},
+ {50,0.899258f,4.273357f,-3.537492f,1.387576f,},
+ {60,0.943584f,4.093228f,-3.469658f,1.410911f,},
+ {70,0.926021f,3.973125f,-3.331985f,1.344690f,},
+ {75,0.894853f,2.871747f,-1.438758f,0.311856f,},
+ {80,0.935122f,2.991857f,-2.038882f,0.686395f,},
+ {90,0.953872f,2.880315f,-2.122365f,0.784032f,},
+ {100,0.951005f,2.894294f,-2.009086f,0.698316f,},
+};
+#endif
/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.h b/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.h
index 5f993bd..0658186 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.h
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.h
@@ -37,10 +37,19 @@
/* */
/****************************************************************************************/
+#ifndef HIGHER_FS
extern const LVM_UINT16 LVM_FsTable[];
extern LVM_UINT16 LVM_GetFsFromTable(LVM_Fs_en FsIndex);
-extern LVM_INT32 LVREV_GainPolyTable[24][5];
+#else
+extern const LVM_UINT32 LVM_FsTable[];
+extern LVM_UINT32 LVM_GetFsFromTable(LVM_Fs_en FsIndex);
+#endif
+#ifndef BUILD_FLOAT
+extern LVM_INT32 LVREV_GainPolyTable[24][5];
+#else
+extern LVM_FLOAT LVREV_GainPolyTable[24][5];
+#endif
#ifdef __cplusplus
}
#endif
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h b/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h
index a675cb2..2038fbb 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h
@@ -216,11 +216,17 @@
/* otherwise Error due to bad parameters */
/* */
/*********************************************************************************************************************************/
+#ifdef BUILD_FLOAT
+LVPSA_RETURN LVPSA_Process ( pLVPSA_Handle_t hInstance,
+ LVM_FLOAT *pLVPSA_InputSamples,
+ LVM_UINT16 InputBlockSize,
+ LVPSA_Time AudioTime );
+#else
LVPSA_RETURN LVPSA_Process ( pLVPSA_Handle_t hInstance,
LVM_INT16 *pLVPSA_InputSamples,
LVM_UINT16 InputBlockSize,
LVPSA_Time AudioTime );
-
+#endif
/*********************************************************************************************************************************/
/* */
/* FUNCTION: LVPSA_GetSpectrum */
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Control.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Control.c
index cd5f69c..f6c4ea7 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Control.c
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Control.c
@@ -28,6 +28,15 @@
LVPSA_RETURN LVPSA_SetQPFCoefficients( LVPSA_InstancePr_t *pInst,
LVPSA_ControlParams_t *pParams );
+#ifdef BUILD_FLOAT
+LVPSA_RETURN LVPSA_BPSinglePrecCoefs( LVM_UINT16 Fs,
+ LVPSA_FilterParam_t *pFilterParams,
+ BP_FLOAT_Coefs_t *pCoefficients);
+
+LVPSA_RETURN LVPSA_BPDoublePrecCoefs( LVM_UINT16 Fs,
+ LVPSA_FilterParam_t *pFilterParams,
+ BP_FLOAT_Coefs_t *pCoefficients);
+#else
LVPSA_RETURN LVPSA_BPSinglePrecCoefs( LVM_UINT16 Fs,
LVPSA_FilterParam_t *pFilterParams,
BP_C16_Coefs_t *pCoefficients);
@@ -39,7 +48,7 @@
LVPSA_RETURN LVPSA_BPDoublePrecCoefs( LVM_UINT16 Fs,
LVPSA_FilterParam_t *pFilterParams,
BP_C32_Coefs_t *pCoefficients);
-
+#endif
LVPSA_RETURN LVPSA_SetBPFCoefficients( LVPSA_InstancePr_t *pInst,
LVPSA_ControlParams_t *pParams );
@@ -179,7 +188,11 @@
LVM_UINT16 Freq;
LVPSA_ControlParams_t Params;
extern LVM_INT16 LVPSA_nSamplesBufferUpdate[];
+#ifndef HIGHER_FS
extern LVM_UINT16 LVPSA_SampleRateTab[];
+#else
+ extern LVM_UINT32 LVPSA_SampleRateTab[];
+#endif
extern LVM_UINT16 LVPSA_DownSamplingFactor[];
@@ -267,8 +280,11 @@
LVPSA_RETURN LVPSA_SetBPFiltersType ( LVPSA_InstancePr_t *pInst,
LVPSA_ControlParams_t *pParams )
{
-
+#ifndef HIGHER_FS
extern LVM_UINT16 LVPSA_SampleRateTab[]; /* Sample rate table */
+#else
+ extern LVM_UINT32 LVPSA_SampleRateTab[]; /* Sample rate table */
+#endif
LVM_UINT16 ii; /* Filter band index */
LVM_UINT32 fs = (LVM_UINT32)LVPSA_SampleRateTab[(LVM_UINT16)pParams->Fs]; /* Sample rate */
LVM_UINT32 fc; /* Filter centre frequency */
@@ -342,26 +358,42 @@
{
case LVPSA_DoublePrecisionFilter:
{
+#ifndef BUILD_FLOAT
BP_C32_Coefs_t Coefficients;
/*
* Calculate the double precision coefficients
*/
LVPSA_BPDoublePrecCoefs((LVM_UINT16)pParams->Fs,
- &pInst->pFiltersParams[ii],
- &Coefficients);
-
+ &pInst->pFiltersParams[ii],
+ &Coefficients);
/*
* Set the coefficients
*/
BP_1I_D16F32Cll_TRC_WRA_01_Init ( &pInst->pBP_Instances[ii],
&pInst->pBP_Taps[ii],
&Coefficients);
+#else
+ BP_FLOAT_Coefs_t Coefficients;
+ /*
+ * Calculate the double precision coefficients
+ */
+ LVPSA_BPDoublePrecCoefs((LVM_UINT16)pParams->Fs,
+ &pInst->pFiltersParams[ii],
+ &Coefficients);
+ /*
+ * Set the coefficients
+ */
+ BP_1I_D16F32Cll_TRC_WRA_01_Init ( &pInst->pBP_Instances[ii],
+ &pInst->pBP_Taps[ii],
+ &Coefficients);
+#endif
break;
}
case LVPSA_SimplePrecisionFilter:
{
+#ifndef BUILD_FLOAT
BP_C16_Coefs_t Coefficients;
/*
@@ -374,9 +406,26 @@
/*
* Set the coefficients
*/
- BP_1I_D16F16Css_TRC_WRA_01_Init ( &pInst->pBP_Instances[ii],
+ BP_1I_D16F16Css_TRC_WRA_01_Init (&pInst->pBP_Instances[ii],
&pInst->pBP_Taps[ii],
&Coefficients);
+#else
+ BP_FLOAT_Coefs_t Coefficients;
+
+ /*
+ * Calculate the single precision coefficients
+ */
+ LVPSA_BPSinglePrecCoefs((LVM_UINT16)pParams->Fs,
+ &pInst->pFiltersParams[ii],
+ &Coefficients);
+
+ /*
+ * Set the coefficients
+ */
+ BP_1I_D16F16Css_TRC_WRA_01_Init (&pInst->pBP_Instances[ii],
+ &pInst->pBP_Taps[ii],
+ &Coefficients);
+#endif
break;
}
}
@@ -409,18 +458,31 @@
{
LVM_UINT16 ii;
LVM_Fs_en Fs = pParams->Fs;
+#ifndef BUILD_FLOAT
QPD_C32_Coefs *pCoefficients;
extern QPD_C32_Coefs LVPSA_QPD_Coefs[];
-
pCoefficients = &LVPSA_QPD_Coefs[(pParams->LevelDetectionSpeed * LVPSA_NR_SUPPORTED_RATE) + Fs];
+#else
+ QPD_FLOAT_Coefs *pCoefficients;
+ extern QPD_FLOAT_Coefs LVPSA_QPD_Float_Coefs[];
+
+ pCoefficients = &LVPSA_QPD_Float_Coefs[(pParams->LevelDetectionSpeed * \
+ LVPSA_NR_SUPPORTED_RATE) + Fs];
+#endif
for (ii = 0; ii < pInst->nRelevantFilters; ii++)
{
- LVPSA_QPD_Init (&pInst->pQPD_States[ii],
- &pInst->pQPD_Taps[ii],
- pCoefficients );
+#ifndef BUILD_FLOAT
+ LVPSA_QPD_Init (&pInst->pQPD_States[ii],
+ &pInst->pQPD_Taps[ii],
+ pCoefficients );
+#else
+ LVPSA_QPD_Init_Float (&pInst->pQPD_States[ii],
+ &pInst->pQPD_Taps[ii],
+ pCoefficients );
+#endif
}
return(LVPSA_OK);
@@ -460,6 +522,87 @@
/* of the n bands equalizer (LVEQNB */
/* */
/****************************************************************************************/
+#ifdef BUILD_FLOAT
+LVPSA_RETURN LVPSA_BPSinglePrecCoefs( LVM_UINT16 Fs,
+ LVPSA_FilterParam_t *pFilterParams,
+ BP_FLOAT_Coefs_t *pCoefficients)
+{
+
+ extern LVM_FLOAT LVPSA_Float_TwoPiOnFsTable[];
+ extern LVM_FLOAT LVPSA_Float_CosCoef[];
+
+
+ /*
+ * Intermediate variables and temporary values
+ */
+ LVM_FLOAT T0;
+ LVM_FLOAT D;
+ LVM_FLOAT A0;
+ LVM_FLOAT B1;
+ LVM_FLOAT B2;
+ LVM_FLOAT Dt0;
+ LVM_FLOAT B2_Den;
+ LVM_FLOAT B2_Num;
+ LVM_FLOAT COS_T0;
+ LVM_FLOAT coef;
+ LVM_FLOAT factor;
+ LVM_FLOAT t0;
+ LVM_INT16 i;
+
+
+ /*
+ * Get the filter definition
+ */
+ LVM_FLOAT Frequency = (LVM_FLOAT)(pFilterParams->CenterFrequency);
+ LVM_FLOAT QFactor = ((LVM_FLOAT)(pFilterParams->QFactor)) / 100;
+
+ /*
+ * Calculating the intermediate values
+ */
+ T0 = Frequency * LVPSA_Float_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
+ D = 3200; /* Floating point value 1.000000 (1*100*2^5) */
+ /* Force D = 1 : the function was originally used for a peaking filter.
+ The D parameter do not exist for a BandPass filter coefficients */
+
+ /*
+ * Calculate the B2 coefficient
+ */
+ Dt0 = T0 / 2048 ;
+ B2_Den = QFactor + Dt0;
+ B2_Num = Dt0 - QFactor;
+ B2 = B2_Num / (2 * B2_Den);
+
+ /*
+ * Calculate the cosine by a polynomial expansion using the equation:
+ *
+ * Cos += coef(n) * t0^n For n = 0 to 6
+ */
+ T0 = (T0 / 2048) * 0.63658558f; /* Scale to 1.0 in 16-bit for range 0 to fs/2 */
+ t0 = T0 ;
+ factor = 1.0f; /* Initialise to 1.0 for the a0 coefficient */
+ COS_T0 = 0.0f; /* Initialise the error to zero */
+ for (i = 1; i < 7; i++)
+ {
+ coef = LVPSA_Float_CosCoef[i]; /* Get the nth coefficient */
+ COS_T0 += (factor * coef); /* The nth partial sum */
+ factor = (factor * t0) ; /* Calculate t0^n */
+ }
+ COS_T0 = COS_T0 * 8; /*LVPSA_CosCoef_float[0]*/ /* Correct the scaling */
+
+
+ B1 = ((LVM_FLOAT)0.5 - B2) * (COS_T0); /* B1 = (0.5 - b2) * cos(t0) */
+ A0 = ((LVM_FLOAT)0.5 + B2) / 2; /* A0 = (0.5 + b2) / 2 */
+
+ /*
+ * Write coeff into the data structure
+ */
+ pCoefficients->A0 = A0 * 2;
+ pCoefficients->B1 = B1 * 2;
+ pCoefficients->B2 = B2 * 2;
+
+ return(LVPSA_OK);
+}
+#else
LVPSA_RETURN LVPSA_BPSinglePrecCoefs( LVM_UINT16 Fs,
LVPSA_FilterParam_t *pFilterParams,
BP_C16_Coefs_t *pCoefficients)
@@ -541,7 +684,7 @@
return(LVPSA_OK);
}
-
+#endif
/****************************************************************************************/
/* */
/* FUNCTION: LVPSA_BPDoublePrecCoefs */
@@ -584,6 +727,90 @@
/* of the n bands equalizer (LVEQNB */
/* */
/****************************************************************************************/
+#ifdef BUILD_FLOAT
+LVPSA_RETURN LVPSA_BPDoublePrecCoefs( LVM_UINT16 Fs,
+ LVPSA_FilterParam_t *pFilterParams,
+ BP_FLOAT_Coefs_t *pCoefficients)
+{
+
+ extern LVM_FLOAT LVPSA_Float_TwoPiOnFsTable[];
+ extern LVM_FLOAT LVPSA_Float_DPCosCoef[];
+
+ /*
+ * Intermediate variables and temporary values
+ */
+ LVM_FLOAT T0;
+ LVM_FLOAT D;
+ LVM_FLOAT A0;
+ LVM_FLOAT B1;
+ LVM_FLOAT B2;
+ LVM_FLOAT Dt0;
+ LVM_FLOAT B2_Den;
+ LVM_FLOAT B2_Num;
+ LVM_FLOAT CosErr;
+ LVM_FLOAT coef;
+ LVM_FLOAT factor;
+ LVM_FLOAT t0;
+ LVM_INT16 i;
+
+ /*
+ * Get the filter definition
+ */
+ LVM_FLOAT Frequency = (LVM_FLOAT)(pFilterParams->CenterFrequency);
+ LVM_FLOAT QFactor = ((LVM_FLOAT)(pFilterParams->QFactor)) / 100;
+
+
+ /*
+ * Calculating the intermediate values
+ */
+ T0 = Frequency * LVPSA_Float_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
+ D = 3200; /* Floating point value 1.000000 (1*100*2^5) */
+ /* Force D = 1 : the function was originally used for a peaking filter.
+ The D parameter do not exist for a BandPass filter coefficients */
+
+ /*
+ * Calculate the B2 coefficient
+ */
+ Dt0 = T0 / 2048 ;
+ B2_Den = QFactor + Dt0;
+ B2_Num = Dt0 - QFactor;
+ B2 = B2_Num / (2 * B2_Den);
+
+ /*
+ * Calculate the cosine error by a polynomial expansion using the equation:
+ *
+ * CosErr += coef(n) * t0^n For n = 0 to 4
+ */
+ T0 = T0 * 0.994750f; /* Scale to 1.0 in 16-bit for range 0 to fs/50 */
+ t0 = T0;
+ factor = 1.0f; /* Initialise to 1.0 for the a0 coefficient */
+ CosErr = 0.0f; /* Initialise the error to zero */
+ for (i = 1; i < 5; i++)
+ {
+ coef = LVPSA_Float_DPCosCoef[i]; /* Get the nth coefficient */
+ CosErr += factor * coef; /* The nth partial sum */
+ factor = factor * t0; /* Calculate t0^n */
+ }
+ CosErr = CosErr * 2; /* Correct the scaling */
+
+ /*
+ * Calculate the B1 and A0 coefficients
+ */
+ B1 = ((LVM_FLOAT)0.5 - B2); /* B1 = (0.5 - b2) */
+ A0 = B1 * CosErr ; /* Temporary storage for (0.5 - b2) * coserr(t0) */
+ B1 -= A0; /* B1 = (0.5 - b2) * (1 - coserr(t0)) */
+ A0 = ((LVM_FLOAT)0.5 + B2) / 2; /* A0 = (0.5 + b2) / 2 */
+
+ /*
+ * Write coeff into the data structure
+ */
+ pCoefficients->A0 = A0;
+ pCoefficients->B1 = B1;
+ pCoefficients->B2 = B2;
+
+ return(LVPSA_OK);
+}
+#else
LVPSA_RETURN LVPSA_BPDoublePrecCoefs( LVM_UINT16 Fs,
LVPSA_FilterParam_t *pFilterParams,
BP_C32_Coefs_t *pCoefficients)
@@ -666,7 +893,7 @@
return(LVPSA_OK);
}
-
+#endif
/************************************************************************************/
/* */
/* FUNCTION: LVPSA_ClearFilterHistory */
@@ -690,11 +917,17 @@
/* Band Pass filters taps */
pTapAddress = (LVM_INT8 *)pInst->pBP_Taps;
+#ifdef BUILD_FLOAT
+ for(i = 0; i < pInst->nBands * sizeof(Biquad_1I_Order2_FLOAT_Taps_t); i++)
+ {
+ pTapAddress[i] = 0;
+ }
+#else
for(i = 0; i < pInst->nBands * sizeof(Biquad_1I_Order2_Taps_t); i++)
{
pTapAddress[i] = 0;
}
-
+#endif
/* Quasi-peak filters taps */
pTapAddress = (LVM_INT8 *)pInst->pQPD_Taps;
for(i = 0; i < pInst->nBands * sizeof(QPD_Taps_t); i++)
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.c
index 27a4bc3..1c26860 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.c
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.c
@@ -47,7 +47,11 @@
LVPSA_InstancePr_t *pLVPSA_Inst;
LVPSA_RETURN errorCode = LVPSA_OK;
LVM_UINT32 ii;
+#ifndef BUILD_FLOAT
extern LVM_INT16 LVPSA_GainTable[];
+#else
+ extern LVM_FLOAT LVPSA_Float_GainTable[];
+#endif
LVM_UINT32 BufferLength = 0;
/* Ints_Alloc instances, needed for memory alignment management */
@@ -141,19 +145,37 @@
/* Assign the pointers */
-
+#ifndef BUILD_FLOAT
pLVPSA_Inst->pPostGains = InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_UINT16) );
+#else
+ pLVPSA_Inst->pPostGains = InstAlloc_AddMember( &Instance, pInitParams->nBands * \
+ sizeof(LVM_FLOAT) );
+#endif
pLVPSA_Inst->pFiltersParams = InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVPSA_FilterParam_t) );
pLVPSA_Inst->pSpectralDataBufferStart = InstAlloc_AddMember( &Instance, pInitParams->nBands * pLVPSA_Inst->SpectralDataBufferLength * sizeof(LVM_UINT8) );
pLVPSA_Inst->pPreviousPeaks = InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_UINT8) );
pLVPSA_Inst->pBPFiltersPrecision = InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVPSA_BPFilterPrecision_en) );
-
+#ifndef BUILD_FLOAT
pLVPSA_Inst->pBP_Instances = InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(Biquad_Instance_t) );
pLVPSA_Inst->pQPD_States = InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(QPD_State_t) );
+#else
+ pLVPSA_Inst->pBP_Instances = InstAlloc_AddMember( &Coef, pInitParams->nBands * \
+ sizeof(Biquad_FLOAT_Instance_t) );
+ pLVPSA_Inst->pQPD_States = InstAlloc_AddMember( &Coef, pInitParams->nBands * \
+ sizeof(QPD_FLOAT_State_t) );
+#endif
+#ifndef BUILD_FLOAT
pLVPSA_Inst->pBP_Taps = InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(Biquad_1I_Order2_Taps_t) );
pLVPSA_Inst->pQPD_Taps = InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(QPD_Taps_t) );
+#else
+ pLVPSA_Inst->pBP_Taps = InstAlloc_AddMember( &Data,
+ pInitParams->nBands * \
+ sizeof(Biquad_1I_Order2_FLOAT_Taps_t));
+ pLVPSA_Inst->pQPD_Taps = InstAlloc_AddMember( &Data, pInitParams->nBands * \
+ sizeof(QPD_FLOAT_Taps_t) );
+#endif
/* Copy filters parameters in the private instance */
for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
@@ -164,7 +186,12 @@
/* Set Post filters gains*/
for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
{
+#ifndef BUILD_FLOAT
pLVPSA_Inst->pPostGains[ii] =(LVM_UINT16) LVPSA_GainTable[pInitParams->pFiltersParams[ii].PostGain + 15];
+#else
+ pLVPSA_Inst->pPostGains[ii] = LVPSA_Float_GainTable[15 + \
+ pInitParams->pFiltersParams[ii].PostGain];
+#endif
}
pLVPSA_Inst->pSpectralDataBufferWritePointer = pLVPSA_Inst->pSpectralDataBufferStart;
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.c
index 0984b10..06a8f9d 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.c
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.c
@@ -106,7 +106,11 @@
*/
InstAlloc_AddMember( &Instance, sizeof(LVPSA_InstancePr_t) );
+#ifdef BUILD_FLOAT
+ InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_FLOAT) );
+#else
InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_UINT16) );
+#endif
InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVPSA_FilterParam_t) );
{
@@ -134,7 +138,11 @@
/*
* Scratch memory
*/
+#ifndef BUILD_FLOAT
InstAlloc_AddMember( &Scratch, 2 * pInitParams->MaxInputBlockSize * sizeof(LVM_INT16) );
+#else
+ InstAlloc_AddMember( &Scratch, 2 * pInitParams->MaxInputBlockSize * sizeof(LVM_FLOAT) );
+#endif
pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].Size = InstAlloc_GetTotal(&Scratch);
pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].Type = LVPSA_SCRATCH;
pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress = LVM_NULL;
@@ -142,8 +150,13 @@
/*
* Persistent coefficients memory
*/
+#ifndef BUILD_FLOAT
InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(Biquad_Instance_t) );
InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(QPD_State_t) );
+#else
+ InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(Biquad_FLOAT_Instance_t) );
+ InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(QPD_FLOAT_State_t) );
+#endif
pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].Size = InstAlloc_GetTotal(&Coef);
pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].Type = LVPSA_PERSISTENT_COEF;
pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
@@ -151,8 +164,13 @@
/*
* Persistent data memory
*/
+#ifndef BUILD_FLOAT
InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(Biquad_1I_Order2_Taps_t) );
InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(QPD_Taps_t) );
+#else
+ InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(Biquad_1I_Order2_FLOAT_Taps_t) );
+ InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(QPD_FLOAT_Taps_t) );
+#endif
pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].Size = InstAlloc_GetTotal(&Data);
pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].Type = LVPSA_PERSISTENT_DATA;
pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h
index 03522fb..a750bb0 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h
@@ -43,8 +43,11 @@
#define LVPSA_MEMREGION_PERSISTENT_COEF 1 /* Offset to persistent coefficients memory region in memory table */
#define LVPSA_MEMREGION_PERSISTENT_DATA 2 /* Offset to persistent taps memory region in memory table */
#define LVPSA_MEMREGION_SCRATCH 3 /* Offset to scratch memory region in memory table */
-
-#define LVPSA_NR_SUPPORTED_RATE 9 /* From 8000Hz to 48000Hz */
+#ifndef HIGHER_FS
+#define LVPSA_NR_SUPPORTED_RATE 9 /* From 8000Hz to 48000Hz*/
+#else
+#define LVPSA_NR_SUPPORTED_RATE 11 /* From 8000Hz to 192000Hz*/
+#endif
#define LVPSA_NR_SUPPORTED_SPEED 3 /* LOW, MEDIUM, HIGH */
#define LVPSA_MAXBUFFERDURATION 4000 /* Maximum length in ms of the levels buffer */
@@ -93,12 +96,27 @@
LVPSA_MemTab_t MemoryTable;
LVPSA_BPFilterPrecision_en *pBPFiltersPrecision; /* Points a nBands elements array that contains the filter precision for each band */
+#ifndef BUILD_FLOAT
Biquad_Instance_t *pBP_Instances; /* Points a nBands elements array that contains the band pass filter instance for each band */
Biquad_1I_Order2_Taps_t *pBP_Taps; /* Points a nBands elements array that contains the band pass filter taps for each band */
QPD_State_t *pQPD_States; /* Points a nBands elements array that contains the QPD filter instance for each band */
QPD_Taps_t *pQPD_Taps; /* Points a nBands elements array that contains the QPD filter taps for each band */
- LVM_UINT16 *pPostGains; /* Points a nBands elements array that contains the post-filter gains for each band */
+#else
+ Biquad_FLOAT_Instance_t *pBP_Instances;
+ /* Points a nBands elements array that contains the band pass filter taps for each band */
+ Biquad_1I_Order2_FLOAT_Taps_t *pBP_Taps;
+ /* Points a nBands elements array that contains the QPD filter instance for each band */
+ QPD_FLOAT_State_t *pQPD_States;
+ /* Points a nBands elements array that contains the QPD filter taps for each band */
+ QPD_FLOAT_Taps_t *pQPD_Taps;
+#endif
+#ifndef BUILD_FLOAT
+ LVM_UINT16 *pPostGains; /* Points a nBands elements array that contains the post-filter gains for each band */
+#else
+ /* Points a nBands elements array that contains the post-filter gains for each band */
+ LVM_FLOAT *pPostGains;
+#endif
LVPSA_FilterParam_t *pFiltersParams; /* Copy of the filters parameters from the input parameters */
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.c
index 9e29f68..ea5f74a 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.c
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.c
@@ -43,6 +43,96 @@
/* otherwise Error due to bad parameters */
/* */
/************************************************************************************/
+#ifdef BUILD_FLOAT
+LVPSA_RETURN LVPSA_Process ( pLVPSA_Handle_t hInstance,
+ LVM_FLOAT *pLVPSA_InputSamples,
+ LVM_UINT16 InputBlockSize,
+ LVPSA_Time AudioTime )
+
+{
+ LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
+ LVM_FLOAT *pScratch;
+ LVM_INT16 ii;
+ LVM_INT32 AudioTimeInc;
+ extern LVM_UINT32 LVPSA_SampleRateInvTab[];
+ LVM_UINT8 *pWrite_Save; /* Position of the write pointer
+ at the beginning of the process */
+
+ /******************************************************************************
+ CHECK PARAMETERS
+ *******************************************************************************/
+ if(hInstance == LVM_NULL || pLVPSA_InputSamples == LVM_NULL)
+ {
+ return(LVPSA_ERROR_NULLADDRESS);
+ }
+ if(InputBlockSize == 0 || InputBlockSize > pLVPSA_Inst->MaxInputBlockSize)
+ {
+ return(LVPSA_ERROR_INVALIDPARAM);
+ }
+
+ pScratch = (LVM_FLOAT*)pLVPSA_Inst->MemoryTable.Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress;
+ pWrite_Save = pLVPSA_Inst->pSpectralDataBufferWritePointer;
+
+ /******************************************************************************
+ APPLY NEW SETTINGS IF NEEDED
+ *******************************************************************************/
+ if (pLVPSA_Inst->bControlPending == LVM_TRUE)
+ {
+ pLVPSA_Inst->bControlPending = 0;
+ LVPSA_ApplyNewSettings( pLVPSA_Inst);
+ }
+
+ /******************************************************************************
+ PROCESS SAMPLES
+ *******************************************************************************/
+ /* Put samples in range [-0.5;0.5[ for BP filters (see Biquads documentation) */
+ Copy_Float(pLVPSA_InputSamples, pScratch, (LVM_INT16)InputBlockSize);
+ Shift_Sat_Float(-1, pScratch, pScratch, (LVM_INT16)InputBlockSize);
+
+ for (ii = 0; ii < pLVPSA_Inst->nRelevantFilters; ii++)
+ {
+ switch(pLVPSA_Inst->pBPFiltersPrecision[ii])
+ {
+ case LVPSA_SimplePrecisionFilter:
+ BP_1I_D16F16C14_TRC_WRA_01 ( &pLVPSA_Inst->pBP_Instances[ii],
+ pScratch,
+ pScratch + InputBlockSize,
+ (LVM_INT16)InputBlockSize);
+ break;
+
+ case LVPSA_DoublePrecisionFilter:
+ BP_1I_D16F32C30_TRC_WRA_01 ( &pLVPSA_Inst->pBP_Instances[ii],
+ pScratch,
+ pScratch + InputBlockSize,
+ (LVM_INT16)InputBlockSize);
+ break;
+ default:
+ break;
+ }
+
+
+ LVPSA_QPD_Process_Float ( pLVPSA_Inst,
+ pScratch + InputBlockSize,
+ (LVM_INT16)InputBlockSize,
+ ii);
+ }
+
+ /******************************************************************************
+ UPDATE SpectralDataBufferAudioTime
+ *******************************************************************************/
+
+ if(pLVPSA_Inst->pSpectralDataBufferWritePointer != pWrite_Save)
+ {
+ MUL32x32INTO32((AudioTime + (LVM_INT32)((LVM_INT32)pLVPSA_Inst->LocalSamplesCount*1000)),
+ (LVM_INT32)LVPSA_SampleRateInvTab[pLVPSA_Inst->CurrentParams.Fs],
+ AudioTimeInc,
+ LVPSA_FsInvertShift)
+ pLVPSA_Inst->SpectralDataBufferAudioTime = AudioTime + AudioTimeInc;
+ }
+
+ return(LVPSA_OK);
+}
+#else
LVPSA_RETURN LVPSA_Process ( pLVPSA_Handle_t hInstance,
LVM_INT16 *pLVPSA_InputSamples,
LVM_UINT16 InputBlockSize,
@@ -130,7 +220,7 @@
return(LVPSA_OK);
}
-
+#endif
/************************************************************************************/
/* */
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD.h b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD.h
index 836bfd7..99d844b 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD.h
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD.h
@@ -31,6 +31,15 @@
LVM_INT32 Coefs[2]; /* pointer to the filter coefficients */
}QPD_State_t, *pQPD_State_t;
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ /* pointer to the delayed samples (data of 32 bits) */
+ LVM_FLOAT *pDelay;
+ LVM_FLOAT Coefs[2]; /* pointer to the filter coefficients */
+}QPD_FLOAT_State_t, *pQPD_FLOAT_State_t;
+#endif
+
typedef struct
{
LVM_INT32 KP; /*should store a0*/
@@ -38,12 +47,30 @@
} QPD_C32_Coefs, *PQPD_C32_Coefs;
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVM_FLOAT KP; /*should store a0*/
+ LVM_FLOAT KM; /*should store b2*/
+
+} QPD_FLOAT_Coefs, *PQPD_FLOAT_Coefs;
+#endif
+
+
typedef struct
{
LVM_INT32 Storage[1];
} QPD_Taps_t, *pQPD_Taps_t;
+#ifdef BUILD_FLOAT
+typedef struct
+{
+ LVM_FLOAT Storage[1];
+
+} QPD_FLOAT_Taps_t, *pQPD_FLOAT_Taps_t;
+
+#endif
/************************************************************************************/
/* */
/* FUNCTION: LVPSA_QPD_Process */
@@ -62,6 +89,12 @@
LVM_INT16 numSamples,
LVM_INT16 BandIndex);
+#ifdef BUILD_FLOAT
+void LVPSA_QPD_Process_Float ( void *hInstance,
+ LVM_FLOAT *pInSamps,
+ LVM_INT16 numSamples,
+ LVM_INT16 BandIndex);
+#endif
/************************************************************************************/
/* */
/* FUNCTION: LVPSA_QPD_Init */
@@ -80,8 +113,12 @@
void LVPSA_QPD_Init ( QPD_State_t *pInstance,
QPD_Taps_t *pTaps,
QPD_C32_Coefs *pCoef );
+#ifdef BUILD_FLOAT
-
+void LVPSA_QPD_Init_Float ( QPD_FLOAT_State_t *pInstance,
+ QPD_FLOAT_Taps_t *pTaps,
+ QPD_FLOAT_Coefs *pCoef );
+#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Init.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Init.c
index 50e0a80..2cc32ab 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Init.c
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Init.c
@@ -40,3 +40,14 @@
pQPD_State->Coefs[0] = pCoef->KP;
pQPD_State->Coefs[1] = pCoef->KM;
}
+
+#ifdef BUILD_FLOAT
+void LVPSA_QPD_Init_Float ( pQPD_FLOAT_State_t pQPD_State,
+ QPD_FLOAT_Taps_t *pTaps,
+ QPD_FLOAT_Coefs *pCoef )
+{
+ pQPD_State->pDelay = pTaps->Storage;
+ pQPD_State->Coefs[0] = ((LVM_FLOAT)pCoef->KP);
+ pQPD_State->Coefs[1] = ((LVM_FLOAT)pCoef->KM);
+}
+#endif
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Process.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Process.c
index 67197c1..e233172 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Process.c
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Process.c
@@ -35,12 +35,16 @@
/* */
/************************************************************************************/
void LVPSA_QPD_WritePeak( pLVPSA_InstancePr_t pLVPSA_Inst,
- LVM_UINT8 **ppWrite,
- LVM_INT16 BandIndex,
- LVM_INT16 Value );
+ LVM_UINT8 **ppWrite,
+ LVM_INT16 BandIndex,
+ LVM_INT16 Value );
-
-
+#ifdef BUILD_FLOAT
+void LVPSA_QPD_WritePeak_Float( pLVPSA_InstancePr_t pLVPSA_Inst,
+ LVM_UINT8 **ppWrite,
+ LVM_INT16 BandIndex,
+ LVM_FLOAT Value );
+#endif
/************************************************************************************/
/* */
/* FUNCTION: LVPSA_QPD_Process */
@@ -54,6 +58,7 @@
/* RETURNS: void */
/* */
/************************************************************************************/
+#ifndef BUILD_FLOAT
void LVPSA_QPD_Process ( void *hInstance,
LVM_INT16 *pInSamps,
LVM_INT16 numSamples,
@@ -173,7 +178,131 @@
pLVPSA_Inst->DownSamplingCount = (LVM_UINT16)(-ii);
}
}
+#else
+void LVPSA_QPD_Process_Float ( void *hInstance,
+ LVM_FLOAT *pInSamps,
+ LVM_INT16 numSamples,
+ LVM_INT16 BandIndex)
+{
+ /******************************************************************************
+ PARAMETERS
+ *******************************************************************************/
+ LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
+ QPD_FLOAT_State_t *pQPDState = (QPD_FLOAT_State_t*)&pLVPSA_Inst->pQPD_States[BandIndex];
+
+ /* Pointer to taps */
+ LVM_FLOAT* pDelay = pQPDState->pDelay;
+
+ /* Parameters needed during quasi peak calculations */
+ LVM_FLOAT X0;
+ LVM_FLOAT temp,temp2;
+ LVM_FLOAT accu;
+ LVM_FLOAT Xg0;
+ LVM_FLOAT D0;
+ LVM_FLOAT V0 = (LVM_FLOAT)(*pDelay);
+
+ /* Filter's coef */
+ LVM_FLOAT Kp = ((LVM_FLOAT)(pQPDState->Coefs[0]));
+ LVM_FLOAT Km = ((LVM_FLOAT)(pQPDState->Coefs[1]));
+
+ LVM_INT16 ii = numSamples;
+
+ LVM_UINT8 *pWrite = pLVPSA_Inst->pSpectralDataBufferWritePointer;
+ LVM_INT32 BufferUpdateSamplesCount = pLVPSA_Inst->BufferUpdateSamplesCount;
+ LVM_UINT16 DownSamplingFactor = pLVPSA_Inst->DownSamplingFactor;
+
+ /******************************************************************************
+ INITIALIZATION
+ *******************************************************************************/
+ /* Correct the pointer to take the first down sampled signal sample */
+ pInSamps += pLVPSA_Inst->DownSamplingCount;
+ /* Correct also the number of samples */
+ ii = (LVM_INT16)(ii - (LVM_INT16)pLVPSA_Inst->DownSamplingCount);
+
+ while (ii > 0)
+ {
+ /* Apply post gain */
+ /* - 1 to compensate scaling in process function*/
+ X0 = (*pInSamps) * pLVPSA_Inst->pPostGains[BandIndex];
+ pInSamps = pInSamps + DownSamplingFactor;
+
+ /* Saturate and take absolute value */
+ if(X0 < 0.0f)
+ X0 = -X0;
+ if (X0 > 1.0f)
+ Xg0 = 1.0f;
+ else
+ Xg0 =X0;
+
+
+ /* Quasi peak filter calculation */
+ D0 = Xg0 - V0;
+
+ temp2 = D0;
+
+ accu = temp2 * Kp;
+ D0 = D0 / 2.0f;
+ if (D0 < 0.0f){
+ D0 = -D0;
+ }
+
+ temp2 = D0;
+
+ temp = D0 * Km;
+ accu += temp + Xg0;
+
+ if (accu > 1.0f)
+ accu = 1.0f;
+ else if(accu < 0.0f)
+ accu = 0.0f;
+
+ V0 = accu;
+
+ if(((pLVPSA_Inst->nSamplesBufferUpdate - BufferUpdateSamplesCount) < DownSamplingFactor))
+ {
+ LVPSA_QPD_WritePeak_Float( pLVPSA_Inst,
+ &pWrite,
+ BandIndex,
+ V0);
+
+ BufferUpdateSamplesCount -= pLVPSA_Inst->nSamplesBufferUpdate;
+ pLVPSA_Inst->LocalSamplesCount = (LVM_UINT16)(numSamples - ii);
+ }
+ BufferUpdateSamplesCount += DownSamplingFactor;
+
+ ii = (LVM_INT16)(ii - DownSamplingFactor);
+
+ }
+
+ /* Store last taps in memory */
+ *pDelay = V0;
+
+ /* If this is the last call to the function after last band processing,
+ update the parameters. */
+ if(BandIndex == (pLVPSA_Inst->nRelevantFilters - 1))
+ {
+ pLVPSA_Inst->pSpectralDataBufferWritePointer = pWrite;
+ /* Adjustment for 11025Hz input, 220,5 is normally
+ the exact number of samples for 20ms.*/
+ if((pLVPSA_Inst->pSpectralDataBufferWritePointer != pWrite)&&
+ (pLVPSA_Inst->CurrentParams.Fs == LVM_FS_11025))
+ {
+ if(pLVPSA_Inst->nSamplesBufferUpdate == 220)
+ {
+ pLVPSA_Inst->nSamplesBufferUpdate = 221;
+ }
+ else
+ {
+ pLVPSA_Inst->nSamplesBufferUpdate = 220;
+ }
+ }
+ pLVPSA_Inst->pSpectralDataBufferWritePointer = pWrite;
+ pLVPSA_Inst->BufferUpdateSamplesCount = BufferUpdateSamplesCount;
+ pLVPSA_Inst->DownSamplingCount = (LVM_UINT16)(-ii);
+ }
+}
+#endif
/************************************************************************************/
/* */
/* FUNCTION: LVPSA_QPD_WritePeak */
@@ -209,4 +338,23 @@
*ppWrite = pWrite;
}
+#ifdef BUILD_FLOAT
+void LVPSA_QPD_WritePeak_Float( pLVPSA_InstancePr_t pLVPSA_Inst,
+ LVM_UINT8 **ppWrite,
+ LVM_INT16 BandIndex,
+ LVM_FLOAT Value )
+{
+ LVM_UINT8 *pWrite = *ppWrite;
+ /* Write the value and update the write pointer */
+ *(pWrite + BandIndex) = (LVM_UINT8)(Value * 256);
+ pWrite += pLVPSA_Inst->nBands;
+ if (pWrite == (pLVPSA_Inst->pSpectralDataBufferStart + pLVPSA_Inst->nBands * \
+ pLVPSA_Inst->SpectralDataBufferLength))
+ {
+ pWrite = pLVPSA_Inst->pSpectralDataBufferStart;
+ }
+
+ *ppWrite = pWrite;
+}
+#endif
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Tables.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Tables.c
index 21a5d8d..1287503 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Tables.c
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Tables.c
@@ -34,6 +34,7 @@
* Sample rate table for converting between the enumerated type and the actual
* frequency
*/
+#ifndef HIGHER_FS
const LVM_UINT16 LVPSA_SampleRateTab[] = { 8000, /* 8kS/s */
11025,
12000,
@@ -43,6 +44,19 @@
32000,
44100,
48000}; /* 48kS/s */
+#else
+const LVM_UINT32 LVPSA_SampleRateTab[] = { 8000, /* 8kS/s */
+ 11025,
+ 12000,
+ 16000,
+ 22050,
+ 24000,
+ 32000,
+ 44100,
+ 48000,
+ 96000,
+ 192000}; /* 192kS/s */
+#endif
/************************************************************************************/
/* */
@@ -62,7 +76,12 @@
89478,
67109,
48696,
- 44739}; /* 48kS/s */
+ 44739
+#ifdef HIGHER_FS
+ ,22369
+ ,11185 /* 192kS/s */
+#endif
+ };
@@ -84,7 +103,12 @@
480,
640,
882,
- 960}; /* 48kS/s */
+ 960
+#ifdef HIGHER_FS
+ ,1920
+ ,3840 /* 192kS/s */
+#endif
+ };
/************************************************************************************/
/* */
/* Down sampling factors */
@@ -102,7 +126,12 @@
16, /* 24000 S/s */
21, /* 32000 S/s */
30, /* 44100 S/s */
- 32}; /* 48000 S/s */
+ 32 /* 48000 S/s */
+#ifdef HIGHER_FS
+ ,64 /* 96000 S/s */
+ ,128 /*192000 S/s */
+#endif
+ };
/************************************************************************************/
@@ -122,8 +151,30 @@
8785,
6588,
4781,
- 4392}; /* 48kS/s */
+ 4392
+#ifdef HIGHER_FS
+ ,2196
+ ,1098 /* 192kS/s */
+#endif
+ };
+#ifdef BUILD_FLOAT
+const LVM_FLOAT LVPSA_Float_TwoPiOnFsTable[] = { 0.8042847f, /* 8kS/s */
+ 0.5836054f,
+ 0.5361796f,
+ 0.4021423f,
+ 0.2917874f,
+ 0.2681051f,
+ 0.2010559f,
+ 0.1459089f,
+ 0.1340372f
+#ifdef HIGHER_FS
+ ,0.0670186f
+ ,0.0335093f /* 192kS/s */
+#endif
+ };
+
+#endif
/*
* Gain table
*/
@@ -159,6 +210,39 @@
10264,
11576}; /* +15dB gain */
+#ifdef BUILD_FLOAT
+const LVM_FLOAT LVPSA_Float_GainTable[]={ 0.177734375f, /* -15dB gain */
+ 0.199218750f,
+ 0.223632812f,
+ 0.250976562f,
+ 0.281738281f,
+ 0.315917968f,
+ 0.354492187f,
+ 0.397949218f,
+ 0.446289062f,
+ 0.500976562f,
+ 0.562011718f,
+ 0.630859375f,
+ 0.707519531f,
+ 0.793945312f,
+ 0.891113281f,
+ 1.000000000f, /* 0dB gain */
+ 1.121582031f,
+ 1.258789062f,
+ 1.412109375f,
+ 1.584472656f,
+ 1.777832031f,
+ 2.000000000f,
+ 2.238281250f,
+ 2.511718750f,
+ 2.818359375f,
+ 3.162109375f,
+ 3.547851562f,
+ 3.980957031f,
+ 4.466796875f,
+ 5.011718750f,
+ 5.652343750f}; /* +15dB gain */
+#endif
/************************************************************************************/
/* */
/* Cosone polynomial coefficients */
@@ -181,7 +265,15 @@
-2671, /* a3 */
23730, /* a4 */
-9490}; /* a5 */
-
+#ifdef BUILD_FLOAT
+const LVM_FLOAT LVPSA_Float_CosCoef[] = { 3, /* Shifts */
+ 0.1250038f, /* a0 */
+ -0.0010986f, /* a1 */
+ -0.6019775f, /* a2 */
+ -0.0815149f, /* a3 */
+ 0.7242042f, /* a4 */
+ -0.2896206f}; /* a5 */
+#endif
/*
* Coefficients for calculating the cosine error with the equation:
*
@@ -201,7 +293,13 @@
-6, /* a1 */
16586, /* a2 */
-44}; /* a3 */
-
+#ifdef BUILD_FLOAT
+const LVM_FLOAT LVPSA_Float_DPCosCoef[] = {1.0f, /* Shifts */
+ 0.0f, /* a0 */
+ -0.00008311f, /* a1 */
+ 0.50617999f, /* a2 */
+ -0.00134281f}; /* a3 */
+#endif
/************************************************************************************/
/* */
/* Quasi peak filter coefficients table */
@@ -239,3 +337,54 @@
{0xA375B2C6,0x1E943BBC},
{0xA2E1E950,0x1E2A532E}}; /* 48kS/s */
+#ifdef BUILD_FLOAT
+const QPD_FLOAT_Coefs LVPSA_QPD_Float_Coefs[] = {
+
+ /* 8kS/s */ /* LVPSA_SPEED_LOW */
+ {-0.9936831989325583f,0.0062135565094650f},
+ {-0.9935833332128823f,0.0063115493394434f},
+ {-0.9932638457976282f,0.0066249934025109f},
+ {-0.9936831989325583f,0.0062135565094650f},
+ {-0.9931269618682563f,0.0067592649720609f},
+ {-0.9932638457976282f,0.0066249934025109f},
+ {-0.9933686633594334f,0.0065221670083702f},
+ {-0.9931269618682563f,0.0067592649720609f},
+ /* 48kS/s */
+ {-0.9932638457976282f,0.0066249934025109f},
+#ifdef HIGHER_FS
+ {-0.9932638457976282f,0.0066249934025109f},
+ {-0.9932638457976282f,0.0066249934025109f},
+#endif
+ /* 8kS/s */ /* LVPSA_SPEED_MEDIUM */
+ {-0.9568079425953329f,0.0418742666952312f},
+ {-0.9561413046903908f,0.0425090822391212f},
+ {-0.9540119562298059f,0.0445343819446862f},
+ {-0.9568079425953329f,0.0418742666952312f},
+ {-0.9531011912040412f,0.0453995238058269f},
+ {-0.9540119562298059f,0.0445343819446862f},
+ {-0.9547099955379963f,0.0438708555884659f},
+ //{0x8600C7B9,0x05CFA6CF},
+ {-0.9531011912040412f,0.0453995238058269f},
+ /* 48kS/s */
+ {-0.9540119562298059f,0.0445343819446862f},
+#ifdef HIGHER_FS
+ {-0.9540119562298059f,0.0445343819446862f},
+ {-0.9540119562298059f,0.0445343819446862f},
+#endif
+ /* 8kS/s */ /* LVPSA_SPEED_HIGH */
+ {-0.7415186790749431f,0.2254409026354551f},
+ {-0.7381451204419136f,0.2279209652915597f},
+ {-0.7274807319045067f,0.2356666540727019f},
+ {-0.7415186790749431f,0.2254409026354551f},
+ {-0.7229706319049001f,0.2388987224549055f},
+ {-0.7274807319045067f,0.2356666540727019f},
+ {-0.7309581353329122f,0.2331568226218224f},
+ {-0.7229706319049001f,0.2388987224549055f},
+ /* 48kS/s */
+ {-0.7274807319045067f,0.2356666540727019f}
+#ifdef HIGHER_FS
+ ,{-0.7274807319045067f,0.2356666540727019f}
+ ,{-0.7274807319045067f,0.2356666540727019f}
+#endif
+ };
+#endif
diff --git a/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h b/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
index 0d62274..e75695e 100644
--- a/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
+++ b/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
@@ -374,12 +374,17 @@
/* NOTES: */
/* */
/****************************************************************************************/
-
+#ifdef BUILD_FLOAT
+LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples);
+#else
LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 *pOutData,
LVM_UINT16 NumSamples);
-
+#endif
#ifdef __cplusplus
}
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.c
index 3e48c7e..29e3c9e 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.c
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.c
@@ -70,11 +70,17 @@
{
LVM_UINT16 Offset;
+#ifndef BUILD_FLOAT
LVM_UINT32 Gain;
+ LVM_INT32 Current;
+#else
+ LVM_FLOAT Gain;
+ LVM_FLOAT Current;
+#endif
LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
LVCS_BypassMix_t *pConfig = (LVCS_BypassMix_t *)&pInstance->BypassMix;
const Gain_t *pOutputGainTable;
- LVM_INT32 Current;
+
/*
@@ -85,7 +91,11 @@
&& (pInstance->MSTarget1 != 0x7FFF) /* this indicates an off->on transtion */
)
{
+#ifndef BUILD_FLOAT
pInstance->TransitionGain = pParams->EffectLevel;
+#else
+ pInstance->TransitionGain = ((LVM_FLOAT)pParams->EffectLevel / 32767);
+#endif
}
else
{
@@ -102,23 +112,46 @@
/*
* Setup the mixer gain for the processed path
*/
+#ifndef BUILD_FLOAT
Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
+#else
+ Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
+#endif
pConfig->Mixer_Instance.MixerStream[0].CallbackParam = 0;
pConfig->Mixer_Instance.MixerStream[0].pCallbackHandle = LVM_NULL;
pConfig->Mixer_Instance.MixerStream[0].pCallBack = LVM_NULL;
pConfig->Mixer_Instance.MixerStream[0].CallbackSet=1;
+
+#ifndef BUILD_FLOAT
Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0],(LVM_INT32)(Gain >> 15),Current);
LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
+#else
+ Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
+ LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0], (LVM_FLOAT)(Gain), Current);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
+ LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
+#endif
+
/*
* Setup the mixer gain for the unprocessed path
*/
+#ifndef BUILD_FLOAT
Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * (0x7FFF - pInstance->TransitionGain));
Gain = (LVM_UINT32)pOutputGainTable[Offset].UnprocLoss * (Gain >> 15);
Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1],(LVM_INT32)(Gain >> 15),Current);
LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
+#else
+ Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss * (1.0 - \
+ (LVM_FLOAT)pInstance->TransitionGain));
+ Gain = (LVM_FLOAT)pOutputGainTable[Offset].UnprocLoss * Gain;
+ Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
+ LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1], (LVM_FLOAT)(Gain), Current);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
+ LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
+#endif
pConfig->Mixer_Instance.MixerStream[1].CallbackParam = 0;
pConfig->Mixer_Instance.MixerStream[1].pCallbackHandle = hInstance;
pConfig->Mixer_Instance.MixerStream[1].CallbackSet=1;
@@ -134,7 +167,7 @@
* Correct gain for the effect level
*/
{
-
+#ifndef BUILD_FLOAT
LVM_INT16 GainCorrect;
LVM_INT32 Gain1;
LVM_INT32 Gain2;
@@ -172,6 +205,43 @@
LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2>>16);
LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
+#else
+ LVM_FLOAT GainCorrect;
+ LVM_FLOAT Gain1;
+ LVM_FLOAT Gain2;
+
+ Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]);
+ Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]);
+ /*
+ * Calculate the gain correction
+ */
+ if (pInstance->Params.CompressorMode == LVM_MODE_ON)
+ {
+ GainCorrect = (LVM_FLOAT)( pInstance->VolCorrect.GainMin
+ - (((LVM_FLOAT)pInstance->VolCorrect.GainMin * \
+ ((LVM_FLOAT)pInstance->TransitionGain)))
+ + (((LVM_FLOAT)pInstance->VolCorrect.GainFull * \
+ ((LVM_FLOAT)pInstance->TransitionGain))));
+
+ /*
+ * Apply the gain correction
+ */
+ Gain1 = (Gain1 * GainCorrect);
+ Gain2 = (Gain2 * GainCorrect);
+
+ }
+
+ /*
+ * Set the gain values
+ */
+ pConfig->Output_Shift = pConfig->Output_Shift;
+ LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
+ LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
+ LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
+ LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
+#endif
}
return(LVCS_SUCCESS);
@@ -206,9 +276,15 @@
/************************************************************************************/
LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t hInstance,
+#ifndef BUILD_FLOAT
const LVM_INT16 *pProcessed,
const LVM_INT16 *pUnprocessed,
LVM_INT16 *pOutData,
+#else
+ const LVM_FLOAT *pProcessed,
+ const LVM_FLOAT *pUnprocessed,
+ LVM_FLOAT *pOutData,
+#endif
LVM_UINT16 NumSamples)
{
@@ -223,6 +299,7 @@
/*
* Apply the bypass mix
*/
+#ifndef BUILD_FLOAT
LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance,
pProcessed,
(LVM_INT16 *) pUnprocessed,
@@ -236,6 +313,20 @@
(LVM_INT16*)pOutData,
(LVM_INT16*)pOutData,
(LVM_INT16)(2*NumSamples)); /* Left and right*/
+#else
+ LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance,
+ pProcessed,
+ (LVM_FLOAT *) pUnprocessed,
+ pOutData,
+ (LVM_INT16)(2 * NumSamples));
+ /*
+ * Apply output gain correction shift
+ */
+ Shift_Sat_Float((LVM_INT16)pConfig->Output_Shift,
+ (LVM_FLOAT*)pOutData,
+ (LVM_FLOAT*)pOutData,
+ (LVM_INT16)(2 * NumSamples)); /* Left and right*/
+#endif
}
return(LVCS_SUCCESS);
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.h
index d1ef70a..f69ba38 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.h
@@ -42,12 +42,16 @@
typedef struct
{
/* Mixer settings */
+#ifdef BUILD_FLOAT
+ LVMixer3_2St_FLOAT_st Mixer_Instance; /* Mixer instance */
+#else
LVMixer3_2St_st Mixer_Instance; /* Mixer instance */
+#endif
LVM_UINT16 Output_Shift; /* Correcting gain output shift */
} LVCS_BypassMix_t;
-
+#ifndef BUILD_FLOAT
/* Output gain type */
typedef struct
{
@@ -56,8 +60,15 @@
LVM_UINT16 Loss; /* Loss required */
LVM_UINT16 UnprocLoss; /* Unprocessed path loss */
} Gain_t;
-
-
+#else
+typedef struct
+{
+ /* Output gain settings, Gain = (Loss/32768) * 2^Shift */
+ LVM_UINT16 Shift; /* Left shifts required */
+ LVM_FLOAT Loss; /* Loss required */
+ LVM_FLOAT UnprocLoss; /* Unprocessed path loss */
+} Gain_t;
+#endif
/************************************************************************************/
/* */
/* Function prototypes */
@@ -67,13 +78,19 @@
LVCS_ReturnStatus_en LVCS_BypassMixInit(LVCS_Handle_t hInstance,
LVCS_Params_t *pParams);
-
+#ifndef BUILD_FLOAT
LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t hInstance,
const LVM_INT16 *pProcessed,
const LVM_INT16 *unProcessed,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples);
-
+ LVM_INT16 *pOutData,
+ LVM_UINT16 NumSamples);
+#else
+LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t hInstance,
+ const LVM_FLOAT *pProcessed,
+ const LVM_FLOAT *unProcessed,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples);
+#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.c
index ce6d410..3bf6ec6 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.c
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.c
@@ -120,11 +120,13 @@
pInstance->VolCorrect = pLVCS_VolCorrectTable[Offset];
pInstance->CompressGain = pInstance->VolCorrect.CompMin;
-
+#ifdef BUILD_FLOAT
+ LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[0], 0, 0);
+#else
LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[0],0,0);
-
-
+#endif
{
+#ifndef BUILD_FLOAT
LVM_UINT32 Gain;
const Gain_t *pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * LVM_MAXINT_16);
@@ -140,7 +142,23 @@
LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMix.Mixer_Instance.MixerStream[1],
LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
+#else
+ LVM_FLOAT Gain;
+ const Gain_t *pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
+ Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss);
+ Gain = (LVM_FLOAT)pOutputGainTable[Offset].UnprocLoss * (Gain);
+ /*
+ * Apply the gain correction
+ */
+ Gain = (Gain * pInstance->VolCorrect.GainMin);
+
+ LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[1], 0, Gain);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMix.Mixer_Instance.MixerStream[0],
+ LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMix.Mixer_Instance.MixerStream[1],
+ LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
+#endif
}
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.c
index 25b0d86..ec5312e 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.c
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.c
@@ -53,7 +53,72 @@
/* NOTES: */
/* */
/************************************************************************************/
+#ifdef BUILD_FLOAT
+LVCS_ReturnStatus_en LVCS_EqualiserInit(LVCS_Handle_t hInstance,
+ LVCS_Params_t *pParams)
+{
+ LVM_UINT16 Offset;
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_Equaliser_t *pConfig = (LVCS_Equaliser_t *)&pInstance->Equaliser;
+ LVCS_Data_t *pData;
+ LVCS_Coefficient_t *pCoefficients;
+ BQ_FLOAT_Coefs_t Coeffs;
+ const BiquadA012B12CoefsSP_t *pEqualiserCoefTable;
+
+ pData = (LVCS_Data_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
+
+ pCoefficients = (LVCS_Coefficient_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+ /*
+ * If the sample rate changes re-initialise the filters
+ */
+ if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
+ (pInstance->Params.SpeakerType != pParams->SpeakerType))
+ {
+ /*
+ * Setup the filter coefficients and clear the history
+ */
+ Offset = (LVM_UINT16)(pParams->SampleRate + (pParams->SpeakerType * (1 + LVM_FS_48000)));
+ pEqualiserCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_EqualiserCoefTable[0];
+
+ /* Left and right filters */
+ /* Convert incoming coefficients to the required format/ordering */
+ Coeffs.A0 = (LVM_FLOAT) pEqualiserCoefTable[Offset].A0;
+ Coeffs.A1 = (LVM_FLOAT) pEqualiserCoefTable[Offset].A1;
+ Coeffs.A2 = (LVM_FLOAT) pEqualiserCoefTable[Offset].A2;
+ Coeffs.B1 = (LVM_FLOAT)-pEqualiserCoefTable[Offset].B1;
+ Coeffs.B2 = (LVM_FLOAT)-pEqualiserCoefTable[Offset].B2;
+
+ LoadConst_Float((LVM_INT16)0, /* Value */
+ (void *)&pData->EqualiserBiquadTaps, /* Destination Cast to void:\
+ no dereferencing in function*/
+ /* Number of words */
+ (LVM_UINT16)(sizeof(pData->EqualiserBiquadTaps) / sizeof(LVM_FLOAT)));
+
+ BQ_2I_D16F32Css_TRC_WRA_01_Init(&pCoefficients->EqualiserBiquadInstance,
+ &pData->EqualiserBiquadTaps,
+ &Coeffs);
+
+ /* Callbacks */
+ switch(pEqualiserCoefTable[Offset].Scale)
+ {
+ case 13:
+ pConfig->pBiquadCallBack = BQ_2I_D16F32C13_TRC_WRA_01;
+ break;
+ case 14:
+ pConfig->pBiquadCallBack = BQ_2I_D16F32C14_TRC_WRA_01;
+ break;
+ case 15:
+ pConfig->pBiquadCallBack = BQ_2I_D16F32C15_TRC_WRA_01;
+ break;
+ }
+ }
+
+ return(LVCS_SUCCESS);
+}
+#else
LVCS_ReturnStatus_en LVCS_EqualiserInit(LVCS_Handle_t hInstance,
LVCS_Params_t *pParams)
{
@@ -112,7 +177,7 @@
return(LVCS_SUCCESS);
}
-
+#endif
/************************************************************************************/
/* */
/* FUNCTION: LVCS_Equaliser */
@@ -132,7 +197,37 @@
/* 1. Always processes in place. */
/* */
/************************************************************************************/
+#ifdef BUILD_FLOAT
+LVCS_ReturnStatus_en LVCS_Equaliser(LVCS_Handle_t hInstance,
+ LVM_FLOAT *pInputOutput,
+ LVM_UINT16 NumSamples)
+{
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_Equaliser_t *pConfig = (LVCS_Equaliser_t *)&pInstance->Equaliser;
+ LVCS_Coefficient_t *pCoefficients;
+
+
+ pCoefficients = (LVCS_Coefficient_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+
+
+ /*
+ * Check if the equaliser is required
+ */
+ if ((pInstance->Params.OperatingMode & LVCS_EQUALISERSWITCH) != 0)
+ {
+ /* Apply filter to the left and right channels */
+ (pConfig->pBiquadCallBack)((Biquad_FLOAT_Instance_t*) \
+ &pCoefficients->EqualiserBiquadInstance,
+ (LVM_FLOAT *)pInputOutput,
+ (LVM_FLOAT *)pInputOutput,
+ (LVM_INT16)NumSamples);
+ }
+
+ return(LVCS_SUCCESS);
+}
+#else
LVCS_ReturnStatus_en LVCS_Equaliser(LVCS_Handle_t hInstance,
LVM_INT16 *pInputOutput,
LVM_UINT16 NumSamples)
@@ -157,4 +252,4 @@
return(LVCS_SUCCESS);
}
-
+#endif
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.h
index cf96f5b..0e756e7 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.h
@@ -32,8 +32,11 @@
/* Equaliser structure */
typedef struct
{
+#ifndef BUILD_FLOAT
void (*pBiquadCallBack) (Biquad_Instance_t*, LVM_INT16*, LVM_INT16*, LVM_INT16);
-
+#else
+ void (*pBiquadCallBack) (Biquad_FLOAT_Instance_t*, LVM_FLOAT*, LVM_FLOAT*, LVM_INT16);
+#endif
} LVCS_Equaliser_t;
@@ -45,12 +48,15 @@
LVCS_ReturnStatus_en LVCS_EqualiserInit(LVCS_Handle_t hInstance,
LVCS_Params_t *pParams);
-
+#ifndef BUILD_FLOAT
LVCS_ReturnStatus_en LVCS_Equaliser(LVCS_Handle_t hInstance,
LVM_INT16 *pInputOutput,
LVM_UINT16 NumSamples);
-
-
+#else
+LVCS_ReturnStatus_en LVCS_Equaliser(LVCS_Handle_t hInstance,
+ LVM_FLOAT *pInputOutput,
+ LVM_UINT16 NumSamples);
+#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Headphone_Coeffs.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Headphone_Coeffs.h
index 3e640cb..4f5221a 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Headphone_Coeffs.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Headphone_Coeffs.h
@@ -24,7 +24,463 @@
/* The Stereo Enhancer */
/* */
/************************************************************************************/
+#ifdef BUILD_FLOAT
+/* Stereo Enhancer coefficients for 8000 Hz sample rate, scaled with 0.161258 */
+#define CS_MIDDLE_8000_A0 0.227720
+#define CS_MIDDLE_8000_A1 -0.215125
+#define CS_MIDDLE_8000_A2 0.000000
+#define CS_MIDDLE_8000_B1 -0.921899
+#define CS_MIDDLE_8000_B2 0.000000
+#define CS_MIDDLE_8000_SCALE 15
+#define CS_SIDE_8000_A0 0.611441
+#define CS_SIDE_8000_A1 -0.380344
+#define CS_SIDE_8000_A2 -0.231097
+#define CS_SIDE_8000_B1 -0.622470
+#define CS_SIDE_8000_B2 -0.130759
+#define CS_SIDE_8000_SCALE 15
+/* Stereo Enhancer coefficients for 11025Hz sample rate, scaled with 0.162943 */
+#define CS_MIDDLE_11025_A0 0.230838
+#define CS_MIDDLE_11025_A1 -0.221559
+#define CS_MIDDLE_11025_A2 0.000000
+#define CS_MIDDLE_11025_B1 -0.943056
+#define CS_MIDDLE_11025_B2 0.000000
+#define CS_MIDDLE_11025_SCALE 15
+#define CS_SIDE_11025_A0 0.557372
+#define CS_SIDE_11025_A1 -0.391490
+#define CS_SIDE_11025_A2 -0.165881
+#define CS_SIDE_11025_B1 -0.880608
+#define CS_SIDE_11025_B2 0.032397
+#define CS_SIDE_11025_SCALE 15
+
+/* Stereo Enhancer coefficients for 12000Hz sample rate, scaled with 0.162191 */
+#define CS_MIDDLE_12000_A0 0.229932
+#define CS_MIDDLE_12000_A1 -0.221436
+#define CS_MIDDLE_12000_A2 0.000000
+#define CS_MIDDLE_12000_B1 -0.947616
+#define CS_MIDDLE_12000_B2 0.000000
+#define CS_MIDDLE_12000_SCALE 15
+#define CS_SIDE_12000_A0 0.558398
+#define CS_SIDE_12000_A1 -0.392211
+#define CS_SIDE_12000_A2 -0.166187
+#define CS_SIDE_12000_B1 -0.892550
+#define CS_SIDE_12000_B2 0.032856
+#define CS_SIDE_12000_SCALE 15
+
+/* Stereo Enhancer coefficients for 16000Hz sample rate, scaled with 0.162371 */
+#define CS_MIDDLE_16000_A0 0.230638
+#define CS_MIDDLE_16000_A1 -0.224232
+#define CS_MIDDLE_16000_A2 0.000000
+#define CS_MIDDLE_16000_B1 -0.960550
+#define CS_MIDDLE_16000_B2 0.000000
+#define CS_MIDDLE_16000_SCALE 15
+#define CS_SIDE_16000_A0 0.499695
+#define CS_SIDE_16000_A1 -0.355543
+#define CS_SIDE_16000_A2 -0.144152
+#define CS_SIDE_16000_B1 -1.050788
+#define CS_SIDE_16000_B2 0.144104
+#define CS_SIDE_16000_SCALE 14
+
+/* Stereo Enhancer coefficients for 22050Hz sample rate, scaled with 0.160781 */
+#define CS_MIDDLE_22050_A0 0.228749
+#define CS_MIDDLE_22050_A1 -0.224128
+#define CS_MIDDLE_22050_A2 0.000000
+#define CS_MIDDLE_22050_B1 -0.971262
+#define CS_MIDDLE_22050_B2 0.000000
+#define CS_MIDDLE_22050_SCALE 15
+#define CS_SIDE_22050_A0 0.440112
+#define CS_SIDE_22050_A1 -0.261096
+#define CS_SIDE_22050_A2 -0.179016
+#define CS_SIDE_22050_B1 -1.116786
+#define CS_SIDE_22050_B2 0.182507
+#define CS_SIDE_22050_SCALE 14
+
+/* Stereo Enhancer coefficients for 24000Hz sample rate, scaled with 0.161882 */
+#define CS_MIDDLE_24000_A0 0.230395
+#define CS_MIDDLE_24000_A1 -0.226117
+#define CS_MIDDLE_24000_A2 0.000000
+#define CS_MIDDLE_24000_B1 -0.973573
+#define CS_MIDDLE_24000_B2 0.000000
+#define CS_MIDDLE_24000_SCALE 15
+#define CS_SIDE_24000_A0 0.414770
+#define CS_SIDE_24000_A1 -0.287182
+#define CS_SIDE_24000_A2 -0.127588
+#define CS_SIDE_24000_B1 -1.229648
+#define CS_SIDE_24000_B2 0.282177
+#define CS_SIDE_24000_SCALE 14
+
+/* Stereo Enhancer coefficients for 32000Hz sample rate, scaled with 0.160322 */
+#define CS_MIDDLE_32000_A0 0.228400
+#define CS_MIDDLE_32000_A1 -0.225214
+#define CS_MIDDLE_32000_A2 0.000000
+#define CS_MIDDLE_32000_B1 -0.980126
+#define CS_MIDDLE_32000_B2 0.000000
+#define CS_MIDDLE_32000_SCALE 15
+#define CS_SIDE_32000_A0 0.364579
+#define CS_SIDE_32000_A1 -0.207355
+#define CS_SIDE_32000_A2 -0.157224
+#define CS_SIDE_32000_B1 -1.274231
+#define CS_SIDE_32000_B2 0.312495
+#define CS_SIDE_32000_SCALE 14
+
+/* Stereo Enhancer coefficients for 44100Hz sample rate, scaled with 0.163834 */
+#define CS_MIDDLE_44100_A0 0.233593
+#define CS_MIDDLE_44100_A1 -0.231225
+#define CS_MIDDLE_44100_A2 0.000000
+#define CS_MIDDLE_44100_B1 -0.985545
+#define CS_MIDDLE_44100_B2 0.000000
+#define CS_MIDDLE_44100_SCALE 15
+#define CS_SIDE_44100_A0 0.284573
+#define CS_SIDE_44100_A1 -0.258910
+#define CS_SIDE_44100_A2 -0.025662
+#define CS_SIDE_44100_B1 -1.572248
+#define CS_SIDE_44100_B2 0.588399
+#define CS_SIDE_44100_SCALE 14
+
+/* Stereo Enhancer coefficients for 48000Hz sample rate, scaled with 0.164402 */
+#define CS_MIDDLE_48000_A0 0.234445
+#define CS_MIDDLE_48000_A1 -0.232261
+#define CS_MIDDLE_48000_A2 0.000000
+#define CS_MIDDLE_48000_B1 -0.986713
+#define CS_MIDDLE_48000_B2 0.000000
+#define CS_MIDDLE_48000_SCALE 15
+#define CS_SIDE_48000_A0 0.272606
+#define CS_SIDE_48000_A1 -0.266952
+#define CS_SIDE_48000_A2 -0.005654
+#define CS_SIDE_48000_B1 -1.617141
+#define CS_SIDE_48000_B2 0.630405
+#define CS_SIDE_48000_SCALE 14
+
+#ifdef HIGHER_FS
+/* Stereo Enhancer coefficients for 96000Hz sample rate, scaled with 0.165*/
+/* high pass filter with cutoff frequency 102.18 Hz*/
+#define CS_MIDDLE_96000_A0 0.235532
+#define CS_MIDDLE_96000_A1 -0.234432
+#define CS_MIDDLE_96000_A2 0.000000
+#define CS_MIDDLE_96000_B1 -0.993334
+#define CS_MIDDLE_96000_B2 0.000000
+#define CS_MIDDLE_96000_SCALE 15
+/* bandpass filter with fc1 270 and fc2 3703, designed using 2nd order butterworth */
+#define CS_SIDE_96000_A0 0.016727
+#define CS_SIDE_96000_A1 0.000000
+#define CS_SIDE_96000_A2 -0.016727
+#define CS_SIDE_96000_B1 -1.793372
+#define CS_SIDE_96000_B2 0.797236
+#define CS_SIDE_96000_SCALE 14
+
+/* Stereo Enhancer coefficients for 192000Hz sample rate, scaled with 0.1689*/
+#define CS_MIDDLE_192000_A0 0.241219
+#define CS_MIDDLE_192000_A1 -0.240656
+#define CS_MIDDLE_192000_A2 0.000000
+#define CS_MIDDLE_192000_B1 -0.996661
+#define CS_MIDDLE_192000_B2 0.000000
+#define CS_MIDDLE_192000_SCALE 15
+/* bandpass filter with fc1 270 and fc2 3703, designed using 2nd order butterworth */
+#define CS_SIDE_192000_A0 0.008991
+#define CS_SIDE_192000_A1 -0.000000
+#define CS_SIDE_192000_A2 -0.008991
+#define CS_SIDE_192000_B1 -1.892509
+#define CS_SIDE_192000_B2 0.893524
+#define CS_SIDE_192000_SCALE 14
+#endif
+
+/************************************************************************************/
+/* */
+/* The Reverb Unit */
+/* */
+/************************************************************************************/
+
+/* Reverb delay settings in samples */
+#define LVCS_STEREODELAY_CS_8KHZ 93 /* Sample rate 8kS/s */
+#define LVCS_STEREODELAY_CS_11KHZ 128 /* Sample rate 11kS/s */
+#define LVCS_STEREODELAY_CS_12KHZ 139 /* Sample rate 12kS/s */
+#define LVCS_STEREODELAY_CS_16KHZ 186 /* Sample rate 16kS/s */
+#define LVCS_STEREODELAY_CS_22KHZ 256 /* Sample rate 22kS/s */
+#define LVCS_STEREODELAY_CS_24KHZ 279 /* Sample rate 24kS/s */
+#define LVCS_STEREODELAY_CS_32KHZ 372 /* Sample rate 32kS/s */
+#define LVCS_STEREODELAY_CS_44KHZ 512 /* Sample rate 44kS/s */
+#define LVCS_STEREODELAY_CS_48KHZ 512 /* Sample rate 48kS/s */
+
+/* Reverb coefficients for 8000 Hz sample rate, scaled with 1.038030 */
+#define CS_REVERB_8000_A0 0.667271
+#define CS_REVERB_8000_A1 -0.667271
+#define CS_REVERB_8000_A2 0.000000
+#define CS_REVERB_8000_B1 -0.668179
+#define CS_REVERB_8000_B2 0.000000
+#define CS_REVERB_8000_SCALE 15
+
+/* Reverb coefficients for 11025Hz sample rate, scaled with 1.038030 */
+#define CS_REVERB_11025_A0 0.699638
+#define CS_REVERB_11025_A1 -0.699638
+#define CS_REVERB_11025_A2 0.000000
+#define CS_REVERB_11025_B1 -0.749096
+#define CS_REVERB_11025_B2 0.000000
+#define CS_REVERB_11025_SCALE 15
+
+/* Reverb coefficients for 12000Hz sample rate, scaled with 1.038030 */
+#define CS_REVERB_12000_A0 0.706931
+#define CS_REVERB_12000_A1 -0.706931
+#define CS_REVERB_12000_A2 0.000000
+#define CS_REVERB_12000_B1 -0.767327
+#define CS_REVERB_12000_B2 0.000000
+#define CS_REVERB_12000_SCALE 15
+
+/* Reverb coefficients for 16000Hz sample rate, scaled with 1.038030 */
+#define CS_REVERB_16000_A0 0.728272
+#define CS_REVERB_16000_A1 -0.728272
+#define CS_REVERB_16000_A2 0.000000
+#define CS_REVERB_16000_B1 -0.820679
+#define CS_REVERB_16000_B2 0.000000
+#define CS_REVERB_16000_SCALE 15
+
+/* Reverb coefficients for 22050Hz sample rate, scaled with 1.038030 */
+#define CS_REVERB_22050_A0 0.516396
+#define CS_REVERB_22050_A1 0.000000
+#define CS_REVERB_22050_A2 -0.516396
+#define CS_REVERB_22050_B1 -0.518512
+#define CS_REVERB_22050_B2 -0.290990
+#define CS_REVERB_22050_SCALE 15
+
+
+/* Reverb coefficients for 24000Hz sample rate, scaled with 1.038030 */
+#define CS_REVERB_24000_A0 0.479565
+#define CS_REVERB_24000_A1 0.000000
+#define CS_REVERB_24000_A2 -0.479565
+#define CS_REVERB_24000_B1 -0.637745
+#define CS_REVERB_24000_B2 -0.198912
+#define CS_REVERB_24000_SCALE 15
+
+/* Reverb coefficients for 32000Hz sample rate, scaled with 1.038030 */
+#define CS_REVERB_32000_A0 0.380349
+#define CS_REVERB_32000_A1 0.000000
+#define CS_REVERB_32000_A2 -0.380349
+#define CS_REVERB_32000_B1 -0.950873
+#define CS_REVERB_32000_B2 0.049127
+#define CS_REVERB_32000_SCALE 15
+
+/* Reverb coefficients for 44100Hz sample rate, scaled with 1.038030 */
+#define CS_REVERB_44100_A0 0.297389
+#define CS_REVERB_44100_A1 0.000000
+#define CS_REVERB_44100_A2 -0.297389
+#define CS_REVERB_44100_B1 -1.200423
+#define CS_REVERB_44100_B2 0.256529
+#define CS_REVERB_44100_SCALE 14
+
+/* Reverb coefficients for 48000Hz sample rate, scaled with 1.038030 */
+#define CS_REVERB_48000_A0 0.278661
+#define CS_REVERB_48000_A1 0.000000
+#define CS_REVERB_48000_A2 -0.278661
+#define CS_REVERB_48000_B1 -1.254993
+#define CS_REVERB_48000_B2 0.303347
+#define CS_REVERB_48000_SCALE 14
+
+#ifdef HIGHER_FS
+/* Reverb coefficients for 96000Hz sample rate, scaled with 0.8 */
+/* Band pass filter with fc1=500 and fc2=8000*/
+#define CS_REVERB_96000_A0 0.1602488
+#define CS_REVERB_96000_A1 0.000000
+#define CS_REVERB_96000_A2 -0.1602488
+#define CS_REVERB_96000_B1 -1.585413
+#define CS_REVERB_96000_B2 0.599377
+#define CS_REVERB_96000_SCALE 14
+
+/* Reverb coefficients for 192000Hz sample rate, scaled with 0.8 */
+/* Band pass filter with fc1=500 and fc2=8000*/
+#define CS_REVERB_192000_A0 0.0878369
+#define CS_REVERB_192000_A1 0.000000
+#define CS_REVERB_192000_A2 -0.0878369
+#define CS_REVERB_192000_B1 -1.7765764
+#define CS_REVERB_192000_B2 0.7804076
+#define CS_REVERB_192000_SCALE 14
+
+#endif
+
+
+/* Reverb Gain Settings */
+#define LVCS_HEADPHONE_DELAYGAIN 0.800000 /* Algorithm delay path gain */
+#define LVCS_HEADPHONE_OUTPUTGAIN 1.000000 /* Algorithm output gain */
+#define LVCS_HEADPHONE_PROCGAIN 18403 /* Processed path gain */
+#define LVCS_HEADPHONE_UNPROCGAIN 18403 /* Unprocessed path gain */
+#define LVCS_HEADPHONE_GAINCORRECT 1.009343 /* Delay mixer gain correction */
+
+/************************************************************************************/
+/* */
+/* The Equaliser */
+/* */
+/************************************************************************************/
+
+/* Equaliser coefficients for 8000 Hz sample rate, \
+ CS scaled with 1.038497 and CSEX scaled with 0.775480 */
+#define CS_EQUALISER_8000_A0 1.263312
+#define CS_EQUALISER_8000_A1 -0.601748
+#define CS_EQUALISER_8000_A2 -0.280681
+#define CS_EQUALISER_8000_B1 -0.475865
+#define CS_EQUALISER_8000_B2 -0.408154
+#define CS_EQUALISER_8000_SCALE 14
+#define CSEX_EQUALISER_8000_A0 0.943357
+#define CSEX_EQUALISER_8000_A1 -0.449345
+#define CSEX_EQUALISER_8000_A2 -0.209594
+#define CSEX_EQUALISER_8000_B1 -0.475865
+#define CSEX_EQUALISER_8000_B2 -0.408154
+#define CSEX_EQUALISER_8000_SCALE 15
+
+/* Equaliser coefficients for 11025Hz sample rate, \
+ CS scaled with 1.027761 and CSEX scaled with 0.767463 */
+#define CS_EQUALISER_11025_A0 1.101145
+#define CS_EQUALISER_11025_A1 0.139020
+#define CS_EQUALISER_11025_A2 -0.864423
+#define CS_EQUALISER_11025_B1 0.024541
+#define CS_EQUALISER_11025_B2 -0.908930
+#define CS_EQUALISER_11025_SCALE 14
+#define CSEX_EQUALISER_11025_A0 0.976058
+#define CSEX_EQUALISER_11025_A1 -0.695326
+#define CSEX_EQUALISER_11025_A2 -0.090809
+#define CSEX_EQUALISER_11025_B1 -0.610594
+#define CSEX_EQUALISER_11025_B2 -0.311149
+#define CSEX_EQUALISER_11025_SCALE 15
+
+/* Equaliser coefficients for 12000Hz sample rate, \
+ CS scaled with 1.032521 and CSEX scaled with 0.771017 */
+#define CS_EQUALISER_12000_A0 1.276661
+#define CS_EQUALISER_12000_A1 -1.017519
+#define CS_EQUALISER_12000_A2 -0.044128
+#define CS_EQUALISER_12000_B1 -0.729616
+#define CS_EQUALISER_12000_B2 -0.204532
+#define CS_EQUALISER_12000_SCALE 14
+#define CSEX_EQUALISER_12000_A0 1.007095
+#define CSEX_EQUALISER_12000_A1 -0.871912
+#define CSEX_EQUALISER_12000_A2 0.023232
+#define CSEX_EQUALISER_12000_B1 -0.745857
+#define CSEX_EQUALISER_12000_B2 -0.189171
+#define CSEX_EQUALISER_12000_SCALE 14
+
+/* Equaliser coefficients for 16000Hz sample rate, \
+ CS scaled with 1.031378 and CSEX scaled with 0.770164 */
+#define CS_EQUALISER_16000_A0 1.281629
+#define CS_EQUALISER_16000_A1 -1.075872
+#define CS_EQUALISER_16000_A2 -0.041365
+#define CS_EQUALISER_16000_B1 -0.725239
+#define CS_EQUALISER_16000_B2 -0.224358
+#define CS_EQUALISER_16000_SCALE 14
+#define CSEX_EQUALISER_16000_A0 1.081091
+#define CSEX_EQUALISER_16000_A1 -0.867183
+#define CSEX_EQUALISER_16000_A2 -0.070247
+#define CSEX_EQUALISER_16000_B1 -0.515121
+#define CSEX_EQUALISER_16000_B2 -0.425893
+#define CSEX_EQUALISER_16000_SCALE 14
+
+/* Equaliser coefficients for 22050Hz sample rate, \
+ CS scaled with 1.041576 and CSEX scaled with 0.777779 */
+#define CS_EQUALISER_22050_A0 1.388605
+#define CS_EQUALISER_22050_A1 -1.305799
+#define CS_EQUALISER_22050_A2 0.039922
+#define CS_EQUALISER_22050_B1 -0.719494
+#define CS_EQUALISER_22050_B2 -0.243245
+#define CS_EQUALISER_22050_SCALE 14
+#define CSEX_EQUALISER_22050_A0 1.272910
+#define CSEX_EQUALISER_22050_A1 -1.341014
+#define CSEX_EQUALISER_22050_A2 0.167462
+#define CSEX_EQUALISER_22050_B1 -0.614219
+#define CSEX_EQUALISER_22050_B2 -0.345384
+#define CSEX_EQUALISER_22050_SCALE 14
+
+/* Equaliser coefficients for 24000Hz sample rate, \
+ CS scaled with 1.034495 and CSEX scaled with 0.772491 */
+#define CS_EQUALISER_24000_A0 1.409832
+#define CS_EQUALISER_24000_A1 -1.456506
+#define CS_EQUALISER_24000_A2 0.151410
+#define CS_EQUALISER_24000_B1 -0.804201
+#define CS_EQUALISER_24000_B2 -0.163783
+#define CS_EQUALISER_24000_SCALE 14
+#define CSEX_EQUALISER_24000_A0 1.299198
+#define CSEX_EQUALISER_24000_A1 -1.452447
+#define CSEX_EQUALISER_24000_A2 0.240489
+#define CSEX_EQUALISER_24000_B1 -0.669303
+#define CSEX_EQUALISER_24000_B2 -0.294984
+#define CSEX_EQUALISER_24000_SCALE 14
+
+/* Equaliser coefficients for 32000Hz sample rate, \
+ CS scaled with 1.044559 and CSEX scaled with 0.780006 */
+#define CS_EQUALISER_32000_A0 1.560988
+#define CS_EQUALISER_32000_A1 -1.877724
+#define CS_EQUALISER_32000_A2 0.389741
+#define CS_EQUALISER_32000_B1 -0.907410
+#define CS_EQUALISER_32000_B2 -0.070489
+#define CS_EQUALISER_32000_SCALE 14
+#define CSEX_EQUALISER_32000_A0 1.785049
+#define CSEX_EQUALISER_32000_A1 -2.233497
+#define CSEX_EQUALISER_32000_A2 0.526431
+#define CSEX_EQUALISER_32000_B1 -0.445939
+#define CSEX_EQUALISER_32000_B2 -0.522446
+#define CSEX_EQUALISER_32000_SCALE 13
+
+/* Equaliser coefficients for 44100Hz sample rate, \
+ CS scaled with 1.022170 and CSEX scaled with 0.763288 */
+#define CS_EQUALISER_44100_A0 1.623993
+#define CS_EQUALISER_44100_A1 -2.270743
+#define CS_EQUALISER_44100_A2 0.688829
+#define CS_EQUALISER_44100_B1 -1.117190
+#define CS_EQUALISER_44100_B2 0.130208
+#define CS_EQUALISER_44100_SCALE 13
+#define CSEX_EQUALISER_44100_A0 2.028315
+#define CSEX_EQUALISER_44100_A1 -2.882459
+#define CSEX_EQUALISER_44100_A2 0.904535
+#define CSEX_EQUALISER_44100_B1 -0.593308
+#define CSEX_EQUALISER_44100_B2 -0.385816
+#define CSEX_EQUALISER_44100_SCALE 13
+
+/* Equaliser coefficients for 48000Hz sample rate, \
+ CS scaled with 1.018635 and CSEX scaled with 0.760648 */
+#define CS_EQUALISER_48000_A0 1.641177
+#define CS_EQUALISER_48000_A1 -2.364687
+#define CS_EQUALISER_48000_A2 0.759910
+#define CS_EQUALISER_48000_B1 -1.166774
+#define CS_EQUALISER_48000_B2 0.178074
+#define CS_EQUALISER_48000_SCALE 13
+#define CSEX_EQUALISER_48000_A0 2.099655
+#define CSEX_EQUALISER_48000_A1 -3.065220
+#define CSEX_EQUALISER_48000_A2 1.010417
+#define CSEX_EQUALISER_48000_B1 -0.634021
+#define CSEX_EQUALISER_48000_B2 -0.347332
+#define CSEX_EQUALISER_48000_SCALE 13
+
+
+#ifdef HIGHER_FS
+#define CS_EQUALISER_96000_A0 1.784497
+#define CS_EQUALISER_96000_A1 -3.001435
+#define CS_EQUALISER_96000_A2 1.228422
+#define CS_EQUALISER_96000_B1 -1.477804
+#define CS_EQUALISER_96000_B2 0.481369
+#define CS_EQUALISER_96000_SCALE 13
+#define CSEX_EQUALISER_96000_A0 2.7573
+#define CSEX_EQUALISER_96000_A1 -4.6721
+#define CSEX_EQUALISER_96000_A2 1.9317
+#define CSEX_EQUALISER_96000_B1 -0.971718
+#define CSEX_EQUALISER_96000_B2 -0.021216
+#define CSEX_EQUALISER_96000_SCALE 13
+
+#define CS_EQUALISER_192000_A0 1.889582
+#define CS_EQUALISER_192000_A1 -3.456140
+#define CS_EQUALISER_192000_A2 1.569864
+#define CS_EQUALISER_192000_B1 -1.700798
+#define CS_EQUALISER_192000_B2 0.701824
+#define CS_EQUALISER_192000_SCALE 13
+#define CSEX_EQUALISER_192000_A0 3.4273
+#define CSEX_EQUALISER_192000_A1 -6.2936
+#define CSEX_EQUALISER_192000_A2 2.8720
+#define CSEX_EQUALISER_192000_B1 -1.31074
+#define CSEX_EQUALISER_192000_B2 0.31312
+#define CSEX_EQUALISER_192000_SCALE 13
+#endif
+
+
+#define LVCS_HEADPHONE_SHIFT 2 /* Output Shift */
+#define LVCS_HEADPHONE_SHIFTLOSS 0.8477735 /* Output Shift loss */
+#define LVCS_HEADPHONE_GAIN 0.2087465 /* Unprocessed path gain */
+#define LVCS_EX_HEADPHONE_SHIFT 3 /* EX Output Shift */
+#define LVCS_EX_HEADPHONE_SHIFTLOSS 0.569225 /* EX Output Shift loss */
+#define LVCS_EX_HEADPHONE_GAIN 0.07794425 /* EX Unprocessed path gain */
+#else
/* Stereo Enhancer coefficients for 8000 Hz sample rate, scaled with 0.161258 */
#define CS_MIDDLE_8000_A0 7462 /* Floating point value 0.227720 */
#define CS_MIDDLE_8000_A1 (-7049) /* Floating point value -0.215125 */
@@ -394,5 +850,6 @@
#define LVCS_EX_HEADPHONE_SHIFT 3 /* EX Output Shift */
#define LVCS_EX_HEADPHONE_SHIFTLOSS 18600 /* EX Output Shift loss */
#define LVCS_EX_HEADPHONE_GAIN 5108 /* EX Unprocessed path gain */
-
#endif
+#endif
+
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.c
index 1904e46..d4c7627 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.c
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.c
@@ -98,7 +98,13 @@
/*
* Scratch memory
*/
+#ifdef BUILD_FLOAT
+ /* Inplace processing */
+ ScratchSize = (LVM_UINT32) \
+ (LVCS_SCRATCHBUFFERS * sizeof(LVM_FLOAT) * pCapabilities->MaxBlockSize);
+#else
ScratchSize = (LVM_UINT32)(LVCS_SCRATCHBUFFERS*sizeof(LVM_INT16)*pCapabilities->MaxBlockSize); /* Inplace processing */
+#endif
pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].Size = ScratchSize;
pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].Type = LVCS_SCRATCH;
pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
@@ -190,6 +196,7 @@
pLVCS_VolCorrectTable = (LVCS_VolCorrect_t*)&LVCS_VolCorrectTable[0];
pInstance->VolCorrect = pLVCS_VolCorrectTable[0];
pInstance->TransitionGain = 0;
+
/* These current and target values are intialized again in LVCS_Control.c */
LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[0],0,0);
/* These current and target values are intialized again in LVCS_Control.c */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
index f3adb8d..a97e4f0 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
@@ -95,10 +95,17 @@
/* Volume correction structure */
typedef struct
{
+#ifdef BUILD_FLOAT
+ LVM_FLOAT CompFull; /* Post CS compression 100% effect */
+ LVM_FLOAT CompMin; /* Post CS compression 0% effect */
+ LVM_FLOAT GainFull; /* CS gain correct 100% effect */
+ LVM_FLOAT GainMin; /* CS gain correct 0% effect */
+#else
LVM_INT16 CompFull; /* Post CS compression 100% effect */
LVM_INT16 CompMin; /* Post CS compression 0% effect */
LVM_INT16 GainFull; /* CS gain correct 100% effect */
LVM_INT16 GainMin; /* CS gain correct 0% effect */
+#endif
} LVCS_VolCorrect_t;
/* Instance structure */
@@ -112,8 +119,13 @@
/* Private parameters */
LVCS_OutputDevice_en OutputDevice; /* Selected output device type */
LVCS_VolCorrect_t VolCorrect; /* Volume correction settings */
+#ifndef BUILD_FLOAT
LVM_INT16 TransitionGain; /* Transition gain */
LVM_INT16 CompressGain; /* Last used compressor gain*/
+#else
+ LVM_FLOAT TransitionGain; /* Transition gain */
+ LVM_FLOAT CompressGain; /* Last used compressor gain*/
+#endif
/* Sub-block configurations */
LVCS_StereoEnhancer_t StereoEnhancer; /* Stereo enhancer configuration */
@@ -134,24 +146,35 @@
/* Coefficient Structure */
typedef struct
{
+#ifdef BUILD_FLOAT
+ Biquad_FLOAT_Instance_t EqualiserBiquadInstance;
+ Biquad_FLOAT_Instance_t ReverbBiquadInstance;
+ Biquad_FLOAT_Instance_t SEBiquadInstanceMid;
+ Biquad_FLOAT_Instance_t SEBiquadInstanceSide;
+#else
Biquad_Instance_t EqualiserBiquadInstance;
Biquad_Instance_t ReverbBiquadInstance;
Biquad_Instance_t SEBiquadInstanceMid;
Biquad_Instance_t SEBiquadInstanceSide;
-
+#endif
} LVCS_Coefficient_t;
/* Data Structure */
typedef struct
{
+#ifdef BUILD_FLOAT
+ Biquad_2I_Order2_FLOAT_Taps_t EqualiserBiquadTaps;
+ Biquad_2I_Order2_FLOAT_Taps_t ReverbBiquadTaps;
+ Biquad_1I_Order1_FLOAT_Taps_t SEBiquadTapsMid;
+ Biquad_1I_Order2_FLOAT_Taps_t SEBiquadTapsSide;
+#else
Biquad_2I_Order2_Taps_t EqualiserBiquadTaps;
Biquad_2I_Order2_Taps_t ReverbBiquadTaps;
Biquad_1I_Order1_Taps_t SEBiquadTapsMid;
Biquad_1I_Order2_Taps_t SEBiquadTapsSide;
-
+#endif
} LVCS_Data_t;
-
void LVCS_TimerCallBack ( void* hInstance,
void* pCallBackParams,
LVM_INT32 CallbackParam);
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c
index 5d99461..3956d4d 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c
@@ -66,7 +66,77 @@
/* NOTES: */
/* */
/************************************************************************************/
+#ifdef BUILD_FLOAT
+LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples)
+{
+ const LVM_FLOAT *pInput;
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVM_FLOAT *pScratch;
+ LVCS_ReturnStatus_en err;
+ pScratch = (LVM_FLOAT *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
+
+ /*
+ * Check if the processing is inplace
+ */
+ if (pInData == pOutData)
+ {
+ /* Processing inplace */
+ pInput = pScratch + (2 * NumSamples);
+ Copy_Float((LVM_FLOAT *)pInData, /* Source */
+ (LVM_FLOAT *)pInput, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Left and right */
+ }
+ else
+ {
+ /* Processing outplace */
+ pInput = pInData;
+ }
+
+ /*
+ * Call the stereo enhancer
+ */
+ err = LVCS_StereoEnhancer(hInstance, /* Instance handle */
+ pInData, /* Pointer to the input data */
+ pOutData, /* Pointer to the output data */
+ NumSamples); /* Number of samples to process */
+
+ /*
+ * Call the reverb generator
+ */
+ err = LVCS_ReverbGenerator(hInstance, /* Instance handle */
+ pOutData, /* Pointer to the input data */
+ pOutData, /* Pointer to the output data */
+ NumSamples); /* Number of samples to process */
+
+ /*
+ * Call the equaliser
+ */
+ err = LVCS_Equaliser(hInstance, /* Instance handle */
+ pOutData, /* Pointer to the input data */
+ NumSamples); /* Number of samples to process */
+
+ /*
+ * Call the bypass mixer
+ */
+ err = LVCS_BypassMixer(hInstance, /* Instance handle */
+ pOutData, /* Pointer to the processed data */
+ pInput, /* Pointer to the input (unprocessed) data */
+ pOutData, /* Pointer to the output data */
+ NumSamples); /* Number of samples to process */
+
+ if(err != LVCS_SUCCESS)
+ {
+ return err;
+ }
+
+ return(LVCS_SUCCESS);
+}
+#else
LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 *pOutData,
@@ -133,7 +203,7 @@
return(LVCS_SUCCESS);
}
-
+#endif
/************************************************************************************/
/* */
/* FUNCTION: LVCS_Process */
@@ -160,7 +230,170 @@
/* NOTES: */
/* */
/************************************************************************************/
+#ifdef BUILD_FLOAT
+LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples)
+{
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_ReturnStatus_en err;
+
+ /*
+ * Check the number of samples is not too large
+ */
+ if (NumSamples > pInstance->Capabilities.MaxBlockSize)
+ {
+ return(LVCS_TOOMANYSAMPLES);
+ }
+
+ /*
+ * Check if the algorithm is enabled
+ */
+ if (pInstance->Params.OperatingMode != LVCS_OFF)
+ {
+ /*
+ * Call CS process function
+ */
+ err = LVCS_Process_CS(hInstance,
+ pInData,
+ pOutData,
+ NumSamples);
+
+
+ /*
+ * Compress to reduce expansion effect of Concert Sound and correct volume
+ * differences for difference settings. Not applied in test modes
+ */
+ if ((pInstance->Params.OperatingMode == LVCS_ON)&& \
+ (pInstance->Params.CompressorMode == LVM_MODE_ON))
+ {
+ LVM_FLOAT Gain = pInstance->VolCorrect.CompMin;
+ LVM_FLOAT Current1;
+
+ Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]);
+ Gain = (LVM_FLOAT)( pInstance->VolCorrect.CompMin
+ - (((LVM_FLOAT)pInstance->VolCorrect.CompMin * (Current1)))
+ + (((LVM_FLOAT)pInstance->VolCorrect.CompFull * (Current1))));
+
+ if(NumSamples < LVCS_COMPGAINFRAME)
+ {
+ NonLinComp_Float(Gain, /* Compressor gain setting */
+ pOutData,
+ pOutData,
+ (LVM_INT32)(2 * NumSamples));
+ }
+ else
+ {
+ LVM_FLOAT GainStep;
+ LVM_FLOAT FinalGain;
+ LVM_INT16 SampleToProcess = NumSamples;
+ LVM_FLOAT *pOutPtr;
+
+ /* Large changes in Gain can cause clicks in output
+ Split data into small blocks and use interpolated gain values */
+
+ GainStep = (LVM_FLOAT)(((Gain-pInstance->CompressGain) * \
+ LVCS_COMPGAINFRAME) / NumSamples);
+
+ if((GainStep == 0) && (pInstance->CompressGain < Gain))
+ {
+ GainStep = 1;
+ }
+ else
+ {
+ if((GainStep == 0) && (pInstance->CompressGain > Gain))
+ {
+ GainStep = -1;
+ }
+ }
+
+ FinalGain = Gain;
+ Gain = pInstance->CompressGain;
+ pOutPtr = pOutData;
+
+ while(SampleToProcess > 0)
+ {
+ Gain = (LVM_FLOAT)(Gain + GainStep);
+ if((GainStep > 0) && (FinalGain <= Gain))
+ {
+ Gain = FinalGain;
+ GainStep = 0;
+ }
+
+ if((GainStep < 0) && (FinalGain > Gain))
+ {
+ Gain = FinalGain;
+ GainStep = 0;
+ }
+
+ if(SampleToProcess > LVCS_COMPGAINFRAME)
+ {
+ NonLinComp_Float(Gain, /* Compressor gain setting */
+ pOutPtr,
+ pOutPtr,
+ (LVM_INT32)(2 * LVCS_COMPGAINFRAME));
+ pOutPtr += (2 * LVCS_COMPGAINFRAME);
+ SampleToProcess = (LVM_INT16)(SampleToProcess - LVCS_COMPGAINFRAME);
+ }
+ else
+ {
+ NonLinComp_Float(Gain, /* Compressor gain setting */
+ pOutPtr,
+ pOutPtr,
+ (LVM_INT32)(2 * SampleToProcess));
+ SampleToProcess = 0;
+ }
+
+ }
+ }
+
+ /* Store gain value*/
+ pInstance->CompressGain = Gain;
+ }
+
+
+ if(pInstance->bInOperatingModeTransition == LVM_TRUE){
+
+ /*
+ * Re-init bypass mix when timer has completed
+ */
+ if ((pInstance->bTimerDone == LVM_TRUE) &&
+ (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0))
+ {
+ err = LVCS_BypassMixInit(hInstance,
+ &pInstance->Params);
+
+ if(err != LVCS_SUCCESS)
+ {
+ return err;
+ }
+
+ }
+ else{
+ LVM_Timer ( &pInstance->TimerInstance,
+ (LVM_INT16)NumSamples);
+ }
+ }
+ }
+ else
+ {
+ if (pInData != pOutData)
+ {
+ /*
+ * The algorithm is disabled so just copy the data
+ */
+ Copy_Float((LVM_FLOAT *)pInData, /* Source */
+ (LVM_FLOAT *)pOutData, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Left and right */
+ }
+ }
+
+
+ return(LVCS_SUCCESS);
+}
+#else
LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 *pOutData,
@@ -321,13 +554,4 @@
return(LVCS_SUCCESS);
}
-
-
-
-
-
-
-
-
-
-
+#endif
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.c
index ee257b8..1085101 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.c
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.c
@@ -57,7 +57,98 @@
/* 2. The numerator coefficients of the filter are negated to cause an inversion. */
/* */
/************************************************************************************/
+#ifdef BUILD_FLOAT
+LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance,
+ LVCS_Params_t *pParams)
+{
+ LVM_UINT16 Delay;
+ LVM_UINT16 Offset;
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
+ LVCS_Data_t *pData;
+ LVCS_Coefficient_t *pCoefficients;
+ BQ_FLOAT_Coefs_t Coeffs;
+ const BiquadA012B12CoefsSP_t *pReverbCoefTable;
+
+
+ pData = (LVCS_Data_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
+
+ pCoefficients = (LVCS_Coefficient_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+
+ /*
+ * Initialise the delay and filters if:
+ * - the sample rate has changed
+ * - the speaker type has changed to or from the mobile speaker
+ */
+ if(pInstance->Params.SampleRate != pParams->SampleRate ) /* Sample rate change test */
+
+ {
+ /*
+ * Setup the delay
+ */
+ Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate];
+
+
+ pConfig->DelaySize = (LVM_INT16)(2 * Delay);
+ pConfig->DelayOffset = 0;
+ LoadConst_Float(0, /* Value */
+ (LVM_FLOAT *)&pConfig->StereoSamples[0], /* Destination */
+ /* Number of words */
+ (LVM_UINT16)(sizeof(pConfig->StereoSamples) / sizeof(LVM_FLOAT)));
+ /*
+ * Setup the filters
+ */
+ Offset = (LVM_UINT16)pParams->SampleRate;
+ pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0];
+
+ /* Convert incoming coefficients to the required format/ordering */
+ Coeffs.A0 = (LVM_FLOAT)pReverbCoefTable[Offset].A0;
+ Coeffs.A1 = (LVM_FLOAT)pReverbCoefTable[Offset].A1;
+ Coeffs.A2 = (LVM_FLOAT)pReverbCoefTable[Offset].A2;
+ Coeffs.B1 = (LVM_FLOAT)-pReverbCoefTable[Offset].B1;
+ Coeffs.B2 = (LVM_FLOAT)-pReverbCoefTable[Offset].B2;
+
+ LoadConst_Float(0, /* Value */
+ (void *)&pData->ReverbBiquadTaps, /* Destination Cast to void:
+ no dereferencing in function*/
+ /* Number of words */
+ (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps) / sizeof(LVM_FLOAT)));
+
+ BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance,
+ &pData->ReverbBiquadTaps,
+ &Coeffs);
+
+ /* Callbacks */
+ switch(pReverbCoefTable[Offset].Scale)
+ {
+ case 14:
+ pConfig->pBiquadCallBack = BQ_2I_D16F16C14_TRC_WRA_01;
+ break;
+ case 15:
+ pConfig->pBiquadCallBack = BQ_2I_D16F16C15_TRC_WRA_01;
+ break;
+ }
+
+
+ /*
+ * Setup the mixer
+ */
+ pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC);
+ pConfig->UnprocGain = (LVM_UINT16)(HEADPHONEGAINUNPROC);
+ }
+
+ if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
+ {
+ LVM_INT32 ReverbPercentage = 83886; // 1 Percent Reverb i.e 1/100 in Q 23 format
+ ReverbPercentage *= pParams->ReverbLevel; // Actual Reverb Level in Q 23 format
+ pConfig->ReverbLevel = ((LVM_FLOAT)(ReverbPercentage>>8)) / 32767.0f;
+ }
+ return(LVCS_SUCCESS);
+}
+#else
LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance,
LVCS_Params_t *pParams)
{
@@ -140,7 +231,7 @@
return(LVCS_SUCCESS);
}
-
+#endif
/************************************************************************************/
/* */
/* FUNCTION: LVCS_Reverb */
@@ -179,7 +270,91 @@
/* 2. The Gain is combined with the LPF and incorporated in to the coefficients */
/* */
/************************************************************************************/
+#ifdef BUILD_FLOAT
+LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples)
+{
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
+ LVCS_Coefficient_t *pCoefficients;
+ LVM_FLOAT *pScratch;
+
+ pCoefficients = (LVCS_Coefficient_t *)\
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+
+ pScratch = (LVM_FLOAT *)\
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
+
+ /*
+ * Copy the data to the output in outplace processing
+ */
+ if (pInData != pOutData)
+ {
+ /*
+ * Reverb not required so just copy the data
+ */
+ Copy_Float((LVM_FLOAT *)pInData, /* Source */
+ (LVM_FLOAT *)pOutData, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Left and right */
+ }
+
+
+ /*
+ * Check if the reverb is required
+ */
+ /* Disable when CS4MS in stereo mode */
+ if (((pInstance->Params.SpeakerType == LVCS_HEADPHONE) || \
+ (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) ||
+ (pInstance->Params.SourceFormat != LVCS_STEREO)) &&
+ /* For validation testing */
+ ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0))
+ {
+ /********************************************************************************/
+ /* */
+ /* Copy the input data to scratch memory and filter it */
+ /* */
+ /********************************************************************************/
+
+ /*
+ * Copy the input data to the scratch memory
+ */
+ Copy_Float((LVM_FLOAT *)pInData, /* Source */
+ (LVM_FLOAT *)pScratch, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Left and right */
+
+ /*
+ * Filter the data
+ */
+ (pConfig->pBiquadCallBack)((Biquad_FLOAT_Instance_t*)&pCoefficients->ReverbBiquadInstance,
+ (LVM_FLOAT *)pScratch,
+ (LVM_FLOAT *)pScratch,
+ (LVM_INT16)NumSamples);
+
+ Mult3s_Float( (LVM_FLOAT *)pScratch,
+ pConfig->ReverbLevel,
+ (LVM_FLOAT *)pScratch,
+ (LVM_INT16)(2 * NumSamples));
+
+
+ /*
+ * Apply the delay mix
+ */
+ DelayMix_Float((LVM_FLOAT *)pScratch,
+ &pConfig->StereoSamples[0],
+ pConfig->DelaySize,
+ pOutData,
+ &pConfig->DelayOffset,
+ (LVM_INT16)NumSamples);
+
+
+ }
+
+ return(LVCS_SUCCESS);
+}
+#else
LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 *pOutData,
@@ -257,8 +432,4 @@
return(LVCS_SUCCESS);
}
-
-
-
-
-
+#endif
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.h
index 6e026ff..69892b6 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.h
@@ -58,14 +58,20 @@
LVM_INT16 DelayOffset;
LVM_INT16 ProcGain;
LVM_INT16 UnprocGain;
+#ifndef BUILD_FLOAT
LVM_INT16 StereoSamples[2*LVCS_STEREODELAY_CS_48KHZ];
-
/* Reverb Level */
LVM_INT16 ReverbLevel;
-
/* Filter */
void (*pBiquadCallBack) (Biquad_Instance_t*, LVM_INT16*, LVM_INT16*, LVM_INT16);
-
+#else
+ LVM_FLOAT StereoSamples[2 * LVCS_STEREODELAY_CS_48KHZ];
+ /* Reverb Level */
+ LVM_FLOAT ReverbLevel;
+ /* Filter */
+ void (*pBiquadCallBack) (Biquad_FLOAT_Instance_t*,
+ LVM_FLOAT*, LVM_FLOAT*, LVM_INT16);
+#endif
} LVCS_ReverbGenerator_t;
@@ -77,12 +83,17 @@
LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance,
LVCS_Params_t *pParams);
-
+#ifdef BUILD_FLOAT
+LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t hInstance,
+ const LVM_FLOAT *pInput,
+ LVM_FLOAT *pOutput,
+ LVM_UINT16 NumSamples);
+#else
LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t hInstance,
const LVM_INT16 *pInput,
LVM_INT16 *pOutput,
LVM_UINT16 NumSamples);
-
+#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.c
index b9b8b05..2992c35 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.c
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.c
@@ -49,7 +49,103 @@
/* NOTES: */
/* */
/************************************************************************************/
+#ifdef BUILD_FLOAT
+LVCS_ReturnStatus_en LVCS_SEnhancerInit(LVCS_Handle_t hInstance,
+ LVCS_Params_t *pParams)
+{
+ LVM_UINT16 Offset;
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_StereoEnhancer_t *pConfig = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
+ LVCS_Data_t *pData;
+ LVCS_Coefficient_t *pCoefficient;
+ FO_FLOAT_Coefs_t CoeffsMid;
+ BQ_FLOAT_Coefs_t CoeffsSide;
+ const BiquadA012B12CoefsSP_t *pSESideCoefs;
+
+
+ pData = (LVCS_Data_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
+
+ pCoefficient = (LVCS_Coefficient_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+
+ /*
+ * If the sample rate or speaker type has changed update the filters
+ */
+ if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
+ (pInstance->Params.SpeakerType != pParams->SpeakerType))
+ {
+ /*
+ * Set the filter coefficients based on the sample rate
+ */
+ /* Mid filter */
+ Offset = (LVM_UINT16)pParams->SampleRate;
+
+ /* Convert incoming coefficients to the required format/ordering */
+ CoeffsMid.A0 = (LVM_FLOAT) LVCS_SEMidCoefTable[Offset].A0;
+ CoeffsMid.A1 = (LVM_FLOAT) LVCS_SEMidCoefTable[Offset].A1;
+ CoeffsMid.B1 = (LVM_FLOAT)-LVCS_SEMidCoefTable[Offset].B1;
+
+ /* Clear the taps */
+ LoadConst_Float(0, /* Value */
+ (void *)&pData->SEBiquadTapsMid, /* Destination Cast to void:\
+ no dereferencing in function*/
+ /* Number of words */
+ (LVM_UINT16)(sizeof(pData->SEBiquadTapsMid) / sizeof(LVM_FLOAT)));
+
+ FO_1I_D16F16Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceMid,
+ &pData->SEBiquadTapsMid,
+ &CoeffsMid);
+
+ /* Callbacks */
+ if(LVCS_SEMidCoefTable[Offset].Scale == 15)
+ {
+ pConfig->pBiquadCallBack_Mid = FO_1I_D16F16C15_TRC_WRA_01;
+ }
+
+ Offset = (LVM_UINT16)(pParams->SampleRate);
+ pSESideCoefs = (BiquadA012B12CoefsSP_t*)&LVCS_SESideCoefTable[0];
+
+ /* Side filter */
+ /* Convert incoming coefficients to the required format/ordering */
+ CoeffsSide.A0 = (LVM_FLOAT) pSESideCoefs[Offset].A0;
+ CoeffsSide.A1 = (LVM_FLOAT) pSESideCoefs[Offset].A1;
+ CoeffsSide.A2 = (LVM_FLOAT) pSESideCoefs[Offset].A2;
+ CoeffsSide.B1 = (LVM_FLOAT)-pSESideCoefs[Offset].B1;
+ CoeffsSide.B2 = (LVM_FLOAT)-pSESideCoefs[Offset].B2;
+
+ /* Clear the taps */
+ LoadConst_Float(0, /* Value */
+ (void *)&pData->SEBiquadTapsSide, /* Destination Cast to void:\
+ no dereferencing in function*/
+ /* Number of words */
+ (LVM_UINT16)(sizeof(pData->SEBiquadTapsSide) / sizeof(LVM_FLOAT)));
+ /* Callbacks */
+ switch(pSESideCoefs[Offset].Scale)
+ {
+ case 14:
+ BQ_1I_D16F32Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
+ &pData->SEBiquadTapsSide,
+ &CoeffsSide);
+
+ pConfig->pBiquadCallBack_Side = BQ_1I_D16F32C14_TRC_WRA_01;
+ break;
+ case 15:
+ BQ_1I_D16F16Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
+ &pData->SEBiquadTapsSide,
+ &CoeffsSide);
+
+ pConfig->pBiquadCallBack_Side = BQ_1I_D16F16C15_TRC_WRA_01;
+ break;
+ }
+
+ }
+
+
+ return(LVCS_SUCCESS);
+}
+#else
LVCS_ReturnStatus_en LVCS_SEnhancerInit(LVCS_Handle_t hInstance,
LVCS_Params_t *pParams)
{
@@ -138,7 +234,7 @@
return(LVCS_SUCCESS);
}
-
+#endif
/************************************************************************************/
/* */
/* FUNCTION: LVCS_StereoEnhance */
@@ -177,7 +273,90 @@
/* 1. The side filter is not used in Mobile Speaker mode */
/* */
/************************************************************************************/
+#ifdef BUILD_FLOAT
+LVCS_ReturnStatus_en LVCS_StereoEnhancer(LVCS_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples)
+{
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_StereoEnhancer_t *pConfig = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
+ LVCS_Coefficient_t *pCoefficient;
+ LVM_FLOAT *pScratch;
+
+ pCoefficient = (LVCS_Coefficient_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+
+ pScratch = (LVM_FLOAT *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
+ /*
+ * Check if the Stereo Enhancer is enabled
+ */
+ if ((pInstance->Params.OperatingMode & LVCS_STEREOENHANCESWITCH) != 0)
+ {
+ /*
+ * Convert from stereo to middle and side
+ */
+ From2iToMS_Float(pInData,
+ pScratch,
+ pScratch + NumSamples,
+ (LVM_INT16)NumSamples);
+
+ /*
+ * Apply filter to the middle signal
+ */
+ if (pInstance->OutputDevice == LVCS_HEADPHONE)
+ {
+ (pConfig->pBiquadCallBack_Mid)((Biquad_FLOAT_Instance_t*)\
+ &pCoefficient->SEBiquadInstanceMid,
+ (LVM_FLOAT *)pScratch,
+ (LVM_FLOAT *)pScratch,
+ (LVM_INT16)NumSamples);
+ }
+ else
+ {
+ Mult3s_Float(pScratch, /* Source */
+ (LVM_FLOAT)pConfig->MidGain, /* Gain */
+ pScratch, /* Destination */
+ (LVM_INT16)NumSamples); /* Number of samples */
+ }
+
+ /*
+ * Apply the filter the side signal only in stereo mode for headphones
+ * and in all modes for mobile speakers
+ */
+ if (pInstance->Params.SourceFormat == LVCS_STEREO)
+ {
+ (pConfig->pBiquadCallBack_Side)((Biquad_FLOAT_Instance_t*) \
+ &pCoefficient->SEBiquadInstanceSide,
+ (LVM_FLOAT *)(pScratch + NumSamples),
+ (LVM_FLOAT *)(pScratch + NumSamples),
+ (LVM_INT16)NumSamples);
+ }
+
+ /*
+ * Convert from middle and side to stereo
+ */
+ MSTo2i_Sat_Float(pScratch,
+ pScratch + NumSamples,
+ pOutData,
+ (LVM_INT16)NumSamples);
+
+ }
+ else
+ {
+ /*
+ * The stereo enhancer is disabled so just copy the data
+ */
+ Copy_Float((LVM_FLOAT *)pInData, /* Source */
+ (LVM_FLOAT *)pOutData, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Left and right */
+ }
+
+ return(LVCS_SUCCESS);
+}
+#else
LVCS_ReturnStatus_en LVCS_StereoEnhancer(LVCS_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 *pOutData,
@@ -254,7 +433,4 @@
return(LVCS_SUCCESS);
}
-
-
-
-
+#endif
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.h
index 15bc407..4125f24 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.h
@@ -43,18 +43,31 @@
/* Stereo enhancer structure */
typedef struct
{
+
+#ifndef BUILD_FLOAT
/*
* Middle filter
*/
void (*pBiquadCallBack_Mid)(Biquad_Instance_t*, LVM_INT16*, LVM_INT16*, LVM_INT16);
-
/*
* Side filter
*/
void (*pBiquadCallBack_Side)(Biquad_Instance_t*, LVM_INT16*, LVM_INT16*, LVM_INT16);
+ LVM_UINT16 MidGain; /* Middle gain in mobile speaker mode */
+#else
+ /*
+ * Middle filter
+ */
+ void (*pBiquadCallBack_Mid)(Biquad_FLOAT_Instance_t*,
+ LVM_FLOAT*, LVM_FLOAT*, LVM_INT16);
- LVM_UINT16 MidGain; /* Middle gain in mobile speaker mode */
-
+ /*
+ * Side filter
+ */
+ void (*pBiquadCallBack_Side)(Biquad_FLOAT_Instance_t*,
+ LVM_FLOAT*, LVM_FLOAT*, LVM_INT16);
+ LVM_FLOAT MidGain; /* Middle gain in mobile speaker mode */
+#endif
} LVCS_StereoEnhancer_t;
@@ -67,12 +80,17 @@
LVCS_ReturnStatus_en LVCS_SEnhancerInit(LVCS_Handle_t hInstance,
LVCS_Params_t *pParams);
+#ifndef BUILD_FLOAT
LVCS_ReturnStatus_en LVCS_StereoEnhancer(LVCS_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 *pOutData,
LVM_UINT16 NumSamples);
-
-
+#else
+LVCS_ReturnStatus_en LVCS_StereoEnhancer(LVCS_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples);
+#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.c
index 974de21..e154e29 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.c
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.c
@@ -71,7 +71,19 @@
{CS_MIDDLE_48000_A0, /* 48kS/s coefficients */
CS_MIDDLE_48000_A1,
CS_MIDDLE_48000_B1,
- (LVM_UINT16 )CS_MIDDLE_48000_SCALE}};
+ (LVM_UINT16 )CS_MIDDLE_48000_SCALE}
+#ifdef HIGHER_FS
+ ,
+ {CS_MIDDLE_96000_A0, /* 96kS/s coefficients */
+ CS_MIDDLE_96000_A1,
+ CS_MIDDLE_96000_B1,
+ (LVM_UINT16 )CS_MIDDLE_96000_SCALE},
+ {CS_MIDDLE_192000_A0, /* 192kS/s coefficients */
+ CS_MIDDLE_192000_A1,
+ CS_MIDDLE_192000_B1,
+ (LVM_UINT16 )CS_MIDDLE_192000_SCALE}
+#endif
+ };
/* Coefficient table for the side filter */
const BiquadA012B12CoefsSP_t LVCS_SESideCoefTable[] = {
@@ -130,6 +142,21 @@
CS_SIDE_48000_B1,
CS_SIDE_48000_B2,
(LVM_UINT16 )CS_SIDE_48000_SCALE}
+#ifdef HIGHER_FS
+ ,
+ {CS_SIDE_96000_A0, /* 96kS/s coefficients */
+ CS_SIDE_96000_A1,
+ CS_SIDE_96000_A2,
+ CS_SIDE_96000_B1,
+ CS_SIDE_96000_B2,
+ (LVM_UINT16 )CS_SIDE_96000_SCALE},
+ {CS_SIDE_192000_A0, /* 192kS/s coefficients */
+ CS_SIDE_192000_A1,
+ CS_SIDE_192000_A2,
+ CS_SIDE_192000_B1,
+ CS_SIDE_192000_B2,
+ (LVM_UINT16 )CS_SIDE_192000_SCALE}
+#endif
};
@@ -195,6 +222,20 @@
CS_EQUALISER_48000_B1,
CS_EQUALISER_48000_B2,
(LVM_UINT16 )CS_EQUALISER_48000_SCALE},
+#ifdef HIGHER_FS
+ {CS_EQUALISER_96000_A0, /* 96kS/s coefficients */
+ CS_EQUALISER_96000_A1,
+ CS_EQUALISER_96000_A2,
+ CS_EQUALISER_96000_B1,
+ CS_EQUALISER_96000_B2,
+ (LVM_UINT16 )CS_EQUALISER_96000_SCALE},
+ {CS_EQUALISER_192000_A0, /* 192kS/s coefficients */
+ CS_EQUALISER_192000_A1,
+ CS_EQUALISER_192000_A2,
+ CS_EQUALISER_192000_B1,
+ CS_EQUALISER_192000_B2,
+ (LVM_UINT16 )CS_EQUALISER_192000_SCALE},
+#endif
/* Concert Sound EX Headphone coefficients */
{CSEX_EQUALISER_8000_A0, /* 8kS/s coefficients */
@@ -251,6 +292,21 @@
CSEX_EQUALISER_48000_B1,
CSEX_EQUALISER_48000_B2,
(LVM_UINT16 )CSEX_EQUALISER_48000_SCALE}
+#ifdef HIGHER_FS
+ ,
+ {CSEX_EQUALISER_96000_A0, /* 96kS/s coefficients */
+ CSEX_EQUALISER_96000_A1,
+ CSEX_EQUALISER_96000_A2,
+ CSEX_EQUALISER_96000_B1,
+ CSEX_EQUALISER_96000_B2,
+ (LVM_UINT16 )CSEX_EQUALISER_96000_SCALE},
+ {CSEX_EQUALISER_192000_A0, /* 192kS/s coefficients */
+ CSEX_EQUALISER_192000_A1,
+ CSEX_EQUALISER_192000_A2,
+ CSEX_EQUALISER_192000_B1,
+ CSEX_EQUALISER_192000_B2,
+ (LVM_UINT16 )CSEX_EQUALISER_192000_SCALE}
+#endif
};
@@ -334,6 +390,21 @@
CS_REVERB_48000_B1,
CS_REVERB_48000_B2,
(LVM_UINT16 )CS_REVERB_48000_SCALE}
+#ifdef HIGHER_FS
+ ,
+ {CS_REVERB_96000_A0, /* 96kS/s coefficients */
+ CS_REVERB_96000_A1,
+ CS_REVERB_96000_A2,
+ CS_REVERB_96000_B1,
+ CS_REVERB_96000_B2,
+ (LVM_UINT16 )CS_REVERB_96000_SCALE},
+ {CS_REVERB_192000_A0, /* 192kS/s coefficients */
+ CS_REVERB_192000_A1,
+ CS_REVERB_192000_A2,
+ CS_REVERB_192000_B1,
+ CS_REVERB_192000_B2,
+ (LVM_UINT16 )CS_REVERB_192000_SCALE}
+#endif
};
@@ -385,6 +456,24 @@
/* */
/************************************************************************************/
const LVCS_VolCorrect_t LVCS_VolCorrectTable[] = {
+#ifdef BUILD_FLOAT
+ {0.433362f, /* Headphone, stereo mode */
+ 0.000000f,
+ 1.000024f,
+ 1.412640f},
+ {0.433362f, /* EX Headphone, stereo mode */
+ 0.000000f,
+ 1.000024f,
+ 1.412640f},
+ {1.000000f, /* Headphone, mono mode */
+ 0.000000f,
+ 1.000024f,
+ 1.412640f},
+ {1.000000f, /* EX Headphone, mono mode */
+ 0.000000f,
+ 1.000024f,
+ 1.412640f}
+#else
{14200, /* Headphone, stereo mode */
0,
4096,
@@ -401,6 +490,7 @@
0,
4096,
5786}
+#endif
};
/************************************************************************************/
@@ -418,8 +508,25 @@
#define LVCS_VOL_TC_Fs32000 32721 /* Floating point value 0.998565674 */
#define LVCS_VOL_TC_Fs44100 32734 /* Floating point value 0.998962402 */
#define LVCS_VOL_TC_Fs48000 32737 /* Floating point value 0.999053955 */
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+#define LVCS_VOL_TC_Fs96000 32751 /* Floating point value 0.999511703 */ /* Todo @ need to re check this value*/
+#define LVCS_VOL_TC_Fs192000 32763 /* Floating point value 0.999877925 */ /* Todo @ need to re check this value*/
+#endif
-
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+const LVM_INT16 LVCS_VolumeTCTable[11] = {LVCS_VOL_TC_Fs8000,
+ LVCS_VOL_TC_Fs11025,
+ LVCS_VOL_TC_Fs12000,
+ LVCS_VOL_TC_Fs16000,
+ LVCS_VOL_TC_Fs22050,
+ LVCS_VOL_TC_Fs24000,
+ LVCS_VOL_TC_Fs32000,
+ LVCS_VOL_TC_Fs44100,
+ LVCS_VOL_TC_Fs48000,
+ LVCS_VOL_TC_Fs96000,
+ LVCS_VOL_TC_Fs192000
+};
+#else
const LVM_INT16 LVCS_VolumeTCTable[9] = {LVCS_VOL_TC_Fs8000,
LVCS_VOL_TC_Fs11025,
LVCS_VOL_TC_Fs12000,
@@ -428,15 +535,30 @@
LVCS_VOL_TC_Fs24000,
LVCS_VOL_TC_Fs32000,
LVCS_VOL_TC_Fs44100,
- LVCS_VOL_TC_Fs48000};
+ LVCS_VOL_TC_Fs48000
+};
+#endif
/************************************************************************************/
/* */
/* Sample rate table */
/* */
/************************************************************************************/
-
-const LVM_INT32 LVCS_SampleRateTable[9] = {8000,
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+const LVM_INT32 LVCS_SampleRateTable[11] = {8000,
+ 11025,
+ 12000,
+ 16000,
+ 22050,
+ 24000,
+ 32000,
+ 44100,
+ 48000,
+ 96000,
+ 192000
+};
+#else
+const LVM_INT16 LVCS_SampleRateTable[9] = {8000,
11025,
12000,
16000,
@@ -444,5 +566,6 @@
24000,
32000,
44100,
- 48000};
-
+ 48000
+};
+#endif
diff --git a/media/libeffects/lvm/wrapper/Android.mk b/media/libeffects/lvm/wrapper/Android.mk
index efd30fb..f106aae 100644
--- a/media/libeffects/lvm/wrapper/Android.mk
+++ b/media/libeffects/lvm/wrapper/Android.mk
@@ -10,7 +10,7 @@
LOCAL_SRC_FILES:= \
Bundle/EffectBundle.cpp
-LOCAL_CFLAGS += -fvisibility=hidden
+LOCAL_CFLAGS += -fvisibility=hidden -DBUILD_FLOAT -DHIGHER_FS
LOCAL_CFLAGS += -Wall -Werror
LOCAL_MODULE:= libbundlewrapper
@@ -43,7 +43,7 @@
LOCAL_SRC_FILES:= \
Reverb/EffectReverb.cpp
-LOCAL_CFLAGS += -fvisibility=hidden
+LOCAL_CFLAGS += -fvisibility=hidden -DBUILD_FLOAT -DHIGHER_FS
LOCAL_CFLAGS += -Wall -Werror
LOCAL_MODULE:= libreverbwrapper
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 1fddf9c..aae80b6 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -14,7 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+#ifndef LVM_FLOAT
+typedef float LVM_FLOAT;
+#endif
#define LOG_TAG "Bundle"
#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array)[0])
//#define LOG_NDEBUG 0
@@ -297,7 +299,10 @@
pContext->pBundledContext->SamplesToExitCountVirt = 0;
pContext->pBundledContext->SamplesToExitCountBb = 0;
pContext->pBundledContext->SamplesToExitCountEq = 0;
-
+#ifdef BUILD_FLOAT
+ pContext->pBundledContext->pInputBuffer = NULL;
+ pContext->pBundledContext->pOutputBuffer = NULL;
+#endif
for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
pContext->pBundledContext->bandGaindB[i] = EQNB_5BandSoftPresets[i];
}
@@ -465,6 +470,14 @@
if (pContext->pBundledContext->workBuffer != NULL) {
free(pContext->pBundledContext->workBuffer);
}
+#ifdef BUILD_FLOAT
+ if (pContext->pBundledContext->pInputBuffer != NULL) {
+ free(pContext->pBundledContext->pInputBuffer);
+ }
+ if (pContext->pBundledContext->pOutputBuffer != NULL) {
+ free(pContext->pBundledContext->pOutputBuffer);
+ }
+#endif
delete pContext->pBundledContext;
pContext->pBundledContext = LVM_NULL;
}
@@ -721,7 +734,47 @@
return 0;
} /* end LvmBundle_init */
+#ifdef BUILD_FLOAT
+/**********************************************************************************
+ FUNCTION INT16LTOFLOAT
+***********************************************************************************/
+// Todo: need to write function descriptor
+static void Int16ToFloat(const LVM_INT16 *src, LVM_FLOAT *dst, size_t n) {
+ size_t ii;
+ src += n-1;
+ dst += n-1;
+ for (ii = n; ii != 0; ii--) {
+ *dst = ((LVM_FLOAT)((LVM_INT16)*src)) / 32768.0f;
+ src--;
+ dst--;
+ }
+ return;
+}
+/**********************************************************************************
+ FUNCTION FLOATTOINT16_SAT
+***********************************************************************************/
+// Todo : Need to write function descriptor
+static void FloatToInt16_SAT(const LVM_FLOAT *src, LVM_INT16 *dst, size_t n) {
+ size_t ii;
+ LVM_INT32 temp;
+ src += n-1;
+ dst += n-1;
+ for (ii = n; ii != 0; ii--) {
+ temp = (LVM_INT32)((*src) * 32768.0f);
+ if (temp >= 32767) {
+ *dst = 32767;
+ } else if (temp <= -32768) {
+ *dst = -32768;
+ } else {
+ *dst = (LVM_INT16)temp;
+ }
+ src--;
+ dst--;
+ }
+ return;
+}
+#endif
//----------------------------------------------------------------------------
// LvmBundle_process()
//----------------------------------------------------------------------------
@@ -739,7 +792,99 @@
// pOut: pointer to updated stereo 16 bit output data
//
//----------------------------------------------------------------------------
+#ifdef BUILD_FLOAT
+int LvmBundle_process(LVM_INT16 *pIn,
+ LVM_INT16 *pOut,
+ int frameCount,
+ EffectContext *pContext){
+
+ //LVM_ControlParams_t ActiveParams; /* Current control Parameters */
+ LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
+ LVM_INT16 *pOutTmp;
+ LVM_FLOAT *pInputBuff;
+ LVM_FLOAT *pOutputBuff;
+
+ if (pContext->pBundledContext->pInputBuffer == NULL ||
+ pContext->pBundledContext->frameCount < frameCount) {
+ if (pContext->pBundledContext->pInputBuffer != NULL) {
+ free(pContext->pBundledContext->pInputBuffer);
+ }
+ pContext->pBundledContext->pInputBuffer = (LVM_FLOAT *)malloc(frameCount * \
+ sizeof(LVM_FLOAT) * FCC_2);
+ }
+
+ if (pContext->pBundledContext->pOutputBuffer == NULL ||
+ pContext->pBundledContext->frameCount < frameCount) {
+ if (pContext->pBundledContext->pOutputBuffer != NULL) {
+ free(pContext->pBundledContext->pOutputBuffer);
+ }
+ pContext->pBundledContext->pOutputBuffer = (LVM_FLOAT *)malloc(frameCount * \
+ sizeof(LVM_FLOAT) * FCC_2);
+ }
+
+ if ((pContext->pBundledContext->pInputBuffer == NULL) ||
+ (pContext->pBundledContext->pOutputBuffer == NULL)) {
+ ALOGV("LVM_ERROR : LvmBundle_process memory allocation for float buffer's failed");
+ return -EINVAL;
+ }
+
+ pInputBuff = pContext->pBundledContext->pInputBuffer;
+ pOutputBuff = pContext->pBundledContext->pOutputBuffer;
+
+ if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE){
+ pOutTmp = pOut;
+ } else if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
+ if (pContext->pBundledContext->frameCount != frameCount) {
+ if (pContext->pBundledContext->workBuffer != NULL) {
+ free(pContext->pBundledContext->workBuffer);
+ }
+ pContext->pBundledContext->workBuffer =
+ (LVM_INT16 *)calloc(frameCount, sizeof(LVM_INT16) * FCC_2);
+ if (pContext->pBundledContext->workBuffer == NULL) {
+ return -ENOMEM;
+ }
+ pContext->pBundledContext->frameCount = frameCount;
+ }
+ pOutTmp = pContext->pBundledContext->workBuffer;
+ } else {
+ ALOGV("LVM_ERROR : LvmBundle_process invalid access mode");
+ return -EINVAL;
+ }
+
+ #ifdef LVM_PCM
+ fwrite(pIn, frameCount*sizeof(LVM_INT16) * FCC_2, 1, pContext->pBundledContext->PcmInPtr);
+ fflush(pContext->pBundledContext->PcmInPtr);
+ #endif
+
+ /* Converting input data from fixed point to float point */
+ Int16ToFloat(pIn, pInputBuff, frameCount * 2);
+
+ /* Process the samples */
+ LvmStatus = LVM_Process(pContext->pBundledContext->hInstance, /* Instance handle */
+ pInputBuff, /* Input buffer */
+ pOutputBuff, /* Output buffer */
+ (LVM_UINT16)frameCount, /* Number of samples to read */
+ 0); /* Audo Time */
+
+ LVM_ERROR_CHECK(LvmStatus, "LVM_Process", "LvmBundle_process")
+ if(LvmStatus != LVM_SUCCESS) return -EINVAL;
+
+ /* Converting output data from float point to fixed point */
+ FloatToInt16_SAT(pOutputBuff, pOutTmp, (LVM_UINT16)frameCount * 2);
+ #ifdef LVM_PCM
+ fwrite(pOutTmp, frameCount*sizeof(LVM_INT16) * FCC_2, 1, pContext->pBundledContext->PcmOutPtr);
+ fflush(pContext->pBundledContext->PcmOutPtr);
+ #endif
+
+ if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
+ for (int i = 0; i < frameCount * 2; i++){
+ pOut[i] = clamp16((LVM_INT32)pOut[i] + (LVM_INT32)pOutTmp[i]);
+ }
+ }
+ return 0;
+} /* end LvmBundle_process */
+#else
int LvmBundle_process(LVM_INT16 *pIn,
LVM_INT16 *pOut,
int frameCount,
@@ -797,7 +942,7 @@
}
return 0;
} /* end LvmBundle_process */
-
+#endif
//----------------------------------------------------------------------------
// EqualizerUpdateActiveParams()
@@ -866,8 +1011,12 @@
float energyBassBoost = 0;
float crossCorrection = 0;
+ bool eqEnabled = pContext->pBundledContext->bEqualizerEnabled == LVM_TRUE;
+ bool bbEnabled = pContext->pBundledContext->bBassEnabled == LVM_TRUE;
+ bool viEnabled = pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE;
+
//EQ contribution
- if (pContext->pBundledContext->bEqualizerEnabled == LVM_TRUE) {
+ if (eqEnabled) {
for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
float bandFactor = pContext->pBundledContext->bandGaindB[i]/15.0;
float bandCoefficient = LimitLevel_bandEnergyCoefficient[i];
@@ -893,35 +1042,37 @@
}
bandFactorSum -= 1.0;
if (bandFactorSum > 0)
- crossCorrection = bandFactorSum * 0.7;
+ crossCorrection = bandFactorSum * 0.7;
}
//BassBoost contribution
- if (pContext->pBundledContext->bBassEnabled == LVM_TRUE) {
+ if (bbEnabled) {
float boostFactor = (pContext->pBundledContext->BassStrengthSaved)/1000.0;
float boostCoefficient = LimitLevel_bassBoostEnergyCoefficient;
energyContribution += boostFactor * boostCoefficient * boostCoefficient;
- for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
- float bandFactor = pContext->pBundledContext->bandGaindB[i]/15.0;
- float bandCrossCoefficient = LimitLevel_bassBoostEnergyCrossCoefficient[i];
- float bandEnergy = boostFactor * bandFactor *
+ if (eqEnabled) {
+ for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
+ float bandFactor = pContext->pBundledContext->bandGaindB[i]/15.0;
+ float bandCrossCoefficient = LimitLevel_bassBoostEnergyCrossCoefficient[i];
+ float bandEnergy = boostFactor * bandFactor *
bandCrossCoefficient;
- if (bandEnergy > 0)
- energyBassBoost += bandEnergy;
+ if (bandEnergy > 0)
+ energyBassBoost += bandEnergy;
+ }
}
}
//Virtualizer contribution
- if (pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE) {
+ if (viEnabled) {
energyContribution += LimitLevel_virtualizerContribution *
LimitLevel_virtualizerContribution;
}
double totalEnergyEstimation = sqrt(energyContribution + energyCross + energyBassBoost) -
crossCorrection;
- ALOGV(" TOTAL energy estimation: %0.2f", totalEnergyEstimation);
+ ALOGV(" TOTAL energy estimation: %0.2f dB", totalEnergyEstimation);
//roundoff
int maxLevelRound = (int)(totalEnergyEstimation + 0.99);
@@ -939,6 +1090,8 @@
/* Activate the initial settings */
LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams);
LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "LvmEffect_limitLevel")
+
+ ALOGV("LVM_SetControlParameters return:%d", (int)LvmStatus);
//ALOGV("\tLvmEffect_limitLevel just Set -> %d\n",
// ActiveParams.pEQNB_BandDefinition[band].Gain);
@@ -1152,6 +1305,16 @@
SampleRate = LVM_FS_48000;
pContext->pBundledContext->SamplesPerSecond = 48000*2; // 2 secs Stereo
break;
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+ case 96000:
+ SampleRate = LVM_FS_96000;
+ pContext->pBundledContext->SamplesPerSecond = 96000*2; // 2 secs Stereo
+ break;
+ case 192000:
+ SampleRate = LVM_FS_192000;
+ pContext->pBundledContext->SamplesPerSecond = 192000*2; // 2 secs Stereo
+ break;
+#endif
default:
ALOGV("\tEffect_setConfig invalid sampling rate %d", pConfig->inputCfg.samplingRate);
return -EINVAL;
@@ -1179,6 +1342,8 @@
ALOGV("\tEffect_setConfig Succesfully called LVM_SetControlParameters\n");
pContext->pBundledContext->SampleRate = SampleRate;
+ LvmEffect_limitLevel(pContext);
+
}else{
//ALOGV("\tEffect_setConfig keep sampling rate at %d", SampleRate);
}
@@ -3669,10 +3834,10 @@
if(rightdB > maxdB){
maxdB = rightdB;
}
- //ALOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB (%d), "
+ //ALOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB, "
// "effect is %d",
//pContext->pBundledContext->SessionNo, pContext->pBundledContext->SessionId,
- //(int32_t)maxdB, maxVol<<7, pContext->EffectType);
+ //(int32_t)maxdB, pContext->EffectType);
//ALOGV("\tEFFECT_CMD_SET_VOLUME: Left is %d, Right is %d", leftVolume, rightVolume);
//ALOGV("\tEFFECT_CMD_SET_VOLUME: Left %ddB, Right %ddB, Position %ddB",
// leftdB, rightdB, pandB);
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index ee604eb..291383a 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -103,6 +103,10 @@
FILE *PcmInPtr;
FILE *PcmOutPtr;
#endif
+ #ifdef BUILD_FLOAT
+ LVM_FLOAT *pInputBuffer;
+ LVM_FLOAT *pOutputBuffer;
+ #endif
};
/* SessionContext : One session */
@@ -209,7 +213,7 @@
static const float LimitLevel_bassBoostEnergyCrossCoefficient[FIVEBAND_NUMBANDS] = {
221.21, 208.10, 28.16, 0.0, 0.0 };
-static const float LimitLevel_bassBoostEnergyCoefficient = 7.12;
+static const float LimitLevel_bassBoostEnergyCoefficient = 9.00;
static const float LimitLevel_virtualizerContribution = 1.9;
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index ec6243a..3d8e982 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -14,7 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+#ifndef LVM_FLOAT
+typedef float LVM_FLOAT;
+#endif
#define LOG_TAG "Reverb"
#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array)[0])
//#define LOG_NDEBUG 0
@@ -152,6 +154,8 @@
LVM_Fs_en SampleRate;
LVM_INT32 *InFrames32;
LVM_INT32 *OutFrames32;
+ size_t bufferSizeIn;
+ size_t bufferSizeOut;
bool auxiliary;
bool preset;
uint16_t curPreset;
@@ -172,8 +176,11 @@
#define REVERB_DEFAULT_PRESET REVERB_PRESET_NONE
-
+#ifdef BUILD_FLOAT
+#define REVERB_SEND_LEVEL 0.75f // 0.75 in 4.12 format
+#else
#define REVERB_SEND_LEVEL (0x0C00) // 0.75 in 4.12 format
+#endif
#define REVERB_UNIT_VOLUME (0x1000) // 1.0 in 4.12 format
//--- local function prototypes
@@ -270,8 +277,15 @@
// Allocate memory for reverb process (*2 is for STEREO)
- pContext->InFrames32 = (LVM_INT32 *)malloc(LVREV_MAX_FRAME_SIZE * sizeof(LVM_INT32) * 2);
- pContext->OutFrames32 = (LVM_INT32 *)malloc(LVREV_MAX_FRAME_SIZE * sizeof(LVM_INT32) * 2);
+#ifdef BUILD_FLOAT
+ pContext->bufferSizeIn = LVREV_MAX_FRAME_SIZE * sizeof(float) * 2;
+ pContext->bufferSizeOut = pContext->bufferSizeIn;
+#else
+ pContext->bufferSizeIn = LVREV_MAX_FRAME_SIZE * sizeof(LVM_INT32) * 2;
+ pContext->bufferSizeOut = pContext->bufferSizeIn;
+#endif
+ pContext->InFrames32 = (LVM_INT32 *)malloc(pContext->bufferSizeIn);
+ pContext->OutFrames32 = (LVM_INT32 *)malloc(pContext->bufferSizeOut);
ALOGV("\tEffectCreate %p, size %zu", pContext, sizeof(ReverbContext));
ALOGV("\tEffectCreate end\n");
@@ -293,6 +307,8 @@
#endif
free(pContext->InFrames32);
free(pContext->OutFrames32);
+ pContext->bufferSizeIn = 0;
+ pContext->bufferSizeOut = 0;
Reverb_free(pContext);
delete pContext;
return 0;
@@ -389,6 +405,46 @@
}
#endif
+#ifdef BUILD_FLOAT
+/**********************************************************************************
+ FUNCTION INT16LTOFLOAT
+***********************************************************************************/
+// Todo: need to write function descriptor
+static void Int16ToFloat(const LVM_INT16 *src, LVM_FLOAT *dst, size_t n) {
+ size_t ii;
+ src += n-1;
+ dst += n-1;
+ for (ii = n; ii != 0; ii--) {
+ *dst = ((LVM_FLOAT)((LVM_INT16)*src)) / 32768.0f;
+ src--;
+ dst--;
+ }
+ return;
+}
+/**********************************************************************************
+ FUNCTION FLOATTOINT16_SAT
+***********************************************************************************/
+// Todo : Need to write function descriptor
+static void FloatToInt16_SAT(const LVM_FLOAT *src, LVM_INT16 *dst, size_t n) {
+ size_t ii;
+ LVM_INT32 temp;
+
+ for (ii = 0; ii < n; ii++) {
+ temp = (LVM_INT32)((*src) * 32768.0f);
+ if (temp >= 32767) {
+ *dst = 32767;
+ } else if (temp <= -32768) {
+ *dst = -32768;
+ } else {
+ *dst = (LVM_INT16)temp;
+ }
+ src++;
+ dst++;
+ }
+ return;
+}
+#endif
+
static inline int16_t clamp16(int32_t sample)
{
if ((sample>>15) ^ (sample>>31))
@@ -422,8 +478,31 @@
LVM_INT16 samplesPerFrame = 1;
LVREV_ReturnStatus_en LvmStatus = LVREV_SUCCESS; /* Function call status */
LVM_INT16 *OutFrames16;
+#ifdef BUILD_FLOAT
+ LVM_FLOAT *pInputBuff;
+ LVM_FLOAT *pOutputBuff;
+#endif
-
+#ifdef BUILD_FLOAT
+ if (pContext->InFrames32 == NULL ||
+ pContext->bufferSizeIn < frameCount * sizeof(float) * 2) {
+ if (pContext->InFrames32 != NULL) {
+ free(pContext->InFrames32);
+ }
+ pContext->bufferSizeIn = frameCount * sizeof(float) * 2;
+ pContext->InFrames32 = (LVM_INT32 *)malloc(pContext->bufferSizeIn);
+ }
+ if (pContext->OutFrames32 == NULL ||
+ pContext->bufferSizeOut < frameCount * sizeof(float) * 2) {
+ if (pContext->OutFrames32 != NULL) {
+ free(pContext->OutFrames32);
+ }
+ pContext->bufferSizeOut = frameCount * sizeof(float) * 2;
+ pContext->OutFrames32 = (LVM_INT32 *)malloc(pContext->bufferSizeOut);
+ }
+ pInputBuff = (float *)pContext->InFrames32;
+ pOutputBuff = (float *)pContext->OutFrames32;
+#endif
// Check that the input is either mono or stereo
if (pContext->config.inputCfg.channels == AUDIO_CHANNEL_OUT_STEREO) {
samplesPerFrame = 2;
@@ -449,49 +528,84 @@
Reverb_LoadPreset(pContext);
}
-
-
// Convert to Input 32 bits
if (pContext->auxiliary) {
+#ifdef BUILD_FLOAT
+ Int16ToFloat(pIn, pInputBuff, frameCount * samplesPerFrame);
+#else
for(int i=0; i<frameCount*samplesPerFrame; i++){
pContext->InFrames32[i] = (LVM_INT32)pIn[i]<<8;
}
- } else {
+#endif
+ } else {
// insert reverb input is always stereo
for (int i = 0; i < frameCount; i++) {
+#ifndef BUILD_FLOAT
pContext->InFrames32[2*i] = (pIn[2*i] * REVERB_SEND_LEVEL) >> 4; // <<8 + >>12
pContext->InFrames32[2*i+1] = (pIn[2*i+1] * REVERB_SEND_LEVEL) >> 4; // <<8 + >>12
+#else
+ pInputBuff[2 * i] = (LVM_FLOAT)pIn[2 * i] * REVERB_SEND_LEVEL / 32768.0f;
+ pInputBuff[2 * i + 1] = (LVM_FLOAT)pIn[2 * i + 1] * REVERB_SEND_LEVEL / 32768.0f;
+#endif
}
}
if (pContext->preset && pContext->curPreset == REVERB_PRESET_NONE) {
+#ifdef BUILD_FLOAT
+ memset(pOutputBuff, 0, frameCount * sizeof(LVM_FLOAT) * 2); //always stereo here
+#else
memset(pContext->OutFrames32, 0, frameCount * sizeof(LVM_INT32) * 2); //always stereo here
+#endif
} else {
if(pContext->bEnabled == LVM_FALSE && pContext->SamplesToExitCount > 0) {
+#ifdef BUILD_FLOAT
+ memset(pInputBuff, 0, frameCount * sizeof(LVM_FLOAT) * samplesPerFrame);
+#else
memset(pContext->InFrames32,0,frameCount * sizeof(LVM_INT32) * samplesPerFrame);
+#endif
ALOGV("\tZeroing %d samples per frame at the end of call", samplesPerFrame);
}
/* Process the samples, producing a stereo output */
+#ifdef BUILD_FLOAT
+ LvmStatus = LVREV_Process(pContext->hInstance, /* Instance handle */
+ pInputBuff, /* Input buffer */
+ pOutputBuff, /* Output buffer */
+ frameCount); /* Number of samples to read */
+#else
LvmStatus = LVREV_Process(pContext->hInstance, /* Instance handle */
pContext->InFrames32, /* Input buffer */
pContext->OutFrames32, /* Output buffer */
frameCount); /* Number of samples to read */
- }
+#endif
+ }
LVM_ERROR_CHECK(LvmStatus, "LVREV_Process", "process")
if(LvmStatus != LVREV_SUCCESS) return -EINVAL;
// Convert to 16 bits
if (pContext->auxiliary) {
+#ifdef BUILD_FLOAT
+ FloatToInt16_SAT(pOutputBuff, OutFrames16, (size_t)frameCount * 2);
+#else
for (int i=0; i < frameCount*2; i++) { //always stereo here
OutFrames16[i] = clamp16(pContext->OutFrames32[i]>>8);
}
- } else {
- for (int i=0; i < frameCount*2; i++) { //always stereo here
- OutFrames16[i] = clamp16((pContext->OutFrames32[i]>>8) + (LVM_INT32)pIn[i]);
- }
+#endif
+ } else {
+#ifdef BUILD_FLOAT
+ for (int i = 0; i < frameCount * 2; i++) {//always stereo here
+ //pOutputBuff and OutFrames16 point to the same buffer, so better to
+ //accumulate in pInputBuff, which is available
+ pInputBuff[i] = pOutputBuff[i] + (LVM_FLOAT)pIn[i] / 32768.0f;
+ }
+ FloatToInt16_SAT(pInputBuff, OutFrames16, (size_t)frameCount * 2);
+#else
+ for (int i=0; i < frameCount*2; i++) { //always stereo here
+ OutFrames16[i] = clamp16((pContext->OutFrames32[i]>>8) + (LVM_INT32)pIn[i]);
+ }
+#endif
// apply volume with ramp if needed
if ((pContext->leftVolume != pContext->prevLeftVolume ||
pContext->rightVolume != pContext->prevRightVolume) &&
@@ -644,6 +758,14 @@
case 48000:
SampleRate = LVM_FS_48000;
break;
+#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
+ case 96000:
+ SampleRate = LVM_FS_96000;
+ break;
+ case 192000:
+ SampleRate = LVM_FS_192000;
+ break;
+#endif
default:
ALOGV("\rReverb_setConfig invalid sampling rate %d", pConfig->inputCfg.samplingRate);
return -EINVAL;
@@ -1011,7 +1133,7 @@
//ALOGV("\tReverbGetRoomHfLevel() ActiveParams.LPFL %d, pContext->SavedHfLevel: %d, "
// "converted level: %d\n", ActiveParams.LPF, pContext->SavedHfLevel, level);
- if(ActiveParams.LPF != level){
+ if((int16_t)ActiveParams.LPF != level){
ALOGV("\tLVM_ERROR : (ignore at start up) ReverbGetRoomHfLevel() has wrong level -> %d %d\n",
ActiveParams.Level, level);
}
diff --git a/media/libheif/Android.bp b/media/libheif/Android.bp
new file mode 100644
index 0000000..7d5a4eb
--- /dev/null
+++ b/media/libheif/Android.bp
@@ -0,0 +1,23 @@
+cc_library_shared {
+ name: "libheif",
+
+ srcs: [
+ "HeifDecoderImpl.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ "libmedia",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ include_dirs: [],
+
+ export_include_dirs: ["include"],
+}
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
new file mode 100644
index 0000000..57209e2
--- /dev/null
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2017 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 "HeifDecoderImpl"
+
+#include "HeifDecoderImpl.h"
+
+#include <stdio.h>
+
+#include <binder/IMemory.h>
+#include <drm/drm_framework_common.h>
+#include <media/IDataSource.h>
+#include <media/mediametadataretriever.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaSource.h>
+#include <private/media/VideoFrame.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+
+HeifDecoder* createHeifDecoder() {
+ return new android::HeifDecoderImpl();
+}
+
+namespace android {
+
+/*
+ * HeifDataSource
+ *
+ * Proxies data requests over IDataSource interface from MediaMetadataRetriever
+ * to the HeifStream interface we received from the heif decoder client.
+ */
+class HeifDataSource : public BnDataSource {
+public:
+ /*
+ * Constructs HeifDataSource; will take ownership of |stream|.
+ */
+ HeifDataSource(HeifStream* stream)
+ : mStream(stream), mEOS(false),
+ mCachedOffset(0), mCachedSize(0), mCacheBufferSize(0) {}
+
+ ~HeifDataSource() override {}
+
+ /*
+ * Initializes internal resources.
+ */
+ bool init();
+
+ sp<IMemory> getIMemory() override { return mMemory; }
+ ssize_t readAt(off64_t offset, size_t size) override;
+ status_t getSize(off64_t* size) override ;
+ void close() {}
+ uint32_t getFlags() override { return 0; }
+ String8 toString() override { return String8("HeifDataSource"); }
+ sp<DecryptHandle> DrmInitialization(const char*) override {
+ return nullptr;
+ }
+
+private:
+ enum {
+ /*
+ * Buffer size for passing the read data to mediaserver. Set to 64K
+ * (which is what MediaDataSource Java API's jni implementation uses).
+ */
+ kBufferSize = 64 * 1024,
+ /*
+ * Initial and max cache buffer size.
+ */
+ kInitialCacheBufferSize = 4 * 1024 * 1024,
+ kMaxCacheBufferSize = 64 * 1024 * 1024,
+ };
+ sp<IMemory> mMemory;
+ std::unique_ptr<HeifStream> mStream;
+ bool mEOS;
+ std::unique_ptr<uint8_t> mCache;
+ off64_t mCachedOffset;
+ size_t mCachedSize;
+ size_t mCacheBufferSize;
+};
+
+bool HeifDataSource::init() {
+ sp<MemoryDealer> memoryDealer =
+ new MemoryDealer(kBufferSize, "HeifDataSource");
+ mMemory = memoryDealer->allocate(kBufferSize);
+ if (mMemory == nullptr) {
+ ALOGE("Failed to allocate shared memory!");
+ return false;
+ }
+ mCache.reset(new uint8_t[kInitialCacheBufferSize]);
+ if (mCache.get() == nullptr) {
+ ALOGE("mFailed to allocate cache!");
+ return false;
+ }
+ mCacheBufferSize = kInitialCacheBufferSize;
+ return true;
+}
+
+ssize_t HeifDataSource::readAt(off64_t offset, size_t size) {
+ ALOGV("readAt: offset=%lld, size=%zu", (long long)offset, size);
+
+ if (offset < mCachedOffset) {
+ // try seek, then rewind/skip, fail if none worked
+ if (mStream->seek(offset)) {
+ ALOGV("readAt: seek to offset=%lld", (long long)offset);
+ mCachedOffset = offset;
+ mCachedSize = 0;
+ mEOS = false;
+ } else if (mStream->rewind()) {
+ ALOGV("readAt: rewind to offset=0");
+ mCachedOffset = 0;
+ mCachedSize = 0;
+ mEOS = false;
+ } else {
+ ALOGE("readAt: couldn't seek or rewind!");
+ mEOS = true;
+ }
+ }
+
+ if (mEOS && (offset < mCachedOffset ||
+ offset >= (off64_t)(mCachedOffset + mCachedSize))) {
+ ALOGV("readAt: EOS");
+ return ERROR_END_OF_STREAM;
+ }
+
+ // at this point, offset must be >= mCachedOffset, other cases should
+ // have been caught above.
+ CHECK(offset >= mCachedOffset);
+
+ off64_t resultOffset;
+ if (__builtin_add_overflow(offset, size, &resultOffset)) {
+ return ERROR_IO;
+ }
+
+ if (size == 0) {
+ return 0;
+ }
+
+ // Can only read max of kBufferSize
+ if (size > kBufferSize) {
+ size = kBufferSize;
+ }
+
+ // copy from cache if the request falls entirely in cache
+ if (offset + size <= mCachedOffset + mCachedSize) {
+ memcpy(mMemory->pointer(), mCache.get() + offset - mCachedOffset, size);
+ return size;
+ }
+
+ // need to fetch more, check if we need to expand the cache buffer.
+ if ((off64_t)(offset + size) > mCachedOffset + kMaxCacheBufferSize) {
+ // it's reaching max cache buffer size, need to roll window, and possibly
+ // expand the cache buffer.
+ size_t newCacheBufferSize = mCacheBufferSize;
+ std::unique_ptr<uint8_t> newCache;
+ uint8_t* dst = mCache.get();
+ if (newCacheBufferSize < kMaxCacheBufferSize) {
+ newCacheBufferSize = kMaxCacheBufferSize;
+ newCache.reset(new uint8_t[newCacheBufferSize]);
+ dst = newCache.get();
+ }
+
+ // when rolling the cache window, try to keep about half the old bytes
+ // in case that the client goes back.
+ off64_t newCachedOffset = offset - (off64_t)(newCacheBufferSize / 2);
+ if (newCachedOffset < mCachedOffset) {
+ newCachedOffset = mCachedOffset;
+ }
+
+ int64_t newCachedSize = (int64_t)(mCachedOffset + mCachedSize) - newCachedOffset;
+ if (newCachedSize > 0) {
+ // in this case, the new cache region partially overlop the old cache,
+ // move the portion of the cache we want to save to the beginning of
+ // the cache buffer.
+ memcpy(dst, mCache.get() + newCachedOffset - mCachedOffset, newCachedSize);
+ } else if (newCachedSize < 0){
+ // in this case, the new cache region is entirely out of the old cache,
+ // in order to guarantee sequential read, we need to skip a number of
+ // bytes before reading.
+ size_t bytesToSkip = -newCachedSize;
+ size_t bytesSkipped = mStream->read(nullptr, bytesToSkip);
+ if (bytesSkipped != bytesToSkip) {
+ // bytesSkipped is invalid, there is not enough bytes to reach
+ // the requested offset.
+ ALOGE("readAt: skip failed, EOS");
+
+ mEOS = true;
+ mCachedOffset = newCachedOffset;
+ mCachedSize = 0;
+ return ERROR_END_OF_STREAM;
+ }
+ // set cache size to 0, since we're not keeping any old cache
+ newCachedSize = 0;
+ }
+
+ if (newCache.get() != nullptr) {
+ mCache.reset(newCache.release());
+ mCacheBufferSize = newCacheBufferSize;
+ }
+ mCachedOffset = newCachedOffset;
+ mCachedSize = newCachedSize;
+
+ ALOGV("readAt: rolling cache window to (%lld, %zu), cache buffer size %zu",
+ (long long)mCachedOffset, mCachedSize, mCacheBufferSize);
+ } else {
+ // expand cache buffer, but no need to roll the window
+ size_t newCacheBufferSize = mCacheBufferSize;
+ while (offset + size > mCachedOffset + newCacheBufferSize) {
+ newCacheBufferSize *= 2;
+ }
+ CHECK(newCacheBufferSize <= kMaxCacheBufferSize);
+ if (mCacheBufferSize < newCacheBufferSize) {
+ uint8_t* newCache = new uint8_t[newCacheBufferSize];
+ memcpy(newCache, mCache.get(), mCachedSize);
+ mCache.reset(newCache);
+ mCacheBufferSize = newCacheBufferSize;
+
+ ALOGV("readAt: current cache window (%lld, %zu), new cache buffer size %zu",
+ (long long) mCachedOffset, mCachedSize, mCacheBufferSize);
+ }
+ }
+ size_t bytesToRead = offset + size - mCachedOffset - mCachedSize;
+ size_t bytesRead = mStream->read(mCache.get() + mCachedSize, bytesToRead);
+ if (bytesRead > bytesToRead || bytesRead == 0) {
+ // bytesRead is invalid
+ mEOS = true;
+ bytesRead = 0;
+ } else if (bytesRead < bytesToRead) {
+ // read some bytes but not all, set EOS
+ mEOS = true;
+ }
+ mCachedSize += bytesRead;
+ ALOGV("readAt: current cache window (%lld, %zu)",
+ (long long) mCachedOffset, mCachedSize);
+
+ // here bytesAvailable could be negative if offset jumped past EOS.
+ int64_t bytesAvailable = mCachedOffset + mCachedSize - offset;
+ if (bytesAvailable <= 0) {
+ return ERROR_END_OF_STREAM;
+ }
+ if (bytesAvailable < (int64_t)size) {
+ size = bytesAvailable;
+ }
+ memcpy(mMemory->pointer(), mCache.get() + offset - mCachedOffset, size);
+ return size;
+}
+
+status_t HeifDataSource::getSize(off64_t* size) {
+ if (!mStream->hasLength()) {
+ *size = -1;
+ ALOGE("getSize: not supported!");
+ return ERROR_UNSUPPORTED;
+ }
+ *size = mStream->getLength();
+ ALOGV("getSize: size=%lld", (long long)*size);
+ return OK;
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+HeifDecoderImpl::HeifDecoderImpl() :
+ // output color format should always be set via setOutputColor(), in case
+ // it's not, default to HAL_PIXEL_FORMAT_RGB_565.
+ mOutputColor(HAL_PIXEL_FORMAT_RGB_565),
+ mCurScanline(0),
+ mFrameDecoded(false) {
+}
+
+HeifDecoderImpl::~HeifDecoderImpl() {
+}
+
+bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) {
+ mFrameDecoded = false;
+ sp<HeifDataSource> dataSource = new HeifDataSource(stream);
+ if (!dataSource->init()) {
+ return false;
+ }
+ mDataSource = dataSource;
+
+ mRetriever = new MediaMetadataRetriever();
+ status_t err = mRetriever->setDataSource(mDataSource, "video/mp4");
+ if (err != OK) {
+ ALOGE("failed to set data source!");
+
+ mRetriever.clear();
+ mDataSource.clear();
+ return false;
+ }
+ ALOGV("successfully set data source.");
+
+ const char* hasVideo = mRetriever->extractMetadata(METADATA_KEY_HAS_VIDEO);
+ if (!hasVideo || strcasecmp(hasVideo, "yes")) {
+ ALOGE("no video: %s", hasVideo ? hasVideo : "null");
+ return false;
+ }
+
+ mFrameMemory = mRetriever->getFrameAtTime(0,
+ IMediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
+ mOutputColor, true /*metaOnly*/);
+ if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
+ ALOGE("getFrameAtTime: videoFrame is a nullptr");
+ return false;
+ }
+
+ VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
+
+ ALOGV("Meta dimension %dx%d, display %dx%d, angle %d, iccSize %d",
+ videoFrame->mWidth,
+ videoFrame->mHeight,
+ videoFrame->mDisplayWidth,
+ videoFrame->mDisplayHeight,
+ videoFrame->mRotationAngle,
+ videoFrame->mIccSize);
+
+ if (frameInfo != nullptr) {
+ frameInfo->set(
+ videoFrame->mWidth,
+ videoFrame->mHeight,
+ videoFrame->mRotationAngle,
+ videoFrame->mBytesPerPixel,
+ videoFrame->mIccSize,
+ videoFrame->getFlattenedIccData());
+ }
+ return true;
+}
+
+bool HeifDecoderImpl::getEncodedColor(HeifEncodedColor* /*outColor*/) const {
+ ALOGW("getEncodedColor: not implemented!");
+ return false;
+}
+
+bool HeifDecoderImpl::setOutputColor(HeifColorFormat heifColor) {
+ switch(heifColor) {
+ case kHeifColorFormat_RGB565:
+ {
+ mOutputColor = HAL_PIXEL_FORMAT_RGB_565;
+ return true;
+ }
+ case kHeifColorFormat_RGBA_8888:
+ {
+ mOutputColor = HAL_PIXEL_FORMAT_RGBA_8888;
+ return true;
+ }
+ case kHeifColorFormat_BGRA_8888:
+ {
+ mOutputColor = HAL_PIXEL_FORMAT_BGRA_8888;
+ return true;
+ }
+ default:
+ break;
+ }
+ ALOGE("Unsupported output color format %d", heifColor);
+ return false;
+}
+
+bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) {
+ // reset scanline pointer
+ mCurScanline = 0;
+
+ if (mFrameDecoded) {
+ return true;
+ }
+
+ mFrameMemory = mRetriever->getFrameAtTime(0,
+ IMediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor);
+ if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
+ ALOGE("getFrameAtTime: videoFrame is a nullptr");
+ return false;
+ }
+
+ VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
+ if (videoFrame->mSize == 0 ||
+ mFrameMemory->size() < videoFrame->getFlattenedSize()) {
+ ALOGE("getFrameAtTime: videoFrame size is invalid");
+ return false;
+ }
+
+ ALOGV("Decoded dimension %dx%d, display %dx%d, angle %d, rowbytes %d, size %d",
+ videoFrame->mWidth,
+ videoFrame->mHeight,
+ videoFrame->mDisplayWidth,
+ videoFrame->mDisplayHeight,
+ videoFrame->mRotationAngle,
+ videoFrame->mRowBytes,
+ videoFrame->mSize);
+
+ if (frameInfo != nullptr) {
+ frameInfo->set(
+ videoFrame->mWidth,
+ videoFrame->mHeight,
+ videoFrame->mRotationAngle,
+ videoFrame->mBytesPerPixel,
+ videoFrame->mIccSize,
+ videoFrame->getFlattenedIccData());
+ }
+ mFrameDecoded = true;
+
+ // Aggressive clear to avoid holding on to resources
+ mRetriever.clear();
+ mDataSource.clear();
+ return true;
+}
+
+bool HeifDecoderImpl::getScanline(uint8_t* dst) {
+ if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
+ return false;
+ }
+ VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
+ if (mCurScanline >= videoFrame->mHeight) {
+ ALOGE("no more scanline available");
+ return false;
+ }
+ uint8_t* src = videoFrame->getFlattenedData() + videoFrame->mRowBytes * mCurScanline++;
+ memcpy(dst, src, videoFrame->mBytesPerPixel * videoFrame->mWidth);
+ return true;
+}
+
+size_t HeifDecoderImpl::skipScanlines(size_t count) {
+ if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
+ return 0;
+ }
+ VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
+
+ uint32_t oldScanline = mCurScanline;
+ mCurScanline += count;
+ if (mCurScanline > videoFrame->mHeight) {
+ mCurScanline = videoFrame->mHeight;
+ }
+ return (mCurScanline > oldScanline) ? (mCurScanline - oldScanline) : 0;
+}
+
+} // namespace android
diff --git a/media/libheif/HeifDecoderImpl.h b/media/libheif/HeifDecoderImpl.h
new file mode 100644
index 0000000..c2e4ff3
--- /dev/null
+++ b/media/libheif/HeifDecoderImpl.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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 _HEIF_DECODER_IMPL_
+#define _HEIF_DECODER_IMPL_
+
+#include "include/HeifDecoderAPI.h"
+#include <system/graphics.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class IDataSource;
+class IMemory;
+class MediaMetadataRetriever;
+
+/*
+ * An implementation of HeifDecoder based on Android's MediaMetadataRetriever.
+ */
+class HeifDecoderImpl : public HeifDecoder {
+public:
+
+ HeifDecoderImpl();
+ ~HeifDecoderImpl() override;
+
+ bool init(HeifStream* stream, HeifFrameInfo* frameInfo) override;
+
+ bool getEncodedColor(HeifEncodedColor* outColor) const override;
+
+ bool setOutputColor(HeifColorFormat heifColor) override;
+
+ bool decode(HeifFrameInfo* frameInfo) override;
+
+ bool getScanline(uint8_t* dst) override;
+
+ size_t skipScanlines(size_t count) override;
+
+private:
+ sp<IDataSource> mDataSource;
+ sp<MediaMetadataRetriever> mRetriever;
+ sp<IMemory> mFrameMemory;
+ android_pixel_format_t mOutputColor;
+ size_t mCurScanline;
+ bool mFrameDecoded;
+};
+
+} // namespace android
+
+#endif // _HEIF_DECODER_IMPL_
diff --git a/media/libheif/include/HeifDecoderAPI.h b/media/libheif/include/HeifDecoderAPI.h
new file mode 100644
index 0000000..5183c39
--- /dev/null
+++ b/media/libheif/include/HeifDecoderAPI.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2017 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 _HEIF_DECODER_API_
+#define _HEIF_DECODER_API_
+
+#include <memory>
+
+/*
+ * The output color pixel format of heif decoder.
+ */
+typedef enum {
+ kHeifColorFormat_RGB565 = 0,
+ kHeifColorFormat_RGBA_8888 = 1,
+ kHeifColorFormat_BGRA_8888 = 2,
+} HeifColorFormat;
+
+/*
+ * The color spaces encoded in the heif image.
+ */
+typedef enum {
+ kHeifEncodedColor_RGB = 0,
+ kHeifEncodedColor_YUV = 1,
+ kHeifEncodedColor_CMYK = 2,
+} HeifEncodedColor;
+
+/*
+ * Represents a color converted (RGB-based) video frame
+ */
+struct HeifFrameInfo
+{
+ HeifFrameInfo() :
+ mWidth(0), mHeight(0), mRotationAngle(0), mBytesPerPixel(0),
+ mIccSize(0), mIccData(nullptr) {}
+
+ // update the frame info, will make a copy of |iccData| internally
+ void set(uint32_t width, uint32_t height, int32_t rotation, uint32_t bpp,
+ uint32_t iccSize, uint8_t* iccData) {
+ mWidth = width;
+ mHeight = height;
+ mRotationAngle = rotation;
+ mBytesPerPixel = bpp;
+
+ if (mIccData != nullptr) {
+ mIccData.reset(nullptr);
+ }
+ mIccSize = iccSize;
+ if (iccSize > 0) {
+ mIccData.reset(new uint8_t[iccSize]);
+ if (mIccData.get() != nullptr) {
+ memcpy(mIccData.get(), iccData, iccSize);
+ } else {
+ mIccSize = 0;
+ }
+ }
+ }
+
+ // Intentional public access modifiers:
+ uint32_t mWidth;
+ uint32_t mHeight;
+ int32_t mRotationAngle; // Rotation angle, clockwise, should be multiple of 90
+ uint32_t mBytesPerPixel; // Number of bytes for one pixel
+ uint32_t mIccSize; // Number of bytes in mIccData
+ std::unique_ptr<uint8_t> mIccData; // Actual ICC data, memory is owned by this structure
+};
+
+/*
+ * Abstract interface to provide data to HeifDecoder.
+ */
+struct HeifStream {
+ HeifStream() {}
+
+ virtual ~HeifStream() {}
+
+ /*
+ * Reads or skips size number of bytes. return the number of bytes actually
+ * read or skipped.
+ * If |buffer| == NULL, skip size bytes, return how many were skipped.
+ * If |buffer| != NULL, copy size bytes into buffer, return how many were copied.
+ */
+ virtual size_t read(void* buffer, size_t size) = 0;
+
+ /*
+ * Rewinds to the beginning of the stream. Returns true if the stream is known
+ * to be at the beginning after this call returns.
+ */
+ virtual bool rewind() = 0;
+
+ /*
+ * Seeks to an absolute position in the stream. If this cannot be done, returns false.
+ * If an attempt is made to seek past the end of the stream, the position will be set
+ * to the end of the stream.
+ */
+ virtual bool seek(size_t /*position*/) = 0;
+
+ /** Returns true if this stream can report its total length. */
+ virtual bool hasLength() const = 0;
+
+ /** Returns the total length of the stream. If this cannot be done, returns 0. */
+ virtual size_t getLength() const = 0;
+
+private:
+ HeifStream(const HeifFrameInfo&) = delete;
+ HeifStream& operator=(const HeifFrameInfo&) = delete;
+};
+
+/*
+ * Abstract interface to decode heif images from a HeifStream data source.
+ */
+struct HeifDecoder {
+ HeifDecoder() {}
+
+ virtual ~HeifDecoder() {}
+
+ /*
+ * Returns true if it successfully sets outColor to the encoded color,
+ * and false otherwise.
+ */
+ virtual bool getEncodedColor(HeifEncodedColor* outColor) const = 0;
+
+ /*
+ * Returns true if it successfully sets the output color format to color,
+ * and false otherwise.
+ */
+ virtual bool setOutputColor(HeifColorFormat color) = 0;
+
+ /*
+ * Returns true if it successfully initialize heif decoder with source,
+ * and false otherwise. |frameInfo| will be filled with information of
+ * the primary picture upon success and unmodified upon failure.
+ * Takes ownership of |stream| regardless of result.
+ */
+ virtual bool init(HeifStream* stream, HeifFrameInfo* frameInfo) = 0;
+
+ /*
+ * Decode the picture internally, returning whether it succeeded. |frameInfo|
+ * will be filled with information of the primary picture upon success and
+ * unmodified upon failure.
+ *
+ * After this succeeded, getScanline can be called to read the scanlines
+ * that were decoded.
+ */
+ virtual bool decode(HeifFrameInfo* frameInfo) = 0;
+
+ /*
+ * Read the next scanline (in top-down order), returns true upon success
+ * and false otherwise.
+ */
+ virtual bool getScanline(uint8_t* dst) = 0;
+
+ /*
+ * Skip the next |count| scanlines, returns true upon success and
+ * false otherwise.
+ */
+ virtual size_t skipScanlines(size_t count) = 0;
+
+private:
+ HeifDecoder(const HeifFrameInfo&) = delete;
+ HeifDecoder& operator=(const HeifFrameInfo&) = delete;
+};
+
+/*
+ * Creates a HeifDecoder. Returns a HeifDecoder instance upon success, or NULL
+ * if the creation has failed.
+ */
+HeifDecoder* createHeifDecoder();
+
+#endif // _HEIF_DECODER_API_
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index bbe97ee..a462f3a 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -2,11 +2,22 @@
name: "libmedia_headers",
vendor_available: true,
export_include_dirs: ["include"],
+ header_libs:[
+ "libstagefright_headers",
+ "media_plugin_headers",
+ ],
+ export_header_lib_headers: [
+ "libstagefright_headers",
+ "media_plugin_headers",
+ ],
}
cc_library {
name: "libmedia_helper",
vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
cflags: [
"-Werror",
@@ -34,6 +45,7 @@
"IMediaCodecList.cpp",
"IMediaCodecService.cpp",
"IOMX.cpp",
+ "IOMXStore.cpp",
"MediaCodecBuffer.cpp",
"MediaCodecInfo.cpp",
"MediaDefs.cpp",
@@ -69,14 +81,6 @@
"libutils",
],
- include_dirs: [
- "frameworks/av/include", // for media/vndk/xmlparser/1.0/MediaCodecsXmlParser.h
- "frameworks/av/include/media",
- "frameworks/native/include", // for media/hardware/MetadataBufferType.h
- "frameworks/native/include/media/openmax",
- "frameworks/av/media/libstagefright",
- ],
-
export_shared_lib_headers: [
"android.hidl.memory@1.0",
"android.hidl.token@1.0-utils",
@@ -120,6 +124,9 @@
cc_library_shared {
name: "libmedia_omx",
vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
defaults: ["libmedia_omx_defaults"],
}
@@ -202,6 +209,7 @@
"libicui18n",
"libsonivox",
"libmediadrm",
+ "libmedia_helper",
"android.hidl.memory@1.0",
],
@@ -210,15 +218,10 @@
"libc_malloc_debug_backtrace",
],
- include_dirs: [
- "frameworks/native/include/media/openmax",
- "frameworks/av/include/media/",
- "frameworks/av/media/libstagefright",
- ],
-
export_include_dirs: [
"include",
],
+
cflags: [
"-Werror",
"-Wno-error=deprecated-declarations",
diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp
index 3020136..990d260 100644
--- a/media/libmedia/CharacterEncodingDetector.cpp
+++ b/media/libmedia/CharacterEncodingDetector.cpp
@@ -18,15 +18,15 @@
#define LOG_TAG "CharacterEncodingDector"
#include <utils/Log.h>
-#include <CharacterEncodingDetector.h>
+#include <media/CharacterEncodingDetector.h>
#include "CharacterEncodingDetectorTables.h"
-#include "utils/Vector.h"
-#include "StringArray.h"
+#include <utils/Vector.h>
+#include <media/StringArray.h>
-#include "unicode/ucnv.h"
-#include "unicode/ucsdet.h"
-#include "unicode/ustring.h"
+#include <unicode/ucnv.h>
+#include <unicode/ucsdet.h>
+#include <unicode/ustring.h>
namespace android {
@@ -85,6 +85,8 @@
UErrorCode status = U_ZERO_ERROR;
UCharsetDetector *csd = ucsdet_open(&status);
const UCharsetMatch *ucm;
+ bool goodmatch = true;
+ int highest = 0;
// try combined detection of artist/album/title etc.
char buf[1024];
@@ -116,8 +118,6 @@
ucsdet_setText(csd, buf, strlen(buf), &status);
int32_t matches;
const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status);
- bool goodmatch = true;
- int highest = 0;
const UCharsetMatch* bestCombinedMatch = getPreferred(buf, strlen(buf),
ucma, matches, &goodmatch, &highest);
@@ -180,8 +180,24 @@
!strcmp(name, "genre") ||
!strcmp(name, "album") ||
!strcmp(name, "title"))) {
- // use encoding determined from the combination of artist/album/title etc.
- enc = combinedenc;
+ if (!goodmatch && highest < 0) {
+ // Give it one more chance if there is no good match.
+ ALOGV("Trying to detect %s separately", name);
+ int32_t matches;
+ bool goodmatchSingle = true;
+ int highestSingle = 0;
+ ucsdet_setText(csd, s, inputLength, &status);
+ const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status);
+ const UCharsetMatch* bestSingleMatch = getPreferred(s, inputLength,
+ ucma, matches, &goodmatchSingle, &highestSingle);
+ if (goodmatchSingle || highestSingle > highest)
+ enc = ucsdet_getName(bestSingleMatch, &status);
+ else
+ enc = combinedenc;
+ } else {
+ // use encoding determined from the combination of artist/album/title etc.
+ enc = combinedenc;
+ }
} else {
if (isPrintableAscii(s, inputLength)) {
enc = "UTF-8";
diff --git a/media/libmedia/IMediaCodecService.cpp b/media/libmedia/IMediaCodecService.cpp
index 2d62419..adfa93d 100644
--- a/media/libmedia/IMediaCodecService.cpp
+++ b/media/libmedia/IMediaCodecService.cpp
@@ -27,7 +27,8 @@
namespace android {
enum {
- GET_OMX = IBinder::FIRST_CALL_TRANSACTION
+ GET_OMX = IBinder::FIRST_CALL_TRANSACTION,
+ GET_OMX_STORE
};
class BpMediaCodecService : public BpInterface<IMediaCodecService>
@@ -45,6 +46,13 @@
return interface_cast<IOMX>(reply.readStrongBinder());
}
+ virtual sp<IOMXStore> getOMXStore() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaCodecService::getInterfaceDescriptor());
+ remote()->transact(GET_OMX_STORE, data, &reply);
+ return interface_cast<IOMXStore>(reply.readStrongBinder());
+ }
+
};
IMPLEMENT_META_INTERFACE(MediaCodecService, "android.media.IMediaCodecService");
@@ -62,6 +70,12 @@
reply->writeStrongBinder(IInterface::asBinder(omx));
return NO_ERROR;
}
+ case GET_OMX_STORE: {
+ CHECK_INTERFACE(IMediaCodecService, data, reply);
+ sp<IOMXStore> omxStore = getOMXStore();
+ reply->writeStrongBinder(IInterface::asBinder(omxStore));
+ return NO_ERROR;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index 4caa79e..a8a7b82 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -21,7 +21,6 @@
#include <stdint.h>
#include <sys/types.h>
-#include <android/media/ICas.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <binder/PermissionCache.h>
@@ -40,7 +39,8 @@
SETMEDIACAS,
SETUID,
NAME,
- GETMETRICS
+ GETMETRICS,
+ RELEASE,
};
class BpMediaExtractor : public BpInterface<IMediaExtractor> {
@@ -118,12 +118,12 @@
return NULL;
}
- virtual status_t setMediaCas(const sp<ICas> & cas) {
+ virtual status_t setMediaCas(const HInterfaceToken &casToken) {
ALOGV("setMediaCas");
Parcel data, reply;
data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(cas));
+ data.writeByteVector(casToken);
status_t err = remote()->transact(SETMEDIACAS, data, &reply);
if (err != NO_ERROR) {
@@ -140,6 +140,13 @@
ALOGV("name NOT IMPLEMENTED");
return NULL;
}
+
+ virtual void release() {
+ ALOGV("release");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ remote()->transact(RELEASE, data, &reply);
+ }
};
IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
@@ -207,15 +214,20 @@
ALOGV("setMediaCas");
CHECK_INTERFACE(IMediaExtractor, data, reply);
- sp<IBinder> casBinder;
- status_t err = data.readNullableStrongBinder(&casBinder);
+ HInterfaceToken casToken;
+ status_t err = data.readByteVector(&casToken);
if (err != NO_ERROR) {
- ALOGE("Error reading cas from parcel");
+ ALOGE("Error reading casToken from parcel");
return err;
}
- sp<ICas> cas = interface_cast<ICas>(casBinder);
- reply->writeInt32(setMediaCas(cas));
+ reply->writeInt32(setMediaCas(casToken));
+ return OK;
+ }
+ case RELEASE: {
+ ALOGV("release");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ release();
return OK;
}
default:
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 7058ee8..5ea2e8b 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -127,22 +127,32 @@
return reply.readInt32();
}
- status_t setDataSource(const sp<IDataSource>& source)
+ status_t setDataSource(const sp<IDataSource>& source, const char *mime)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
data.writeStrongBinder(IInterface::asBinder(source));
+
+ if (mime != NULL) {
+ data.writeInt32(1);
+ data.writeCString(mime);
+ } else {
+ data.writeInt32(0);
+ }
remote()->transact(SET_DATA_SOURCE_CALLBACK, data, &reply);
return reply.readInt32();
}
- sp<IMemory> getFrameAtTime(int64_t timeUs, int option)
+ sp<IMemory> getFrameAtTime(int64_t timeUs, int option, int colorFormat, bool metaOnly)
{
- ALOGV("getTimeAtTime: time(%" PRId64 " us) and option(%d)", timeUs, option);
+ ALOGV("getTimeAtTime: time(%" PRId64 " us), option(%d), colorFormat(%d) metaOnly(%d)",
+ timeUs, option, colorFormat, metaOnly);
Parcel data, reply;
data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
data.writeInt64(timeUs);
data.writeInt32(option);
+ data.writeInt32(colorFormat);
+ data.writeInt32(metaOnly);
#ifndef DISABLE_GROUP_SCHEDULE_HACK
sendSchedPolicy(data);
#endif
@@ -258,7 +268,12 @@
if (source == NULL) {
reply->writeInt32(BAD_VALUE);
} else {
- reply->writeInt32(setDataSource(source));
+ int32_t hasMime = data.readInt32();
+ const char *mime = NULL;
+ if (hasMime) {
+ mime = data.readCString();
+ }
+ reply->writeInt32(setDataSource(source, mime));
}
return NO_ERROR;
} break;
@@ -266,11 +281,14 @@
CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
int64_t timeUs = data.readInt64();
int option = data.readInt32();
- ALOGV("getTimeAtTime: time(%" PRId64 " us) and option(%d)", timeUs, option);
+ int colorFormat = data.readInt32();
+ bool metaOnly = (data.readInt32() != 0);
+ ALOGV("getTimeAtTime: time(%" PRId64 " us), option(%d), colorFormat(%d), metaOnly(%d)",
+ timeUs, option, colorFormat, metaOnly);
#ifndef DISABLE_GROUP_SCHEDULE_HACK
setSchedPolicy(data);
#endif
- sp<IMemory> bitmap = getFrameAtTime(timeUs, option);
+ sp<IMemory> bitmap = getFrameAtTime(timeUs, option, colorFormat, metaOnly);
if (bitmap != 0) { // Don't send NULL across the binder interface
reply->writeInt32(NO_ERROR);
reply->writeStrongBinder(IInterface::asBinder(bitmap));
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 43130eb..a073081 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -29,7 +29,7 @@
#include <utils/NativeHandle.h>
#include <gui/IGraphicBufferProducer.h>
-#include <omx/1.0/WOmxNode.h>
+#include <media/omx/1.0/WOmxNode.h>
#include <android/IGraphicBufferSource.h>
#include <android/IOMXBufferSource.h>
diff --git a/media/libmedia/IOMXStore.cpp b/media/libmedia/IOMXStore.cpp
new file mode 100644
index 0000000..4948f1a
--- /dev/null
+++ b/media/libmedia/IOMXStore.cpp
@@ -0,0 +1,367 @@
+/*
+ * 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 "IOMXStore"
+
+#include <utils/Log.h>
+
+#include <media/IOMX.h>
+#include <media/IOMXStore.h>
+#include <android/hardware/media/omx/1.0/IOmxStore.h>
+
+#include <binder/IInterface.h>
+#include <binder/IBinder.h>
+#include <binder/Parcel.h>
+
+#include <vector>
+#include <string>
+
+namespace android {
+
+namespace {
+
+enum {
+ CONNECT = IBinder::FIRST_CALL_TRANSACTION,
+ LIST_SERVICE_ATTRIBUTES,
+ GET_NODE_PREFIX,
+ LIST_ROLES,
+ GET_OMX,
+};
+
+// Forward declarations of std::vector<T> <-> Parcel conversion funcitons that
+// depend on writeToParcel() and readToParcel() for T <-> Parcel.
+
+template <typename T>
+status_t writeToParcel(const std::vector<T>& v, Parcel* p);
+
+template <typename T>
+status_t readFromParcel(std::vector<T>* v, const Parcel& p);
+
+// std::string <-> Parcel
+
+status_t writeToParcel(const std::string& s, Parcel* p) {
+ if (s.size() > INT32_MAX) {
+ return BAD_VALUE;
+ }
+ return p->writeByteArray(
+ s.size(), reinterpret_cast<const uint8_t*>(s.c_str()));
+}
+
+status_t readFromParcel(std::string* s, const Parcel& p) {
+ int32_t len;
+ status_t status = p.readInt32(&len);
+ if (status != NO_ERROR) {
+ return status;
+ } else if ((len < 0) || (static_cast<uint64_t>(len) > SIZE_MAX)) {
+ return BAD_VALUE;
+ }
+ s->resize(len);
+ if (len == 0) {
+ return NO_ERROR;
+ }
+ return p.read(static_cast<void*>(&s->front()), static_cast<size_t>(len));
+}
+
+// IOMXStore::Attribute <-> Parcel
+
+status_t writeToParcel(const IOMXStore::Attribute& a, Parcel* p) {
+ status_t status = writeToParcel(a.key, p);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return writeToParcel(a.value, p);
+}
+
+status_t readFromParcel(IOMXStore::Attribute* a, const Parcel& p) {
+ status_t status = readFromParcel(&(a->key), p);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return readFromParcel(&(a->value), p);
+}
+
+// IOMXStore::NodeInfo <-> Parcel
+
+status_t writeToParcel(const IOMXStore::NodeInfo& n, Parcel* p) {
+ status_t status = writeToParcel(n.name, p);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = writeToParcel(n.owner, p);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return writeToParcel(n.attributes, p);
+}
+
+status_t readFromParcel(IOMXStore::NodeInfo* n, const Parcel& p) {
+ status_t status = readFromParcel(&(n->name), p);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = readFromParcel(&(n->owner), p);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return readFromParcel(&(n->attributes), p);
+}
+
+// IOMXStore::RoleInfo <-> Parcel
+
+status_t writeToParcel(const IOMXStore::RoleInfo& r, Parcel* p) {
+ status_t status = writeToParcel(r.role, p);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = writeToParcel(r.type, p);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = p->writeBool(r.isEncoder);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = p->writeBool(r.preferPlatformNodes);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return writeToParcel(r.nodes, p);
+}
+
+status_t readFromParcel(IOMXStore::RoleInfo* r, const Parcel& p) {
+ status_t status = readFromParcel(&(r->role), p);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = readFromParcel(&(r->type), p);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = p.readBool(&(r->isEncoder));
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = p.readBool(&(r->preferPlatformNodes));
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return readFromParcel(&(r->nodes), p);
+}
+
+// std::vector<NodeInfo> <-> Parcel
+// std::vector<RoleInfo> <-> Parcel
+
+template <typename T>
+status_t writeToParcel(const std::vector<T>& v, Parcel* p) {
+ status_t status = p->writeVectorSize(v);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ for (const T& x : v) {
+ status = writeToParcel(x, p);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+template <typename T>
+status_t readFromParcel(std::vector<T>* v, const Parcel& p) {
+ status_t status = p.resizeOutVector(v);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ for (T& x : *v) {
+ status = readFromParcel(&x, p);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+} // unnamed namespace
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BpOMXStore : public BpInterface<IOMXStore> {
+public:
+ explicit BpOMXStore(const sp<IBinder> &impl)
+ : BpInterface<IOMXStore>(impl) {
+ }
+
+ status_t listServiceAttributes(
+ std::vector<Attribute>* attributes) override {
+ Parcel data, reply;
+ status_t status;
+ status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = remote()->transact(LIST_SERVICE_ATTRIBUTES, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return readFromParcel(attributes, reply);
+ }
+
+ status_t getNodePrefix(std::string* prefix) override {
+ Parcel data, reply;
+ status_t status;
+ status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = remote()->transact(GET_NODE_PREFIX, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return readFromParcel(prefix, reply);
+ }
+
+ status_t listRoles(std::vector<RoleInfo>* roleList) override {
+ Parcel data, reply;
+ status_t status;
+ status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = remote()->transact(LIST_ROLES, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return readFromParcel(roleList, reply);
+ }
+
+ status_t getOmx(const std::string& name, sp<IOMX>* omx) override {
+ Parcel data, reply;
+ status_t status;
+ status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = writeToParcel(name, &data);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = remote()->transact(GET_OMX, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return reply.readStrongBinder(omx);
+ }
+
+};
+
+IMPLEMENT_META_INTERFACE(OMXStore, "android.hardware.IOMXStore");
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define CHECK_OMX_INTERFACE(interface, data, reply) \
+ do { if (!(data).enforceInterface(interface::getInterfaceDescriptor())) { \
+ ALOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnOMXStore::onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+ switch (code) {
+ case LIST_SERVICE_ATTRIBUTES: {
+ CHECK_OMX_INTERFACE(IOMXStore, data, reply);
+ status_t status;
+ std::vector<Attribute> attributes;
+
+ status = listServiceAttributes(&attributes);
+ if (status != NO_ERROR) {
+ ALOGE("listServiceAttributes() fails with status %d",
+ static_cast<int>(status));
+ return NO_ERROR;
+ }
+ status = writeToParcel(attributes, reply);
+ if (status != NO_ERROR) {
+ ALOGE("listServiceAttributes() fails to send reply");
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+ }
+ case GET_NODE_PREFIX: {
+ CHECK_OMX_INTERFACE(IOMXStore, data, reply);
+ status_t status;
+ std::string prefix;
+
+ status = getNodePrefix(&prefix);
+ if (status != NO_ERROR) {
+ ALOGE("getNodePrefix() fails with status %d",
+ static_cast<int>(status));
+ return NO_ERROR;
+ }
+ status = writeToParcel(prefix, reply);
+ if (status != NO_ERROR) {
+ ALOGE("getNodePrefix() fails to send reply");
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+ }
+ case LIST_ROLES: {
+ CHECK_OMX_INTERFACE(IOMXStore, data, reply);
+ status_t status;
+ std::vector<RoleInfo> roleList;
+
+ status = listRoles(&roleList);
+ if (status != NO_ERROR) {
+ ALOGE("listRoles() fails with status %d",
+ static_cast<int>(status));
+ return NO_ERROR;
+ }
+ status = writeToParcel(roleList, reply);
+ if (status != NO_ERROR) {
+ ALOGE("listRoles() fails to send reply");
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+ }
+ case GET_OMX: {
+ CHECK_OMX_INTERFACE(IOMXStore, data, reply);
+ status_t status;
+ std::string name;
+ sp<IOMX> omx;
+
+ status = readFromParcel(&name, data);
+ if (status != NO_ERROR) {
+ ALOGE("getOmx() fails to retrieve name");
+ return NO_ERROR;
+ }
+ status = getOmx(name, &omx);
+ if (status != NO_ERROR) {
+ ALOGE("getOmx() fails with status %d",
+ static_cast<int>(status));
+ return NO_ERROR;
+ }
+ status = reply->writeStrongBinder(IInterface::asBinder(omx));
+ if (status != NO_ERROR) {
+ ALOGE("getOmx() fails to send reply");
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+} // namespace android
diff --git a/media/libmedia/IResourceManagerService.cpp b/media/libmedia/IResourceManagerService.cpp
index 95f7d2e..9724fc1 100644
--- a/media/libmedia/IResourceManagerService.cpp
+++ b/media/libmedia/IResourceManagerService.cpp
@@ -19,7 +19,7 @@
#define LOG_TAG "IResourceManagerService"
#include <utils/Log.h>
-#include "media/IResourceManagerService.h"
+#include <media/IResourceManagerService.h>
#include <binder/Parcel.h>
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index 1f188f3..a570ffe 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -101,36 +101,46 @@
return OK;
}
-void MediaCodecInfo::CapabilitiesBuilder::addProfileLevel(uint32_t profile, uint32_t level) {
+void MediaCodecInfo::CapabilitiesWriter::addDetail(
+ const char* key, const char* value) {
+ mCap->mDetails->setString(key, value);
+}
+
+void MediaCodecInfo::CapabilitiesWriter::addDetail(
+ const char* key, int32_t value) {
+ mCap->mDetails->setInt32(key, value);
+}
+
+void MediaCodecInfo::CapabilitiesWriter::addProfileLevel(
+ uint32_t profile, uint32_t level) {
ProfileLevel profileLevel;
profileLevel.mProfile = profile;
profileLevel.mLevel = level;
- mProfileLevels.push_back(profileLevel);
+ if (mCap->mProfileLevelsSorted.indexOf(profileLevel) < 0) {
+ mCap->mProfileLevels.push_back(profileLevel);
+ mCap->mProfileLevelsSorted.add(profileLevel);
+ }
}
-void MediaCodecInfo::CapabilitiesBuilder::addColorFormat(uint32_t format) {
- mColorFormats.push(format);
+void MediaCodecInfo::CapabilitiesWriter::addColorFormat(uint32_t format) {
+ if (mCap->mColorFormatsSorted.indexOf(format) < 0) {
+ mCap->mColorFormats.push(format);
+ mCap->mColorFormatsSorted.add(format);
+ }
}
-void MediaCodecInfo::CapabilitiesBuilder::addFlags(uint32_t flags) {
- mFlags |= flags;
+void MediaCodecInfo::CapabilitiesWriter::addFlags(uint32_t flags) {
+ mCap->mFlags |= flags;
+}
+
+MediaCodecInfo::CapabilitiesWriter::CapabilitiesWriter(
+ MediaCodecInfo::Capabilities* cap) : mCap(cap) {
}
bool MediaCodecInfo::isEncoder() const {
return mIsEncoder;
}
-bool MediaCodecInfo::hasQuirk(const char *name) const {
- if (name) {
- for (size_t ix = 0; ix < mQuirks.size(); ix++) {
- if (mQuirks.itemAt(ix).equalsIgnoreCase(name)) {
- return true;
- }
- }
- }
- return false;
-}
-
void MediaCodecInfo::getSupportedMimes(Vector<AString> *mimes) const {
mimes->clear();
for (size_t ix = 0; ix < mCaps.size(); ix++) {
@@ -151,20 +161,21 @@
return mName.c_str();
}
+const char *MediaCodecInfo::getOwnerName() const {
+ return mOwner.c_str();
+}
+
// static
sp<MediaCodecInfo> MediaCodecInfo::FromParcel(const Parcel &parcel) {
AString name = AString::FromParcel(parcel);
+ AString owner = AString::FromParcel(parcel);
bool isEncoder = static_cast<bool>(parcel.readInt32());
- sp<MediaCodecInfo> info = new MediaCodecInfo(name, isEncoder, NULL);
+ sp<MediaCodecInfo> info = new MediaCodecInfo;
+ info->mName = name;
+ info->mOwner = owner;
+ info->mIsEncoder = isEncoder;
size_t size = static_cast<size_t>(parcel.readInt32());
for (size_t i = 0; i < size; i++) {
- AString quirk = AString::FromParcel(parcel);
- if (info != NULL) {
- info->mQuirks.push_back(quirk);
- }
- }
- size = static_cast<size_t>(parcel.readInt32());
- for (size_t i = 0; i < size; i++) {
AString mime = AString::FromParcel(parcel);
sp<Capabilities> caps = Capabilities::FromParcel(parcel);
if (caps == NULL)
@@ -178,11 +189,8 @@
status_t MediaCodecInfo::writeToParcel(Parcel *parcel) const {
mName.writeToParcel(parcel);
+ mOwner.writeToParcel(parcel);
parcel->writeInt32(mIsEncoder);
- parcel->writeInt32(mQuirks.size());
- for (size_t i = 0; i < mQuirks.size(); i++) {
- mQuirks.itemAt(i).writeToParcel(parcel);
- }
parcel->writeInt32(mCaps.size());
for (size_t i = 0; i < mCaps.size(); i++) {
mCaps.keyAt(i).writeToParcel(parcel);
@@ -202,86 +210,46 @@
return -1;
}
-MediaCodecInfo::MediaCodecInfo(AString name, bool encoder, const char *mime)
- : mName(name),
- mIsEncoder(encoder),
- mHasSoleMime(false) {
- if (mime != NULL) {
- addMime(mime);
- mHasSoleMime = true;
- }
+MediaCodecInfo::MediaCodecInfo() {
}
-status_t MediaCodecInfo::addMime(const char *mime) {
- if (mHasSoleMime) {
- ALOGE("Codec '%s' already had its type specified", mName.c_str());
- return -EINVAL;
- }
- ssize_t ix = getCapabilityIndex(mime);
+void MediaCodecInfoWriter::setName(const char* name) {
+ mInfo->mName = name;
+}
+
+void MediaCodecInfoWriter::setOwner(const char* owner) {
+ mInfo->mOwner = owner;
+}
+
+void MediaCodecInfoWriter::setEncoder(bool isEncoder) {
+ mInfo->mIsEncoder = isEncoder;
+}
+
+std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>
+ MediaCodecInfoWriter::addMime(const char *mime) {
+ ssize_t ix = mInfo->getCapabilityIndex(mime);
if (ix >= 0) {
- mCurrentCaps = mCaps.valueAt(ix);
- } else {
- mCurrentCaps = new Capabilities();
- mCaps.add(AString(mime), mCurrentCaps);
+ return std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>(
+ new MediaCodecInfo::CapabilitiesWriter(
+ mInfo->mCaps.valueAt(ix).get()));
}
- return OK;
+ sp<MediaCodecInfo::Capabilities> caps = new MediaCodecInfo::Capabilities();
+ mInfo->mCaps.add(AString(mime), caps);
+ return std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>(
+ new MediaCodecInfo::CapabilitiesWriter(caps.get()));
}
-status_t MediaCodecInfo::updateMime(const char *mime) {
- ssize_t ix = getCapabilityIndex(mime);
- if (ix < 0) {
- ALOGE("updateMime mime not found %s", mime);
- return -EINVAL;
- }
-
- mCurrentCaps = mCaps.valueAt(ix);
- return OK;
-}
-
-void MediaCodecInfo::removeMime(const char *mime) {
- ssize_t ix = getCapabilityIndex(mime);
+bool MediaCodecInfoWriter::removeMime(const char *mime) {
+ ssize_t ix = mInfo->getCapabilityIndex(mime);
if (ix >= 0) {
- mCaps.removeItemsAt(ix);
- // mCurrentCaps will be removed when completed
+ mInfo->mCaps.removeItemsAt(ix);
+ return true;
}
+ return false;
}
-status_t MediaCodecInfo::initializeCapabilities(const sp<Capabilities> &caps) {
- // TRICKY: copy data to mCurrentCaps as it is a reference to
- // an element of the capabilites map.
- mCurrentCaps->mColorFormats.clear();
- mCurrentCaps->mColorFormats.appendVector(caps->mColorFormats);
- mCurrentCaps->mProfileLevels.clear();
- mCurrentCaps->mProfileLevels.appendVector(caps->mProfileLevels);
- mCurrentCaps->mFlags = caps->mFlags;
- mCurrentCaps->mDetails = caps->mDetails;
- return OK;
-}
-
-void MediaCodecInfo::addQuirk(const char *name) {
- if (!hasQuirk(name)) {
- mQuirks.push(name);
- }
-}
-
-void MediaCodecInfo::complete() {
- mCurrentCaps = NULL;
-}
-
-void MediaCodecInfo::addDetail(const AString &key, const AString &value) {
- mCurrentCaps->mDetails->setString(key.c_str(), value.c_str());
-}
-
-void MediaCodecInfo::addFeature(const AString &key, int32_t value) {
- AString tag = "feature-";
- tag.append(key);
- mCurrentCaps->mDetails->setInt32(tag.c_str(), value);
-}
-
-void MediaCodecInfo::addFeature(const AString &key, const char *value) {
- AString tag = "feature-";
- tag.append(key);
- mCurrentCaps->mDetails->setString(tag.c_str(), value);
+MediaCodecInfoWriter::MediaCodecInfoWriter(MediaCodecInfo* info) :
+ mInfo(info) {
}
} // namespace android
diff --git a/media/libmedia/MediaScannerClient.cpp b/media/libmedia/MediaScannerClient.cpp
index 9f803cb..028616b 100644
--- a/media/libmedia/MediaScannerClient.cpp
+++ b/media/libmedia/MediaScannerClient.cpp
@@ -20,8 +20,8 @@
#include <media/mediascanner.h>
-#include "CharacterEncodingDetector.h"
-#include "StringArray.h"
+#include <media/CharacterEncodingDetector.h>
+#include <media/StringArray.h>
namespace android {
diff --git a/media/libmedia/MediaUtils.cpp b/media/libmedia/MediaUtils.cpp
index dc2bc82..bcdc3bd 100644
--- a/media/libmedia/MediaUtils.cpp
+++ b/media/libmedia/MediaUtils.cpp
@@ -24,6 +24,8 @@
#include "MediaUtils.h"
+extern "C" size_t __cfi_shadow_size();
+
namespace android {
void limitProcessMemory(
@@ -62,6 +64,19 @@
if (propVal > 0 && uint64_t(propVal) <= SIZE_MAX) {
maxMem = propVal;
}
+
+ // Increase by the size of the CFI shadow mapping. Most of the shadow is not
+ // backed with physical pages, and it is possible for the result to be
+ // higher than total physical memory. This is fine for RLIMIT_AS.
+ size_t cfi_size = __cfi_shadow_size();
+ if (cfi_size) {
+ ALOGV("cfi shadow size: %zu", cfi_size);
+ if (maxMem <= SIZE_MAX - cfi_size) {
+ maxMem += cfi_size;
+ } else {
+ maxMem = SIZE_MAX;
+ }
+ }
ALOGV("actual limit: %zu", maxMem);
struct rlimit limit;
diff --git a/media/libmedia/MidiDeviceInfo.cpp b/media/libmedia/MidiDeviceInfo.cpp
index 02efc5f..7588e00 100644
--- a/media/libmedia/MidiDeviceInfo.cpp
+++ b/media/libmedia/MidiDeviceInfo.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "MidiDeviceInfo"
-#include "MidiDeviceInfo.h"
+#include <media/MidiDeviceInfo.h>
#include <binder/Parcel.h>
#include <log/log.h>
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index faae954..4e5d67f 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -22,7 +22,7 @@
#include <sys/stat.h>
#include <fcntl.h>
-#include "media/MidiIoWrapper.h"
+#include <media/MidiIoWrapper.h>
static int readAt(void *handle, void *buffer, int pos, int size) {
return ((android::MidiIoWrapper*)handle)->readAt(buffer, pos, size);
diff --git a/media/libmedia/StringArray.cpp b/media/libmedia/StringArray.cpp
index b2e5907..7868b85 100644
--- a/media/libmedia/StringArray.cpp
+++ b/media/libmedia/StringArray.cpp
@@ -21,7 +21,7 @@
#include <stdlib.h>
#include <string.h>
-#include "StringArray.h"
+#include <media/StringArray.h>
namespace android {
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmedia/TypeConverter.cpp
index a6eba86..e6c8f9c 100644
--- a/media/libmedia/TypeConverter.cpp
+++ b/media/libmedia/TypeConverter.cpp
@@ -375,7 +375,7 @@
audio_channel_mask_t channelMaskFromString(const std::string &literalChannels)
{
audio_channel_mask_t channels;
- if (!OutputChannelConverter::fromString(literalChannels, channels) ||
+ if (!OutputChannelConverter::fromString(literalChannels, channels) &&
!InputChannelConverter::fromString(literalChannels, channels)) {
return AUDIO_CHANNEL_INVALID;
}
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
index e031765..5d25e4d 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/media/libmedia/include/media/DrmHal.h
@@ -39,6 +39,11 @@
struct DrmSessionClientInterface;
+inline bool operator==(const Vector<uint8_t> &l, const Vector<uint8_t> &r) {
+ if (l.size() != r.size()) return false;
+ return memcmp(l.array(), r.array(), l.size()) == 0;
+}
+
struct DrmHal : public BnDrm,
public IBinder::DeathRecipient,
public IDrmPluginListener {
@@ -161,6 +166,9 @@
const Vector<sp<IDrmFactory>> mFactories;
sp<IDrmPlugin> mPlugin;
+ Vector<Vector<uint8_t>> mOpenSessions;
+ void closeOpenSessions();
+
/**
* mInitCheck is:
* NO_INIT if a plugin hasn't been created yet
@@ -175,6 +183,11 @@
void writeByteArray(Parcel &obj, const hidl_vec<uint8_t>& array);
+ void reportMetrics() const;
+ status_t getPropertyStringInternal(String8 const &name, String8 &value) const;
+ status_t getPropertyByteArrayInternal(String8 const &name,
+ Vector<uint8_t> &value) const;
+
DISALLOW_EVIL_CONSTRUCTORS(DrmHal);
};
diff --git a/media/libmedia/include/media/IDataSource.h b/media/libmedia/include/media/IDataSource.h
index 655f337..3858f78 100644
--- a/media/libmedia/include/media/IDataSource.h
+++ b/media/libmedia/include/media/IDataSource.h
@@ -35,7 +35,9 @@
// Get the memory that readAt writes into.
virtual sp<IMemory> getIMemory() = 0;
// Read up to |size| bytes into the memory returned by getIMemory(). Returns
- // the number of bytes read, or -1 on error. |size| must not be larger than
+ // the number of bytes read, or negative value on error (eg.
+ // ERROR_END_OF_STREAM indicating EOS. This is needed by CallbackDataSource
+ // to properly handle reading of last chunk). |size| must not be larger than
// the buffer.
virtual ssize_t readAt(off64_t offset, size_t size) = 0;
// Get the size, or -1 if the size is unknown.
diff --git a/media/libmedia/include/media/IMediaCodecService.h b/media/libmedia/include/media/IMediaCodecService.h
index da3c5a03..59fb1c0 100644
--- a/media/libmedia/include/media/IMediaCodecService.h
+++ b/media/libmedia/include/media/IMediaCodecService.h
@@ -22,6 +22,7 @@
#include <binder/Parcel.h>
#include <media/IDataSource.h>
#include <media/IOMX.h>
+#include <media/IOMXStore.h>
namespace android {
@@ -31,6 +32,7 @@
DECLARE_META_INTERFACE(MediaCodecService);
virtual sp<IOMX> getOMX() = 0;
+ virtual sp<IOMXStore> getOMXStore() = 0;
};
class BnMediaCodecService: public BnInterface<IMediaCodecService>
diff --git a/media/libmedia/include/media/IMediaExtractor.h b/media/libmedia/include/media/IMediaExtractor.h
index ab40f53..0ac7673 100644
--- a/media/libmedia/include/media/IMediaExtractor.h
+++ b/media/libmedia/include/media/IMediaExtractor.h
@@ -20,14 +20,12 @@
#include <media/IMediaSource.h>
#include <media/stagefright/DataSource.h>
+#include <vector>
namespace android {
class MetaData;
-namespace media {
-class ICas;
-};
-using namespace media;
+typedef std::vector<uint8_t> HInterfaceToken;
class IMediaExtractor : public IInterface {
public:
@@ -65,11 +63,13 @@
// for DRM
virtual char* getDrmTrackInfo(size_t trackID, int *len) = 0;
- virtual status_t setMediaCas(const sp<ICas> &cas) = 0;
+ virtual status_t setMediaCas(const HInterfaceToken &casToken) = 0;
virtual void setUID(uid_t uid) = 0;
virtual const char * name() = 0;
+
+ virtual void release() = 0;
};
diff --git a/media/libmedia/include/media/IMediaMetadataRetriever.h b/media/libmedia/include/media/IMediaMetadataRetriever.h
index c90f254..ea95161 100644
--- a/media/libmedia/include/media/IMediaMetadataRetriever.h
+++ b/media/libmedia/include/media/IMediaMetadataRetriever.h
@@ -19,13 +19,12 @@
#define ANDROID_IMEDIAMETADATARETRIEVER_H
#include <binder/IInterface.h>
-#include <binder/Parcel.h>
#include <binder/IMemory.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
namespace android {
-
+class Parcel;
class IDataSource;
struct IMediaHTTPService;
@@ -41,8 +40,10 @@
const KeyedVector<String8, String8> *headers = NULL) = 0;
virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0;
- virtual status_t setDataSource(const sp<IDataSource>& dataSource) = 0;
- virtual sp<IMemory> getFrameAtTime(int64_t timeUs, int option) = 0;
+ virtual status_t setDataSource(
+ const sp<IDataSource>& dataSource, const char *mime) = 0;
+ virtual sp<IMemory> getFrameAtTime(
+ int64_t timeUs, int option, int colorFormat, bool metaOnly) = 0;
virtual sp<IMemory> extractAlbumArt() = 0;
virtual const char* extractMetadata(int keyCode) = 0;
};
diff --git a/media/libmedia/include/media/IOMX.h b/media/libmedia/include/media/IOMX.h
index 9a0ada1..e69c02d 100644
--- a/media/libmedia/include/media/IOMX.h
+++ b/media/libmedia/include/media/IOMX.h
@@ -29,8 +29,9 @@
#include <media/hardware/MetadataBufferType.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
-#include <OMX_Core.h>
-#include <OMX_Video.h>
+#include <media/openmax/OMX_Core.h>
+#include <media/openmax/OMX_Video.h>
+#include <media/openmax/OMX_VideoExt.h>
namespace android {
diff --git a/media/libmedia/include/media/IOMXStore.h b/media/libmedia/include/media/IOMXStore.h
new file mode 100644
index 0000000..628db70
--- /dev/null
+++ b/media/libmedia/include/media/IOMXStore.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_IOMXSTORE_H_
+
+#define ANDROID_IOMXSTORE_H_
+
+#include <media/IOMX.h>
+#include <android/hardware/media/omx/1.0/IOmxStore.h>
+
+#include <binder/IInterface.h>
+#include <binder/IBinder.h>
+
+#include <vector>
+#include <string>
+
+namespace android {
+
+using hardware::media::omx::V1_0::IOmxStore;
+
+class IOMXStore : public IInterface {
+public:
+ DECLARE_META_INTERFACE(OMXStore);
+
+ struct Attribute {
+ std::string key;
+ std::string value;
+ };
+
+ struct NodeInfo {
+ std::string name;
+ std::string owner;
+ std::vector<Attribute> attributes;
+ };
+
+ struct RoleInfo {
+ std::string role;
+ std::string type;
+ bool isEncoder;
+ bool preferPlatformNodes;
+ std::vector<NodeInfo> nodes;
+ };
+
+ virtual status_t listServiceAttributes(
+ std::vector<Attribute>* attributes) = 0;
+
+ virtual status_t getNodePrefix(std::string* prefix) = 0;
+
+ virtual status_t listRoles(std::vector<RoleInfo>* roleList) = 0;
+
+ virtual status_t getOmx(const std::string& name, sp<IOMX>* omx) = 0;
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BnOMXStore : public BnInterface<IOMXStore> {
+public:
+ virtual status_t onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply,
+ uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // ANDROID_IOMX_H_
diff --git a/media/libmedia/include/media/MediaCodecInfo.h b/media/libmedia/include/media/MediaCodecInfo.h
index 6b50f22..ab2cd24 100644
--- a/media/libmedia/include/media/MediaCodecInfo.h
+++ b/media/libmedia/include/media/MediaCodecInfo.h
@@ -18,6 +18,7 @@
#define MEDIA_CODEC_INFO_H_
+#include <android-base/macros.h>
#include <binder/Parcel.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AString.h>
@@ -36,12 +37,20 @@
typedef KeyedVector<AString, AString> CodecSettings;
+struct MediaCodecInfoWriter;
+struct MediaCodecListWriter;
+
struct MediaCodecInfo : public RefBase {
struct ProfileLevel {
uint32_t mProfile;
uint32_t mLevel;
+ bool operator <(const ProfileLevel &o) const {
+ return mProfile < o.mProfile || (mProfile == o.mProfile && mLevel < o.mLevel);
+ }
};
+ struct CapabilitiesWriter;
+
struct Capabilities : public RefBase {
enum {
// decoder flags
@@ -61,7 +70,9 @@
protected:
Vector<ProfileLevel> mProfileLevels;
+ SortedVector<ProfileLevel> mProfileLevelsSorted;
Vector<uint32_t> mColorFormats;
+ SortedVector<uint32_t> mColorFormatsSorted;
uint32_t mFlags;
sp<AMessage> mDetails;
@@ -72,72 +83,191 @@
static sp<Capabilities> FromParcel(const Parcel &parcel);
status_t writeToParcel(Parcel *parcel) const;
- DISALLOW_EVIL_CONSTRUCTORS(Capabilities);
+ DISALLOW_COPY_AND_ASSIGN(Capabilities);
friend struct MediaCodecInfo;
+ friend struct MediaCodecInfoWriter;
+ friend struct CapabilitiesWriter;
};
- // Use a subclass to allow setting fields on construction without allowing
- // to do the same throughout the framework.
- struct CapabilitiesBuilder : public Capabilities {
+ /**
+ * This class is used for modifying information inside a `Capabilities`
+ * object. An object of type `CapabilitiesWriter` can be obtained by calling
+ * `MediaCodecInfoWriter::addMime()` or
+ * `MediaCodecInfoWriter::updateMime()`.
+ */
+ struct CapabilitiesWriter {
+ /**
+ * Add a key-value pair to the list of details. If the key already
+ * exists, the old value will be replaced.
+ *
+ * A pair added by this function will be accessible by
+ * `Capabilities::getDetails()`. Call `AMessage::getString()` with the
+ * same key to retrieve the value.
+ *
+ * @param key The key.
+ * @param value The string value.
+ */
+ void addDetail(const char* key, const char* value);
+ /**
+ * Add a key-value pair to the list of details. If the key already
+ * exists, the old value will be replaced.
+ *
+ * A pair added by this function will be accessible by
+ * `Capabilities::getDetails()`. Call `AMessage::getInt32()` with the
+ * same key to retrieve the value.
+ *
+ * @param key The key.
+ * @param value The `int32_t` value.
+ */
+ void addDetail(const char* key, int32_t value);
+ /**
+ * Add a profile-level pair. If this profile-level pair already exists,
+ * it will be ignored.
+ *
+ * @param profile The "profile" component.
+ * @param level The "level" component.
+ */
void addProfileLevel(uint32_t profile, uint32_t level);
+ /**
+ * Add a color format. If this color format already exists, it will be
+ * ignored.
+ *
+ * @param format The color format.
+ */
void addColorFormat(uint32_t format);
+ /**
+ * Add flags. The underlying operation is bitwise-or. In other words,
+ * bits that have already been set will be ignored.
+ *
+ * @param flags The additional flags.
+ */
void addFlags(uint32_t flags);
+ private:
+ /**
+ * The associated `Capabilities` object.
+ */
+ Capabilities* mCap;
+ /**
+ * Construct a writer for the given `Capabilities` object.
+ *
+ * @param cap The `Capabilities` object to be written to.
+ */
+ CapabilitiesWriter(Capabilities* cap);
+
+ friend MediaCodecInfoWriter;
};
bool isEncoder() const;
- bool hasQuirk(const char *name) const;
void getSupportedMimes(Vector<AString> *mimes) const;
const sp<Capabilities> getCapabilitiesFor(const char *mime) const;
const char *getCodecName() const;
/**
+ * Return the name of the service that hosts the codec. This value is not
+ * visible at the Java level.
+ *
+ * Currently, this is the "instance name" of the IOmx service.
+ */
+ const char *getOwnerName() const;
+
+ /**
* Serialization over Binder
*/
static sp<MediaCodecInfo> FromParcel(const Parcel &parcel);
status_t writeToParcel(Parcel *parcel) const;
private:
- // variable set only in constructor - these are accessed by MediaCodecList
- // to avoid duplication of same variables
AString mName;
+ AString mOwner;
bool mIsEncoder;
- bool mHasSoleMime; // was initialized with mime
-
- Vector<AString> mQuirks;
KeyedVector<AString, sp<Capabilities> > mCaps;
- sp<Capabilities> mCurrentCaps; // currently initalized capabilities
-
ssize_t getCapabilityIndex(const char *mime) const;
- /* Methods used by MediaCodecList to construct the info
- * object from XML.
- *
- * After info object is created:
- * - additional quirks can be added
- * - additional mimes can be added
- * - OMX codec capabilities can be set for the current mime-type
- * - a capability detail can be set for the current mime-type
- * - a feature can be set for the current mime-type
- * - info object can be completed when parsing of a mime-type is done
+ /**
+ * Construct an `MediaCodecInfo` object. After the construction, its
+ * information can be set via an `MediaCodecInfoWriter` object obtained from
+ * `MediaCodecListWriter::addMediaCodecInfo()`.
*/
- MediaCodecInfo(AString name, bool encoder, const char *mime);
- void addQuirk(const char *name);
- status_t addMime(const char *mime);
- status_t updateMime(const char *mime);
+ MediaCodecInfo();
- status_t initializeCapabilities(const sp<Capabilities> &caps);
- void addDetail(const AString &key, const AString &value);
- void addFeature(const AString &key, int32_t value);
- void addFeature(const AString &key, const char *value);
- void removeMime(const char *mime);
- void complete();
+ DISALLOW_COPY_AND_ASSIGN(MediaCodecInfo);
- DISALLOW_EVIL_CONSTRUCTORS(MediaCodecInfo);
-
- friend struct MediaCodecList;
friend class MediaCodecListOverridesTest;
+ friend struct MediaCodecInfoWriter;
+ friend struct MediaCodecListWriter;
+};
+
+/**
+ * This class is to be used by a `MediaCodecListBuilderBase` instance to
+ * populate information inside the associated `MediaCodecInfo` object.
+ *
+ * The only place where an instance of `MediaCodecInfoWriter` can be constructed
+ * is `MediaCodecListWriter::addMediaCodecInfo()`. A `MediaCodecListBuilderBase`
+ * instance should call `MediaCodecListWriter::addMediaCodecInfo()` on the given
+ * `MediaCodecListWriter` object given as an input to
+ * `MediaCodecListBuilderBase::buildMediaCodecList()`.
+ */
+struct MediaCodecInfoWriter {
+ /**
+ * Set the name of the codec.
+ *
+ * @param name The new name.
+ */
+ void setName(const char* name);
+ /**
+ * Set the owner name of the codec.
+ *
+ * This "owner name" is the name of the `IOmx` instance that supports this
+ * codec.
+ *
+ * @param owner The new owner name.
+ */
+ void setOwner(const char* owner);
+ /**
+ * Set whether this codec is an encoder or a decoder.
+ *
+ * @param isEncoder Whether this codec is an encoder or a decoder.
+ */
+ void setEncoder(bool isEncoder = true);
+ /**
+ * Add a mime to an indexed list and return a `CapabilitiesWriter` object
+ * that can be used for modifying the associated `Capabilities`.
+ *
+ * If the mime already exists, this function will return the
+ * `CapabilitiesWriter` associated with the mime.
+ *
+ * @param[in] mime The name of a new mime to add.
+ * @return writer The `CapabilitiesWriter` object for modifying the
+ * `Capabilities` associated with the mime. `writer` will be valid
+ * regardless of whether `mime` already exists or not.
+ */
+ std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> addMime(
+ const char* mime);
+ /**
+ * Remove a mime.
+ *
+ * @param mime The name of the mime to remove.
+ * @return `true` if `mime` is removed; `false` if `mime` is not found.
+ */
+ bool removeMime(const char* mime);
+private:
+ /**
+ * The associated `MediaCodecInfo`.
+ */
+ MediaCodecInfo* mInfo;
+ /**
+ * Construct the `MediaCodecInfoWriter` object associated with the given
+ * `MediaCodecInfo` object.
+ *
+ * @param info The underlying `MediaCodecInfo` object.
+ */
+ MediaCodecInfoWriter(MediaCodecInfo* info);
+
+ DISALLOW_COPY_AND_ASSIGN(MediaCodecInfoWriter);
+
+ friend struct MediaCodecListWriter;
};
} // namespace android
diff --git a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
index a5e1350..257002d 100644
--- a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
+++ b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
@@ -41,8 +41,9 @@
const KeyedVector<String8, String8> *headers = NULL) = 0;
virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0;
- virtual status_t setDataSource(const sp<DataSource>& source) = 0;
- virtual VideoFrame* getFrameAtTime(int64_t timeUs, int option) = 0;
+ virtual status_t setDataSource(const sp<DataSource>& source, const char *mime) = 0;
+ virtual VideoFrame* getFrameAtTime(
+ int64_t timeUs, int option, int colorFormat, bool metaOnly) = 0;
virtual MediaAlbumArt* extractAlbumArt() = 0;
virtual const char* extractMetadata(int keyCode) = 0;
};
@@ -54,7 +55,9 @@
MediaMetadataRetrieverInterface() {}
virtual ~MediaMetadataRetrieverInterface() {}
- virtual VideoFrame* getFrameAtTime(int64_t /*timeUs*/, int /*option*/) { return NULL; }
+ virtual VideoFrame* getFrameAtTime(
+ int64_t /*timeUs*/, int /*option*/, int /*colorFormat*/, bool /*metaOnly*/)
+ { return NULL; }
virtual MediaAlbumArt* extractAlbumArt() { return NULL; }
virtual const char* extractMetadata(int /*keyCode*/) { return NULL; }
};
diff --git a/media/libmedia/include/media/PluginMetricsReporting.h b/media/libmedia/include/media/PluginMetricsReporting.h
new file mode 100644
index 0000000..4a5a363
--- /dev/null
+++ b/media/libmedia/include/media/PluginMetricsReporting.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 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 PLUGIN_METRICS_REPORTING_H_
+
+#define PLUGIN_METRICS_REPORTING_H_
+
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+status_t reportDrmPluginMetrics(const Vector<uint8_t>& serializedMetrics,
+ const String8& vendorName,
+ const String8& description);
+
+} // namespace android
+
+#endif // PLUGIN_METRICS_REPORTING_H_
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index 8ed07ee..65c266b 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -76,8 +76,10 @@
const KeyedVector<String8, String8> *headers = NULL);
status_t setDataSource(int fd, int64_t offset, int64_t length);
- status_t setDataSource(const sp<IDataSource>& dataSource);
- sp<IMemory> getFrameAtTime(int64_t timeUs, int option);
+ status_t setDataSource(
+ const sp<IDataSource>& dataSource, const char *mime = NULL);
+ sp<IMemory> getFrameAtTime(int64_t timeUs, int option,
+ int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
sp<IMemory> extractAlbumArt();
const char* extractMetadata(int keyCode);
diff --git a/include/media/omx/1.0/Conversion.h b/media/libmedia/include/media/omx/1.0/Conversion.h
similarity index 100%
rename from include/media/omx/1.0/Conversion.h
rename to media/libmedia/include/media/omx/1.0/Conversion.h
diff --git a/include/media/omx/1.0/WGraphicBufferSource.h b/media/libmedia/include/media/omx/1.0/WGraphicBufferSource.h
similarity index 100%
rename from include/media/omx/1.0/WGraphicBufferSource.h
rename to media/libmedia/include/media/omx/1.0/WGraphicBufferSource.h
diff --git a/include/media/omx/1.0/WOmx.h b/media/libmedia/include/media/omx/1.0/WOmx.h
similarity index 100%
rename from include/media/omx/1.0/WOmx.h
rename to media/libmedia/include/media/omx/1.0/WOmx.h
diff --git a/include/media/omx/1.0/WOmxBufferSource.h b/media/libmedia/include/media/omx/1.0/WOmxBufferSource.h
similarity index 98%
rename from include/media/omx/1.0/WOmxBufferSource.h
rename to media/libmedia/include/media/omx/1.0/WOmxBufferSource.h
index 86322da..086f648 100644
--- a/include/media/omx/1.0/WOmxBufferSource.h
+++ b/media/libmedia/include/media/omx/1.0/WOmxBufferSource.h
@@ -21,7 +21,7 @@
#include <hidl/Status.h>
#include <binder/Binder.h>
-#include <OMXFenceParcelable.h>
+#include <media/OMXFenceParcelable.h>
#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
#include <android/BnOMXBufferSource.h>
diff --git a/include/media/omx/1.0/WOmxNode.h b/media/libmedia/include/media/omx/1.0/WOmxNode.h
similarity index 100%
rename from include/media/omx/1.0/WOmxNode.h
rename to media/libmedia/include/media/omx/1.0/WOmxNode.h
diff --git a/include/media/omx/1.0/WOmxObserver.h b/media/libmedia/include/media/omx/1.0/WOmxObserver.h
similarity index 100%
rename from include/media/omx/1.0/WOmxObserver.h
rename to media/libmedia/include/media/omx/1.0/WOmxObserver.h
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 08a9e6a..7d27d57 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -130,7 +130,7 @@
}
status_t MediaMetadataRetriever::setDataSource(
- const sp<IDataSource>& dataSource)
+ const sp<IDataSource>& dataSource, const char *mime)
{
ALOGV("setDataSource(IDataSource)");
Mutex::Autolock _l(mLock);
@@ -138,18 +138,20 @@
ALOGE("retriever is not initialized");
return INVALID_OPERATION;
}
- return mRetriever->setDataSource(dataSource);
+ return mRetriever->setDataSource(dataSource, mime);
}
-sp<IMemory> MediaMetadataRetriever::getFrameAtTime(int64_t timeUs, int option)
+sp<IMemory> MediaMetadataRetriever::getFrameAtTime(
+ int64_t timeUs, int option, int colorFormat, bool metaOnly)
{
- ALOGV("getFrameAtTime: time(%" PRId64 " us) option(%d)", timeUs, option);
+ ALOGV("getFrameAtTime: time(%" PRId64 " us) option(%d) colorFormat(%d) metaOnly(%d)",
+ timeUs, option, colorFormat, metaOnly);
Mutex::Autolock _l(mLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
}
- return mRetriever->getFrameAtTime(timeUs, option);
+ return mRetriever->getFrameAtTime(timeUs, option, colorFormat, metaOnly);
}
const char* MediaMetadataRetriever::extractMetadata(int keyCode)
diff --git a/media/libmediametrics/IMediaAnalyticsService.cpp b/media/libmediametrics/IMediaAnalyticsService.cpp
index 68bafe1..28a7746 100644
--- a/media/libmediametrics/IMediaAnalyticsService.cpp
+++ b/media/libmediametrics/IMediaAnalyticsService.cpp
@@ -60,7 +60,7 @@
data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
err = remote()->transact(GENERATE_UNIQUE_SESSIONID, data, &reply);
if (err != NO_ERROR) {
- ALOGW("bad response from service");
+ ALOGW("bad response from service for generateSessionId, err=%d", err);
return MediaAnalyticsItem::SessionIDInvalid;
}
sessionid = reply.readInt64();
@@ -94,6 +94,7 @@
err = remote()->transact(SUBMIT_ITEM, data, &reply);
if (err != NO_ERROR) {
+ ALOGW("bad response from service for submit, err=%d", err);
return MediaAnalyticsItem::SessionIDInvalid;
}
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index 43881b3..f968c09 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -59,6 +59,7 @@
MediaAnalyticsItem::MediaAnalyticsItem()
: mPid(-1),
mUid(-1),
+ mPkgVersionCode(0),
mSessionID(MediaAnalyticsItem::SessionIDNone),
mTimestamp(0),
mFinalized(0),
@@ -70,6 +71,7 @@
MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
: mPid(-1),
mUid(-1),
+ mPkgVersionCode(0),
mSessionID(MediaAnalyticsItem::SessionIDNone),
mTimestamp(0),
mFinalized(0),
@@ -98,7 +100,7 @@
// clean attributes
// contents of the attributes
- for (size_t i = 0 ; i < mPropSize; i++ ) {
+ for (size_t i = 0 ; i < mPropCount; i++ ) {
clearProp(&mProps[i]);
}
// the attribute records themselves
@@ -120,6 +122,8 @@
// key as part of constructor
dst->mPid = this->mPid;
dst->mUid = this->mUid;
+ dst->mPkgName = this->mPkgName;
+ dst->mPkgVersionCode = this->mPkgVersionCode;
dst->mSessionID = this->mSessionID;
dst->mTimestamp = this->mTimestamp;
dst->mFinalized = this->mFinalized;
@@ -201,6 +205,24 @@
return mUid;
}
+MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(AString pkgName) {
+ mPkgName = pkgName;
+ return *this;
+}
+
+AString MediaAnalyticsItem::getPkgName() const {
+ return mPkgName;
+}
+
+MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int32_t pkgVersionCode) {
+ mPkgVersionCode = pkgVersionCode;
+ return *this;
+}
+
+int32_t MediaAnalyticsItem::getPkgVersionCode() const {
+ return mPkgVersionCode;
+}
+
// this key is for the overall record -- "codec", "player", "drm", etc
MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
mKey = key;
@@ -263,11 +285,30 @@
i = mPropCount++;
prop = &mProps[i];
prop->setName(name, len);
+ prop->mType = kTypeNone; // make caller set type info
}
return prop;
}
+// used within the summarizers; return whether property existed
+bool MediaAnalyticsItem::removeProp(const char *name) {
+ size_t len = strlen(name);
+ size_t i = findPropIndex(name, len);
+ if (i < mPropCount) {
+ Prop *prop = &mProps[i];
+ clearProp(prop);
+ if (i != mPropCount-1) {
+ // in the middle, bring last one down to fill gap
+ copyProp(prop, &mProps[mPropCount-1]);
+ clearProp(&mProps[mPropCount-1]);
+ }
+ mPropCount--;
+ return true;
+ }
+ return false;
+}
+
// set the values
void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
Prop *prop = allocateProp(name);
@@ -568,6 +609,10 @@
// into 'this' object
// .. we make a copy of the string to put away.
mKey = data.readCString();
+ mPid = data.readInt32();
+ mUid = data.readInt32();
+ mPkgName = data.readCString();
+ mPkgVersionCode = data.readInt32();
mSessionID = data.readInt64();
mFinalized = data.readInt32();
mTimestamp = data.readInt64();
@@ -611,6 +656,10 @@
data->writeCString(mKey.c_str());
+ data->writeInt32(mPid);
+ data->writeInt32(mUid);
+ data->writeCString(mPkgName.c_str());
+ data->writeInt32(mPkgVersionCode);
data->writeInt64(mSessionID);
data->writeInt32(mFinalized);
data->writeInt64(mTimestamp);
@@ -651,21 +700,54 @@
AString MediaAnalyticsItem::toString() {
+ return toString(-1);
+}
- AString result = "(";
+AString MediaAnalyticsItem::toString(int version) {
+
+ // v0 : released with 'o'
+ // v1 : bug fix (missing pid/finalized separator),
+ // adds apk name, apk version code
+
+ if (version <= PROTO_FIRST) {
+ // default to original v0 format, until proper parsers are in place
+ version = PROTO_V0;
+ } else if (version > PROTO_LAST) {
+ version = PROTO_LAST;
+ }
+
+ AString result;
char buffer[512];
+ if (version == PROTO_V0) {
+ result = "(";
+ } else {
+ snprintf(buffer, sizeof(buffer), "[%d:", version);
+ result.append(buffer);
+ }
+
// same order as we spill into the parcel, although not required
// key+session are our primary matching criteria
- //RBE ALOGD("mKey.c_str");
result.append(mKey.c_str());
- //RBE ALOGD("post-mKey.c_str");
result.append(":");
snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
result.append(buffer);
- // we need these internally, but don't want to upload them
- snprintf(buffer, sizeof(buffer), "%d:%d", mUid, mPid);
+ snprintf(buffer, sizeof(buffer), "%d:", mUid);
+ result.append(buffer);
+
+ if (version >= PROTO_V1) {
+ result.append(mPkgName);
+ snprintf(buffer, sizeof(buffer), ":%d:", mPkgVersionCode);
+ result.append(buffer);
+ }
+
+ // in 'o' (v1) , the separator between pid and finalized was omitted
+ if (version <= PROTO_V0) {
+ snprintf(buffer, sizeof(buffer), "%d", mPid);
+ } else {
+ snprintf(buffer, sizeof(buffer), "%d:", mPid);
+ }
result.append(buffer);
snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
@@ -713,7 +795,11 @@
result.append(buffer);
}
- result.append(")");
+ if (version == PROTO_V0) {
+ result.append(")");
+ } else {
+ result.append("]");
+ }
return result;
}
@@ -734,11 +820,16 @@
sp<IMediaAnalyticsService> svc = getInstance();
if (svc != NULL) {
- svc->submit(this, forcenew);
+ MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
+ if (newid == SessionIDInvalid) {
+ AString p = this->toString();
+ ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
+ return false;
+ }
return true;
} else {
AString p = this->toString();
- ALOGD("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
+ ALOGW("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
return false;
}
}
@@ -747,6 +838,7 @@
// static
sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
static Mutex sInitMutex;
+static int remainingBindAttempts = SVC_TRIES;
//static
bool MediaAnalyticsItem::isEnabled() {
@@ -764,10 +856,28 @@
return true;
}
+
+// monitor health of our connection to the metrics service
+class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
+ virtual void binderDied(const wp<IBinder> &) {
+ ALOGW("Reacquire service connection on next request");
+ MediaAnalyticsItem::dropInstance();
+ }
+};
+
+static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
+
+// static
+void MediaAnalyticsItem::dropInstance() {
+ Mutex::Autolock _l(sInitMutex);
+ remainingBindAttempts = SVC_TRIES;
+ sAnalyticsService = NULL;
+}
+
//static
sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
+
static const char *servicename = "media.metrics";
- static int tries_remaining = SVC_TRIES;
int enabled = isEnabled();
if (enabled == false) {
@@ -799,15 +909,20 @@
Mutex::Autolock _l(sInitMutex);
const char *badness = "";
- // think of tries_remaining as telling us whether service==NULL because
+ // think of remainingBindAttempts as telling us whether service==NULL because
// (1) we haven't tried to initialize it yet
// (2) we've tried to initialize it, but failed.
- if (sAnalyticsService == NULL && tries_remaining > 0) {
+ if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
sp<IServiceManager> sm = defaultServiceManager();
if (sm != NULL) {
sp<IBinder> binder = sm->getService(String16(servicename));
if (binder != NULL) {
sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
+ if (sNotifier != NULL) {
+ sNotifier = NULL;
+ }
+ sNotifier = new MediaMetricsDeathNotifier();
+ binder->linkToDeath(sNotifier);
} else {
badness = "did not find service";
}
@@ -816,8 +931,8 @@
}
if (sAnalyticsService == NULL) {
- if (tries_remaining > 0) {
- tries_remaining--;
+ if (remainingBindAttempts > 0) {
+ remainingBindAttempts--;
}
if (DEBUG_SERVICEACCESS) {
ALOGD("Unable to bind to service %s: %s", servicename, badness);
@@ -829,7 +944,6 @@
}
}
-
// merge the info from 'incoming' into this record.
// we finish with a union of this+incoming and special handling for collisions
bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index dc501b2..dd7452f 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -42,6 +42,7 @@
friend class IMediaAnalyticsService;
friend class MediaMetricsJNI;
friend class MetricsSummarizer;
+ friend class MediaMetricsDeathNotifier;
public:
@@ -75,6 +76,14 @@
typedef const char *Attr;
+ enum {
+ PROTO_V0 = 0,
+ PROTO_FIRST = PROTO_V0,
+ PROTO_V1 = 1,
+ PROTO_LAST = PROTO_V1,
+ };
+
+
public:
// access functions for the class
@@ -161,11 +170,18 @@
MediaAnalyticsItem &setUid(uid_t);
uid_t getUid() const;
+ MediaAnalyticsItem &setPkgName(AString);
+ AString getPkgName() const;
+
+ MediaAnalyticsItem &setPkgVersionCode(int32_t);
+ int32_t getPkgVersionCode() const;
+
// our serialization code for binder calls
int32_t writeToParcel(Parcel *);
int32_t readFromParcel(const Parcel&);
AString toString();
+ AString toString(int version);
// are we collecting analytics data
static bool isEnabled();
@@ -188,10 +204,13 @@
// to help validate that A doesn't mess with B's records
pid_t mPid;
uid_t mUid;
+ AString mPkgName;
+ int32_t mPkgVersionCode;
// let's reuse a binder connection
static sp<IMediaAnalyticsService> sAnalyticsService;
static sp<IMediaAnalyticsService> getInstance();
+ static void dropInstance();
// tracking information
SessionID_t mSessionID; // grouping similar records
@@ -228,6 +247,7 @@
size_t findPropIndex(const char *name, size_t len);
Prop *findProp(const char *name);
Prop *allocateProp(const char *name);
+ bool removeProp(const char *name);
size_t mPropCount;
size_t mPropSize;
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 54d6014..686c059 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -244,8 +244,12 @@
if (sInitComplete)
return;
- registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
- registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
+ IFactory* factory = new NuPlayerFactory();
+ if (registerFactory_l(factory, NU_PLAYER) != OK)
+ delete factory;
+ factory = new TestPlayerFactory();
+ if (registerFactory_l(factory, TEST_PLAYER) != OK)
+ delete factory;
sInitComplete = true;
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 91887a1..3445469 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -77,7 +77,7 @@
#include "TestPlayerStub.h"
#include "nuplayer/NuPlayerDriver.h"
-#include <OMX.h>
+#include <media/stagefright/omx/OMX.h>
#include "HDCP.h"
#include "HTTPBase.h"
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 793f476..5a468f3 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -175,7 +175,7 @@
}
status_t MetadataRetrieverClient::setDataSource(
- const sp<IDataSource>& source)
+ const sp<IDataSource>& source, const char *mime)
{
ALOGV("setDataSource(IDataSource)");
Mutex::Autolock lock(mLock);
@@ -186,16 +186,18 @@
ALOGV("player type = %d", playerType);
sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
if (p == NULL) return NO_INIT;
- status_t ret = p->setDataSource(dataSource);
+ status_t ret = p->setDataSource(dataSource, mime);
if (ret == NO_ERROR) mRetriever = p;
return ret;
}
Mutex MetadataRetrieverClient::sLock;
-sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
+sp<IMemory> MetadataRetrieverClient::getFrameAtTime(
+ int64_t timeUs, int option, int colorFormat, bool metaOnly)
{
- ALOGV("getFrameAtTime: time(%lld us) option(%d)", (long long)timeUs, option);
+ ALOGV("getFrameAtTime: time(%lld us) option(%d) colorFormat(%d), metaOnly(%d)",
+ (long long)timeUs, option, colorFormat, metaOnly);
Mutex::Autolock lock(mLock);
Mutex::Autolock glock(sLock);
mThumbnail.clear();
@@ -203,12 +205,13 @@
ALOGE("retriever is not initialized");
return NULL;
}
- VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option);
+ VideoFrame *frame = mRetriever->getFrameAtTime(
+ timeUs, option, colorFormat, metaOnly);
if (frame == NULL) {
ALOGE("failed to capture a video frame");
return NULL;
}
- size_t size = sizeof(VideoFrame) + frame->mSize;
+ size_t size = frame->getFlattenedSize();
sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
if (heap == NULL) {
ALOGE("failed to create MemoryDealer");
@@ -222,16 +225,7 @@
return NULL;
}
VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
- frameCopy->mWidth = frame->mWidth;
- frameCopy->mHeight = frame->mHeight;
- frameCopy->mDisplayWidth = frame->mDisplayWidth;
- frameCopy->mDisplayHeight = frame->mDisplayHeight;
- frameCopy->mSize = frame->mSize;
- frameCopy->mRotationAngle = frame->mRotationAngle;
- ALOGV("rotation: %d", frameCopy->mRotationAngle);
- frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
- memcpy(frameCopy->mData, frame->mData, frame->mSize);
- frameCopy->mData = 0;
+ frameCopy->copyFlattened(*frame);
delete frame; // Fix memory leakage
return mThumbnail;
}
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index fe7547c..c78cd4b 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -49,8 +49,9 @@
const KeyedVector<String8, String8> *headers);
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
- virtual status_t setDataSource(const sp<IDataSource>& source);
- virtual sp<IMemory> getFrameAtTime(int64_t timeUs, int option);
+ virtual status_t setDataSource(const sp<IDataSource>& source, const char *mime);
+ virtual sp<IMemory> getFrameAtTime(
+ int64_t timeUs, int option, int colorFormat, bool metaOnly);
virtual sp<IMemory> extractAlbumArt();
virtual const char* extractMetadata(int keyCode);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 6a09227..df36046 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1171,7 +1171,7 @@
if (mSource != nullptr) {
if (audio) {
if (mVideoDecoderError || mSource->getFormat(false /* audio */) == NULL
- || mSurface == NULL) {
+ || mSurface == NULL || mVideoDecoder == NULL) {
// When both audio and video have error, or this stream has only audio
// which has error, notify client of error.
notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
@@ -1182,7 +1182,7 @@
mAudioDecoderError = true;
} else {
if (mAudioDecoderError || mSource->getFormat(true /* audio */) == NULL
- || mAudioSink == NULL) {
+ || mAudioSink == NULL || mAudioDecoder == NULL) {
// When both audio and video have error, or this stream has only video
// which has error, notify client of error.
notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 8fe255b..ac187cc 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -343,7 +343,7 @@
format, mSurface, crypto, 0 /* flags */);
if (err != OK) {
- ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err);
+ ALOGE("Failed to configure [%s] decoder (err=%d)", mComponentName.c_str(), err);
mCodec->release();
mCodec.clear();
handleError(err);
@@ -372,7 +372,7 @@
err = mCodec->start();
if (err != OK) {
- ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err);
+ ALOGE("Failed to start [%s] decoder (err=%d)", mComponentName.c_str(), err);
mCodec->release();
mCodec.clear();
handleError(err);
@@ -460,6 +460,12 @@
if (notifyComplete) {
mResumePending = true;
}
+
+ if (mCodec == NULL) {
+ ALOGE("[%s] onResume without a valid codec", mComponentName.c_str());
+ handleError(NO_INIT);
+ return;
+ }
mCodec->start();
}
@@ -481,7 +487,7 @@
}
if (err != OK) {
- ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err);
+ ALOGE("failed to flush [%s] (err=%d)", mComponentName.c_str(), err);
handleError(err);
// finish with posting kWhatFlushCompleted.
// we attempt to release the buffers even if flush fails.
@@ -530,7 +536,7 @@
releaseAndResetMediaBuffers();
if (err != OK) {
- ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
+ ALOGE("failed to release [%s] (err=%d)", mComponentName.c_str(), err);
handleError(err);
// finish with posting kWhatShutdownCompleted.
}
@@ -631,10 +637,17 @@
return false;
}
+ if (mCodec == NULL) {
+ ALOGE("[%s] handleAnInputBuffer without a valid codec", mComponentName.c_str());
+ handleError(NO_INIT);
+ return false;
+ }
+
sp<MediaCodecBuffer> buffer;
mCodec->getInputBuffer(index, &buffer);
if (buffer == NULL) {
+ ALOGE("[%s] handleAnInputBuffer, failed to get input buffer", mComponentName.c_str());
handleError(UNKNOWN_ERROR);
return false;
}
@@ -697,11 +710,18 @@
size_t size,
int64_t timeUs,
int32_t flags) {
+ if (mCodec == NULL) {
+ ALOGE("[%s] handleAnOutputBuffer without a valid codec", mComponentName.c_str());
+ handleError(NO_INIT);
+ return false;
+ }
+
// CHECK_LT(bufferIx, mOutputBuffers.size());
sp<MediaCodecBuffer> buffer;
mCodec->getOutputBuffer(index, &buffer);
if (buffer == NULL) {
+ ALOGE("[%s] handleAnOutputBuffer, failed to get output buffer", mComponentName.c_str());
handleError(UNKNOWN_ERROR);
return false;
}
@@ -949,6 +969,12 @@
}
bool NuPlayer::Decoder::onInputBufferFetched(const sp<AMessage> &msg) {
+ if (mCodec == NULL) {
+ ALOGE("[%s] onInputBufferFetched without a valid codec", mComponentName.c_str());
+ handleError(NO_INIT);
+ return false;
+ }
+
size_t bufferIx;
CHECK(msg->findSize("buffer-ix", &bufferIx));
CHECK_LT(bufferIx, mInputBuffers.size());
@@ -979,7 +1005,7 @@
}
if (streamErr != ERROR_END_OF_STREAM) {
- ALOGE("Stream error for %s (err=%d), EOS %s queued",
+ ALOGE("Stream error for [%s] (err=%d), EOS %s queued",
mComponentName.c_str(),
streamErr,
err == OK ? "successfully" : "unsuccessfully");
@@ -1073,7 +1099,7 @@
} // no cryptInfo
if (err != OK) {
- ALOGE("onInputBufferFetched: queue%sInputBuffer failed for %s (err=%d, %s)",
+ ALOGE("onInputBufferFetched: queue%sInputBuffer failed for [%s] (err=%d, %s)",
(cryptInfo != NULL ? "Secure" : ""),
mComponentName.c_str(), err, errorDetailMsg.c_str());
handleError(err);
@@ -1102,7 +1128,9 @@
}
}
- if (msg->findInt32("render", &render) && render) {
+ if (mCodec == NULL) {
+ err = NO_INIT;
+ } else if (msg->findInt32("render", &render) && render) {
int64_t timestampNs;
CHECK(msg->findInt64("timestampNs", ×tampNs));
err = mCodec->renderOutputBufferAndRelease(bufferIx, timestampNs);
@@ -1111,7 +1139,7 @@
err = mCodec->releaseOutputBuffer(bufferIx);
}
if (err != OK) {
- ALOGE("failed to release output buffer for %s (err=%d)",
+ ALOGE("failed to release output buffer for [%s] (err=%d)",
mComponentName.c_str(), err);
handleError(err);
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 25e2d73..a512a0b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -69,6 +69,7 @@
mPlayer(new NuPlayer(pid)),
mPlayerFlags(0),
mAnalyticsItem(NULL),
+ mClientUid(-1),
mAtEOS(false),
mLooping(false),
mAutoLoop(false) {
@@ -110,6 +111,10 @@
status_t NuPlayerDriver::setUID(uid_t uid) {
mPlayer->setUID(uid);
+ mClientUid = uid;
+ if (mAnalyticsItem) {
+ mAnalyticsItem->setUid(mClientUid);
+ }
return OK;
}
@@ -616,6 +621,7 @@
mAnalyticsItem = new MediaAnalyticsItem("nuplayer");
if (mAnalyticsItem) {
mAnalyticsItem->generateSessionID();
+ mAnalyticsItem->setUid(mClientUid);
}
} else {
ALOGV("did not have anything to record");
@@ -654,11 +660,6 @@
notifyListener_l(MEDIA_STOPPED);
}
- if (property_get_bool("persist.debug.sf.stats", false)) {
- Vector<String16> args;
- dump(-1, args);
- }
-
mState = STATE_RESET_IN_PROGRESS;
mPlayer->resetAsync();
@@ -953,7 +954,10 @@
// don't send completion event when looping
return;
}
-
+ if (property_get_bool("persist.debug.sf.stats", false)) {
+ Vector<String16> args;
+ dump(-1, args);
+ }
mPlayer->pause();
mState = STATE_PAUSED;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index ab1955e..327f21b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -132,12 +132,14 @@
uint32_t mPlayerFlags;
MediaAnalyticsItem *mAnalyticsItem;
+ uid_t mClientUid;
mutable Mutex mMetricsLock;
bool mAtEOS;
bool mLooping;
bool mAutoLoop;
+
void updateMetrics(const char *where);
void logMetrics(const char *where);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 758db1f..bd866cb 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -840,7 +840,7 @@
return;
}
- notifyEOS(true /* audio */, ERROR_END_OF_STREAM);
+ notifyEOS_l(true /* audio */, ERROR_END_OF_STREAM);
}
size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
@@ -917,10 +917,10 @@
if (mAudioSink->needsTrailingPadding()) {
postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
}
- ALOGV("fillAudioBuffer: notifyEOS "
+ ALOGV("fillAudioBuffer: notifyEOS_l "
"mNumFramesWritten:%u finalResult:%d postEOSDelay:%lld",
mNumFramesWritten, entry->mFinalResult, (long long)postEOSDelayUs);
- notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
+ notifyEOS_l(true /* audio */, entry->mFinalResult, postEOSDelayUs);
}
}
return sizeCopied;
@@ -1152,7 +1152,18 @@
return writtenAudioDurationUs - (mediaUs - mAudioFirstAnchorTimeMediaUs);
}
}
- return writtenAudioDurationUs - mAudioSink->getPlayedOutDurationUs(nowUs);
+
+ const int64_t audioSinkPlayedUs = mAudioSink->getPlayedOutDurationUs(nowUs);
+ int64_t pendingUs = writtenAudioDurationUs - audioSinkPlayedUs;
+ if (pendingUs < 0) {
+ // This shouldn't happen unless the timestamp is stale.
+ ALOGW("%s: pendingUs %lld < 0, clamping to zero, potential resume after pause "
+ "writtenAudioDurationUs: %lld, audioSinkPlayedUs: %lld",
+ __func__, (long long)pendingUs,
+ (long long)writtenAudioDurationUs, (long long)audioSinkPlayedUs);
+ pendingUs = 0;
+ }
+ return pendingUs;
}
int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
@@ -1408,6 +1419,11 @@
}
void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
+ Mutex::Autolock autoLock(mLock);
+ notifyEOS_l(audio, finalResult, delayUs);
+}
+
+void NuPlayer::Renderer::notifyEOS_l(bool audio, status_t finalResult, int64_t delayUs) {
if (audio && delayUs > 0) {
sp<AMessage> msg = new AMessage(kWhatEOS, this);
msg->setInt32("audioEOSGeneration", mAudioEOSGeneration);
@@ -1420,6 +1436,11 @@
notify->setInt32("audio", static_cast<int32_t>(audio));
notify->setInt32("finalResult", finalResult);
notify->post(delayUs);
+
+ if (audio) {
+ // Video might outlive audio. Clear anchor to enable video only case.
+ mAnchorTimeMediaUs = -1;
+ }
}
void NuPlayer::Renderer::notifyAudioTearDown(AudioTearDownReason reason) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index e6850b5..f58b79c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -275,6 +275,7 @@
void onChangeAudioFormat(const sp<AMessage> &meta, const sp<AMessage> ¬ify);
void notifyEOS(bool audio, status_t finalResult, int64_t delayUs = 0);
+ void notifyEOS_l(bool audio, status_t finalResult, int64_t delayUs = 0);
void notifyFlushComplete(bool audio);
void notifyPosition();
void notifyVideoLateBy(int64_t lateByUs);
diff --git a/media/libnbaio/Android.bp b/media/libnbaio/Android.bp
index f511876..4220b77 100644
--- a/media/libnbaio/Android.bp
+++ b/media/libnbaio/Android.bp
@@ -1,15 +1,51 @@
+
+cc_defaults {
+ name: "libnbaio_mono_defaults",
+ srcs: [
+ "MonoPipe.cpp",
+ "MonoPipeReader.cpp",
+ "NBAIO.cpp",
+ ],
+ header_libs: [
+ "libaudioclient_headers",
+ "libaudio_system_headers",
+ "libmedia_headers",
+ ],
+ export_header_lib_headers: [
+ "libaudioclient_headers",
+ "libmedia_headers",
+ ],
+
+ shared_libs: [
+ "libaudioutils",
+ "liblog",
+ "libutils",
+ ],
+
+ export_include_dirs: ["include_mono"],
+}
+
+// libnbaio_mono is the part of libnbaio that is available for vendors to use. Vendor modules can't
+// link against libnbaio and system modules can't link against libnbaio_mono. The rest of libnbaio
+// pulls in too many other dependencies.
+cc_library_shared {
+ name: "libnbaio_mono",
+ vendor: true,
+ defaults: ["libnbaio_mono_defaults"],
+}
+
cc_library_shared {
name: "libnbaio",
+ defaults: ["libnbaio_mono_defaults"],
srcs: [
"AudioBufferProviderSource.cpp",
"AudioStreamInSource.cpp",
"AudioStreamOutSink.cpp",
- "MonoPipe.cpp",
- "MonoPipeReader.cpp",
- "NBAIO.cpp",
"NBLog.cpp",
+ "PerformanceAnalysis.cpp",
"Pipe.cpp",
"PipeReader.cpp",
+ "ReportPerformance.cpp",
"SourceAudioBufferProvider.cpp",
],
@@ -24,8 +60,8 @@
"libaudioutils",
"libbinder",
"libcutils",
- "libutils",
"liblog",
+ "libutils",
],
cflags: [
@@ -35,7 +71,5 @@
include_dirs: ["system/media/audio_utils/include"],
- local_include_dirs: ["include"],
-
export_include_dirs: ["include"],
}
diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp
index cbff87d..8564899 100644
--- a/media/libnbaio/AudioStreamOutSink.cpp
+++ b/media/libnbaio/AudioStreamOutSink.cpp
@@ -18,6 +18,7 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <audio_utils/clock.h>
#include <media/audiohal/StreamHalInterface.h>
#include <media/nbaio/AudioStreamOutSink.h>
@@ -82,8 +83,7 @@
return INVALID_OPERATION;
}
timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = position64;
- timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
- time.tv_sec * 1000000000LL + time.tv_nsec;
+ timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = audio_utils_ns_from_timespec(&time);
return OK;
}
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index ebb90c8..2f639d2 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -18,14 +18,14 @@
* Documentation: Workflow summary for histogram data processing:
* For more details on FIFO, please see system/media/audio_utils; doxygen
* TODO: add this documentation to doxygen once it is further developed
-* 1) writing the data to a buffer
-* onWork
+* 1) Writing buffer period timestamp to the circular buffer
+* onWork()
* Called every period length (e.g., 4ms)
* Calls LOG_HIST_TS
* LOG_HIST_TS
-* Hashes file name and line number
-* calls NBLOG::Writer::logHistTS once
-* NBLOG::Writer::logHistTS
+* Hashes file name and line number, and writes single timestamp to buffer
+* calls NBLOG::Writer::logEventHistTS once
+* NBLOG::Writer::logEventHistTS
* calls NBLOG::Writer::log on hash and current timestamp
* time is in CLOCK_MONOTONIC converted to ns
* NBLOG::Writer::log(Event, const void*, size_t)
@@ -44,6 +44,8 @@
* ssize_t audio_utils_fifo_reader::obtain
* Determines readable buffer section via pointer arithmetic on reader
* and writer pointers
+* Similarly, LOG_AUDIO_STATE() is called by onStateChange whenever audio is
+* turned on or off, and writes this notification to the FIFO.
*
* 2) reading the data from shared memory
* Thread::threadloop()
@@ -51,6 +53,7 @@
* NBLog::MergeThread::threadLoop()
* calls NBLog::Merger::merge
* NBLog::Merger::merge
+* Merges snapshots sorted by timestamp
* for each reader in vector of class NamedReader,
* callsNamedReader::reader()->getSnapshot
* TODO: check whether the rest of this function is relevant
@@ -59,11 +62,12 @@
* calls mFifoReader->obtain to find readable data
* sets snapshot.begin() and .end() iterators to boundaries of valid entries
* moves the fifo reader index to after the last entry read
-* in this case, the buffer is in shared memory. in (3), the buffer is private
+* in this case, the buffer is in shared memory. in (4), the buffer is private
*
* 3) reading the data from private buffer
* MediaLogService::dump
-* calls NBLog::Reader::dump(int) on instance of subclass mergeReader
+* calls NBLog::Reader::dump(CONSOLE)
+* The private buffer contains all logs for all readers in shared memory
* NBLog::Reader::dump(int)
* calls getSnapshot on the current reader
* calls dump(int, size_t, Snapshot)
@@ -72,9 +76,10 @@
* (string, timestamp, etc...)
* In the case of EVENT_HISTOGRAM_ENTRY_TS, adds a list of timestamp sequences
* (histogram entry) to NBLog::mHists
-* In the case of EVENT_HISTOGRAM_FLUSH, calls drawHistogram on each element in
-* the list and erases it
-* TODO: when do these events occur?
+* TODO: add every HISTOGRAM_ENTRY_TS to two
+* circular buffers: one short-term and one long-term (can add even longer-term
+* structures in the future). When dump is called, print everything currently
+* in the buffer.
* NBLog::drawHistogram
* input: timestamp array
* buckets this to a histogram and prints
@@ -82,7 +87,7 @@
*/
#define LOG_TAG "NBLog"
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
#include <algorithm>
#include <climits>
@@ -102,6 +107,8 @@
#include <new>
#include <audio_utils/roundup.h>
#include <media/nbaio/NBLog.h>
+#include <media/nbaio/PerformanceAnalysis.h>
+#include <media/nbaio/ReportPerformance.h>
// #include <utils/CallStack.h> // used to print callstack
#include <utils/Log.h>
#include <utils/String8.h>
@@ -134,7 +141,7 @@
switch (type) {
case EVENT_START_FMT:
return std::make_unique<FormatEntry>(FormatEntry(ptr));
- case EVENT_HISTOGRAM_FLUSH:
+ case EVENT_AUDIO_STATE:
case EVENT_HISTOGRAM_ENTRY_TS:
return std::make_unique<HistogramEntry>(HistogramEntry(ptr));
default:
@@ -513,7 +520,7 @@
log(EVENT_HASH, &hash, sizeof(hash));
}
-void NBLog::Writer::logHistTS(log_hash_t hash)
+void NBLog::Writer::logEventHistTs(Event event, log_hash_t hash)
{
if (!mEnabled) {
return;
@@ -522,22 +529,7 @@
data.hash = hash;
data.ts = get_monotonic_ns();
if (data.ts > 0) {
- log(EVENT_HISTOGRAM_ENTRY_TS, &data, sizeof(data));
- } else {
- ALOGE("Failed to get timestamp");
- }
-}
-
-void NBLog::Writer::logHistFlush(log_hash_t hash)
-{
- if (!mEnabled) {
- return;
- }
- HistTsEntry data;
- data.hash = hash;
- data.ts = get_monotonic_ns();
- if (data.ts > 0) {
- log(EVENT_HISTOGRAM_FLUSH, &data, sizeof(data));
+ log(event, &data, sizeof(data));
} else {
ALOGE("Failed to get timestamp");
}
@@ -771,15 +763,15 @@
NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS};
const std::set<NBLog::Event> NBLog::Reader::endingTypes {NBLog::Event::EVENT_END_FMT,
NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
- NBLog::Event::EVENT_HISTOGRAM_FLUSH};
+ NBLog::Event::EVENT_AUDIO_STATE};
+
NBLog::Reader::Reader(const void *shared, size_t size)
: mShared((/*const*/ Shared *) shared), /*mIMemory*/
mFd(-1), mIndent(0),
mFifo(mShared != NULL ?
new audio_utils_fifo(size, sizeof(uint8_t),
mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
- mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL),
- findGlitch(false)
+ mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
{
}
@@ -795,39 +787,6 @@
delete mFifo;
}
-inline static int deltaMs(int64_t ns1, int64_t ns2) {
- return (ns2 - ns1) / (1000 * 1000);
-}
-
-// Produces a log warning if the timing of recent buffer periods caused a glitch
-// Computes sum of running window of three buffer periods
-// Checks whether the buffer periods leave enough CPU time for the next one
-// e.g. if a buffer period is expected to be 4 ms and a buffer requires 3 ms of CPU time,
-// here are some glitch cases:
-// 4 + 4 + 6 ; 5 + 4 + 5; 2 + 2 + 10
-// TODO: develop this code to track changes in histogram distribution in addition
-// to / instead of glitches
-void NBLog::Reader::alertIfGlitch(const std::vector<int64_t> &samples) {
- //TODO: measure kPeriodLen and kRatio from the data as they may change.
- static const int kPeriodLen = 4; // current period length is ideally 4 ms
- static const double kRatio = 0.75; // estimate of CPU time as ratio of period length
- // DAC processing time for 4 ms buffer
- static const int kPeriodTime = static_cast<int>(round(kPeriodLen * kRatio));
- static const int kNumBuff = 3; // number of buffers considered in local history
- std::deque<int> periods(kNumBuff, kPeriodLen);
- for (size_t i = 2; i < samples.size(); ++i) { // skip first time entry
- periods.push_front(deltaMs(samples[i - 1], samples[i]));
- periods.pop_back();
- // TODO: check that all glitch cases are covered
- if (std::accumulate(periods.begin(), periods.end(), 0) > kNumBuff * kPeriodLen +
- kPeriodLen - kPeriodTime) {
- ALOGW("A glitch occurred");
- periods.assign(kNumBuff, kPeriodLen);
- }
- }
- return;
-}
-
const uint8_t *NBLog::Reader::findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
const std::set<Event> &types) {
while (back + Entry::kPreviousLengthOffset >= front) {
@@ -911,61 +870,17 @@
}
-// writes sample deltas to file, either truncating or appending
-inline void writeHistToFile(const std::vector<int64_t> &samples, bool append) {
- // name of file on audioserver
- static const char* const kName = (char *)"/data/misc/audioserver/sample_results.txt";
- // stores deltas between the samples
- std::vector<int64_t> intervals;
- for (size_t i = 1; i < samples.size(); ++i) {
- intervals.push_back(deltaMs(samples[i - 1], samples[i]));
- }
- if (intervals.empty()) return;
- // Deletes maximum value in a histogram. Temp quick fix.
- // FIXME: need to find root cause of approx. 35th element from the end
- // consistently being an outlier in the first histogram of a flush
- // ALOGW("%" PRId64 "before", (int64_t) *(std::max_element(intervals.begin(), intervals.end())));
- intervals.erase(std::max_element(intervals.begin(), intervals.end()));
- // ALOGW("%" PRId64 "after", (int64_t) *(std::max_element(intervals.begin(), intervals.end())));
- std::ofstream ofs;
- ofs.open(kName, append ? std::ios::app : std::ios::trunc);
- if (!ofs) {
- ALOGW("couldn't open file %s", kName);
- return;
- }
- for (size_t i = 0; i < intervals.size(); ++i) {
- ofs << intervals[i] << "\n";
- }
- ofs.close();
-}
-
+// TODO: move this to PerformanceAnalysis
+// TODO: make call to dump periodic so that data in shared FIFO does not get overwritten
void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
{
- // CallStack cs(LOG_TAG);
-#if 0
- struct timespec ts;
- time_t maxSec = -1;
- while (entry - start >= (int) Entry::kOverhead) {
- if (prevEntry - start < 0 || !prevEntry.hasConsistentLength()) {
- break;
- }
- if (prevEntry->type == EVENT_TIMESTAMP) {
- if (prevEntry->length != sizeof(struct timespec)) {
- // corrupt
- break;
- }
- prevEntry.copyData((uint8_t*) &ts);
- if (ts.tv_sec > maxSec) {
- maxSec = ts.tv_sec;
- }
- }
- --entry;
- --prevEntry;
- }
-#endif
mFd = fd;
mIndent = indent;
String8 timestamp, body;
+ // FIXME: this is not thread safe
+ // TODO: need a separate instance of performanceAnalysis for each thread
+ // used to store data and to call analysis functions
+ static ReportPerformance::PerformanceAnalysis performanceAnalysis;
size_t lost = snapshot.lost() + (snapshot.begin() - EntryIterator(snapshot.data()));
if (lost > 0) {
body.appendFormat("warning: lost %zu bytes worth of events", lost);
@@ -973,85 +888,9 @@
// log to push it out. Consider keeping the timestamp/body between calls to copyEntryDataAt().
dumpLine(timestamp, body);
}
-#if 0
- size_t width = 1;
- while (maxSec >= 10) {
- ++width;
- maxSec /= 10;
- }
- if (maxSec >= 0) {
- timestamp.appendFormat("[%*s]", (int) width + 4, "");
- }
- bool deferredTimestamp = false;
-#endif
for (auto entry = snapshot.begin(); entry != snapshot.end();) {
switch (entry->type) {
-#if 0
- case EVENT_STRING:
- body.appendFormat("%.*s", (int) entry.length(), entry.data());
- break;
- case EVENT_TIMESTAMP: {
- // already checked that length == sizeof(struct timespec);
- entry.copyData((const uint8_t*) &ts);
- long prevNsec = ts.tv_nsec;
- long deltaMin = LONG_MAX;
- long deltaMax = -1;
- long deltaTotal = 0;
- auto aux(entry);
- for (;;) {
- ++aux;
- if (end - aux >= 0 || aux.type() != EVENT_TIMESTAMP) {
- break;
- }
- struct timespec tsNext;
- aux.copyData((const uint8_t*) &tsNext);
- if (tsNext.tv_sec != ts.tv_sec) {
- break;
- }
- long delta = tsNext.tv_nsec - prevNsec;
- if (delta < 0) {
- break;
- }
- if (delta < deltaMin) {
- deltaMin = delta;
- }
- if (delta > deltaMax) {
- deltaMax = delta;
- }
- deltaTotal += delta;
- prevNsec = tsNext.tv_nsec;
- }
- size_t n = (aux - entry) / (sizeof(struct timespec) + 3 /*Entry::kOverhead?*/);
- if (deferredTimestamp) {
- dumpLine(timestamp, body);
- deferredTimestamp = false;
- }
- timestamp.clear();
- if (n >= kSquashTimestamp) {
- timestamp.appendFormat("[%d.%03d to .%.03d by .%.03d to .%.03d]",
- (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
- (int) ((ts.tv_nsec + deltaTotal) / 1000000),
- (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
- entry = aux;
- // advance = 0;
- break;
- }
- timestamp.appendFormat("[%d.%03d]", (int) ts.tv_sec,
- (int) (ts.tv_nsec / 1000000));
- deferredTimestamp = true;
- }
- break;
- case EVENT_INTEGER:
- appendInt(&body, entry.data());
- break;
- case EVENT_FLOAT:
- appendFloat(&body, entry.data());
- break;
- case EVENT_PID:
- appendPID(&body, entry.data(), entry.length());
- break;
-#endif
case EVENT_START_FMT:
entry = handleFormat(FormatEntry(entry), ×tamp, &body);
break;
@@ -1063,40 +902,12 @@
memcpy(&hash, &(data->hash), sizeof(hash));
int64_t ts;
memcpy(&ts, &data->ts, sizeof(ts));
- const std::pair<log_hash_t, int> key(hash, data->author);
- // TODO might want to filter excessively high outliers, which are usually caused
- // by the thread being inactive.
- mHists[key].push_back(ts);
+ performanceAnalysis.logTsEntry(ts);
++entry;
break;
}
- // draws histograms stored in global Reader::mHists and erases them
- case EVENT_HISTOGRAM_FLUSH: {
- HistogramEntry histEntry(entry);
- // Log timestamp
- // Timestamp of call to drawHistogram, not when audio was generated
- const int64_t ts = histEntry.timestamp();
- timestamp.clear();
- timestamp.appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
- (int) ((ts / (1000 * 1000)) % 1000));
- // Log histograms
- setFindGlitch(true);
- body.appendFormat("Histogram flush - ");
- handleAuthor(histEntry, &body);
- for (auto hist = mHists.begin(); hist != mHists.end();) {
- if (hist->first.second == histEntry.author()) {
- body.appendFormat("%X", (int)hist->first.first);
- if (findGlitch) {
- alertIfGlitch(hist->second);
- }
- // set file to empty and write data for all histograms in this set
- writeHistToFile(hist->second, hist != mHists.begin());
- drawHistogram(&body, hist->second, true, indent);
- hist = mHists.erase(hist);
- } else {
- ++hist;
- }
- }
+ case EVENT_AUDIO_STATE: {
+ performanceAnalysis.handleStateChange();
++entry;
break;
}
@@ -1110,10 +921,10 @@
++entry;
break;
}
-
- if (!body.isEmpty()) {
- dumpLine(timestamp, body);
- }
+ }
+ performanceAnalysis.reportPerformance(&body);
+ if (!body.isEmpty()) {
+ dumpLine(timestamp, body);
}
}
@@ -1139,16 +950,6 @@
return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
}
-void NBLog::Reader::setFindGlitch(bool s)
-{
- findGlitch = s;
-}
-
-bool NBLog::Reader::isFindGlitch() const
-{
- return findGlitch;
-}
-
// ---------------------------------------------------------------------------
void NBLog::appendTimestamp(String8 *body, const void *data) {
@@ -1283,126 +1084,6 @@
return arg;
}
-static int widthOf(int x) {
- int width = 0;
- while (x > 0) {
- ++width;
- x /= 10;
- }
- return width;
-}
-
-static std::map<int, int> buildBuckets(const std::vector<int64_t> &samples) {
- // TODO allow buckets of variable resolution
- std::map<int, int> buckets;
- for (size_t i = 1; i < samples.size(); ++i) {
- ++buckets[deltaMs(samples[i - 1], samples[i])];
- }
- return buckets;
-}
-
-static inline uint32_t log2(uint32_t x) {
- // This works for x > 0
- return 31 - __builtin_clz(x);
-}
-
-// TODO put this function in separate file. Make it return a std::string instead of modifying body
-/*
-Example output:
-[54.234] Histogram flush - AudioOut_D:
-Histogram 33640BF1
- [ 1][ 1][ 1][ 3][54][69][ 1][ 2][ 1]
- 64| []
- 32| [] []
- 16| [] []
- 8| [] []
- 4| [] []
- 2|______________[]__[]__[]______[]____
- 4 5 6 8 9 10 11 13 15
-Notice that all values that fall in the same row have the same height (65 and 127 are displayed
-identically). That's why exact counts are added at the top.
-*/
-void NBLog::Reader::drawHistogram(String8 *body,
- const std::vector<int64_t> &samples,
- bool logScale,
- int indent,
- int maxHeight) {
- // this avoids some corner cases
- if (samples.size() <= 1) {
- return;
- }
- // temp code for debugging the outlier timestamp
- const int kMaxMs = 100;
- for (size_t i = 1; i < samples.size()-1; ++i) {
- const int currDelta = deltaMs(samples[i - 1], samples[i]);
- if (currDelta > kMaxMs) {
- body->appendFormat("\nlocation: %zu, size: %zu, pos from end: %zu, %d\t", i,
- samples.size(), samples.size() - i, currDelta);
- }
- }
- // FIXME: as can be seen when printing the values, the outlier timestamps typically occur
- // in the first histogram 35 to 38 indices from the end (most often 35).
- // TODO: build histogram buckets earlier and discard timestamps to save memory
- std::map<int, int> buckets = buildBuckets(samples);
- // TODO consider changing all ints to uint32_t or uint64_t
-
- // underscores and spaces length corresponds to maximum width of histogram
- static const int kLen = 40;
- std::string underscores(kLen, '-');
- std::string spaces(kLen, ' ');
-
- auto it = buckets.begin();
- int maxDelta = it->first;
- int maxCount = it->second;
- // Compute maximum values
- while (++it != buckets.end()) {
- if (it->first > maxDelta) {
- maxDelta = it->first;
- }
- if (it->second > maxCount) {
- maxCount = it->second;
- }
- }
- int height = logScale ? log2(maxCount) + 1 : maxCount; // maxCount > 0, safe to call log2
- const int leftPadding = widthOf(logScale ? pow(2, height) : maxCount);
- const int colWidth = std::max(std::max(widthOf(maxDelta) + 1, 3), leftPadding + 2);
- int scalingFactor = 1;
- // scale data if it exceeds maximum height
- if (height > maxHeight) {
- scalingFactor = (height + maxHeight) / maxHeight;
- height /= scalingFactor;
- }
- body->appendFormat("\n%*s", leftPadding + 11, "Occurrences");
- // write histogram label line with bucket values
- body->appendFormat("\n%*s", indent, " ");
- body->appendFormat("%*s", leftPadding, " ");
- for (auto const &x : buckets) {
- body->appendFormat("%*d", colWidth, x.second);
- }
- // write histogram ascii art
- body->appendFormat("\n%*s", indent, " ");
- for (int row = height * scalingFactor; row >= 0; row -= scalingFactor) {
- const int value = logScale ? (1 << row) : row;
- body->appendFormat("%.*s", leftPadding, spaces.c_str());
- for (auto const &x : buckets) {
- body->appendFormat("%.*s%s", colWidth - 1, spaces.c_str(), x.second < value ? " " : "|");
- }
- body->appendFormat("\n%*s", indent, " ");
- }
- // print x-axis
- const int columns = static_cast<int>(buckets.size());
- body->appendFormat("%*c", leftPadding, ' ');
- body->appendFormat("%.*s", (columns + 1) * colWidth, underscores.c_str());
- body->appendFormat("\n%*s", indent, " ");
-
- // write footer with bucket labels
- body->appendFormat("%*s", leftPadding, " ");
- for (auto const &x : buckets) {
- body->appendFormat("%*d", colWidth, x.first);
- }
- body->appendFormat("%.*s%s", colWidth, spaces.c_str(), "ms\n");
-}
-
NBLog::Merger::Merger(const void *shared, size_t size):
mShared((Shared *) shared),
mFifo(mShared != NULL ?
diff --git a/media/libnbaio/OWNERS b/media/libnbaio/OWNERS
new file mode 100644
index 0000000..f9cb567
--- /dev/null
+++ b/media/libnbaio/OWNERS
@@ -0,0 +1 @@
+gkasten@google.com
diff --git a/media/libnbaio/PerformanceAnalysis.cpp b/media/libnbaio/PerformanceAnalysis.cpp
new file mode 100644
index 0000000..fb3bddc
--- /dev/null
+++ b/media/libnbaio/PerformanceAnalysis.cpp
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2017 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_TAG "PerformanceAnalysis"
+// #define LOG_NDEBUG 0
+
+#include <algorithm>
+#include <climits>
+#include <deque>
+#include <iostream>
+#include <math.h>
+#include <numeric>
+#include <vector>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <time.h>
+#include <new>
+#include <audio_utils/roundup.h>
+#include <media/nbaio/NBLog.h>
+#include <media/nbaio/PerformanceAnalysis.h>
+#include <media/nbaio/ReportPerformance.h>
+// #include <utils/CallStack.h> // used to print callstack
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <queue>
+#include <utility>
+
+namespace android {
+
+namespace ReportPerformance {
+
+PerformanceAnalysis::PerformanceAnalysis() {
+ // These variables will be (FIXME) learned from the data
+ kPeriodMs = 4; // typical buffer period (mode)
+ // average number of Ms spent processing buffer
+ kPeriodMsCPU = static_cast<int>(kPeriodMs * kRatio);
+}
+
+// converts a time series into a map. key: buffer period length. value: count
+static std::map<int, int> buildBuckets(const std::vector<int64_t> &samples) {
+ // TODO allow buckets of variable resolution
+ std::map<int, int> buckets;
+ for (size_t i = 1; i < samples.size(); ++i) {
+ ++buckets[deltaMs(samples[i - 1], samples[i])];
+ }
+ return buckets;
+}
+
+static int widthOf(int x) {
+ int width = 0;
+ while (x > 0) {
+ ++width;
+ x /= 10;
+ }
+ return width;
+}
+
+// Given a series of audio processing wakeup timestamps,
+// buckets the time intervals into a histogram, searches for
+// outliers, analyzes the outlier series for unexpectedly
+// small or large values and stores these as peaks, and flushes
+// the timestamp series from memory.
+void PerformanceAnalysis::processAndFlushTimeStampSeries() {
+ // 1) analyze the series to store all outliers and their exact timestamps:
+ storeOutlierData(mTimeStampSeries);
+
+ // 2) detect peaks in the outlier series
+ detectPeaks();
+
+ // 3) compute its histogram, append to mRecentHists and clear the time series
+ mRecentHists.emplace_back(static_cast<timestamp>(mTimeStampSeries[0]),
+ buildBuckets(mTimeStampSeries));
+ // do not let mRecentHists exceed capacity
+ // ALOGD("mRecentHists size: %d", static_cast<int>(mRecentHists.size()));
+ if (mRecentHists.size() >= kRecentHistsCapacity) {
+ // ALOGD("popped back mRecentHists");
+ mRecentHists.pop_front();
+ }
+ mTimeStampSeries.clear();
+}
+
+// forces short-term histogram storage to avoid adding idle audio time interval
+// to buffer period data
+void PerformanceAnalysis::handleStateChange() {
+ ALOGD("handleStateChange");
+ processAndFlushTimeStampSeries();
+ return;
+}
+
+// Takes a single buffer period timestamp entry information and stores it in a
+// temporary series of timestamps. Once the series is full, the data is analyzed,
+// stored, and emptied.
+void PerformanceAnalysis::logTsEntry(int64_t ts) {
+ // TODO might want to filter excessively high outliers, which are usually caused
+ // by the thread being inactive.
+ // Store time series data for each reader in order to bucket it once there
+ // is enough data. Then, write to recentHists as a histogram.
+ mTimeStampSeries.push_back(ts);
+ // if length of the time series has reached kShortHistSize samples,
+ // analyze the data and flush the timestamp series from memory
+ if (mTimeStampSeries.size() >= kShortHistSize) {
+ processAndFlushTimeStampSeries();
+ }
+}
+
+// When the short-term histogram array mRecentHists has reached capacity,
+// merge histograms for data compression and store them in mLongTermHists
+// clears mRecentHists
+// TODO: have logTsEntry write directly to mLongTermHists, discard mRecentHists,
+// start a new histogram when a peak occurs
+void PerformanceAnalysis::processAndFlushRecentHists() {
+
+ // Buckets is used to aggregate short-term histograms.
+ Histogram buckets;
+ timestamp startingTs = mRecentHists[0].first;
+
+ for (const auto &shortHist: mRecentHists) {
+ // If the time between starting and ending timestamps has reached the maximum,
+ // add the current histogram (buckets) to the long-term histogram buffer,
+ // clear buckets, and start a new long-term histogram aggregation process.
+ if (deltaMs(startingTs, shortHist.first) >= kMaxHistTimespanMs) {
+ mLongTermHists.emplace_back(startingTs, std::move(buckets));
+ buckets.clear();
+ startingTs = shortHist.first;
+ // When memory is full, delete oldest histogram
+ // TODO use a circular buffer
+ if (mLongTermHists.size() >= kLongTermHistsCapacity) {
+ mLongTermHists.pop_front();
+ }
+ }
+
+ // add current histogram to buckets
+ for (const auto &countPair : shortHist.second) {
+ buckets[countPair.first] += countPair.second;
+ }
+ }
+ mRecentHists.clear();
+ // TODO: decide when/where to call writeToFile
+ // TODO: add a thread-specific extension to the file name
+ static const char* const kName = (const char *) "/data/misc/audioserver/sample_results.txt";
+ writeToFile(mOutlierData, mLongTermHists, kName, false);
+}
+
+// Given a series of outlier intervals (mOutlier data),
+// looks for changes in distribution (peaks), which can be either positive or negative.
+// The function sets the mean to the starting value and sigma to 0, and updates
+// them as long as no peak is detected. When a value is more than 'threshold'
+// standard deviations from the mean, a peak is detected and the mean and sigma
+// are set to the peak value and 0.
+void PerformanceAnalysis::detectPeaks() {
+ if (mOutlierData.empty()) {
+ return;
+ }
+
+ // compute mean of the distribution. Used to check whether a value is large
+ const double kTypicalDiff = std::accumulate(
+ mOutlierData.begin(), mOutlierData.end(), 0,
+ [](auto &a, auto &b){return a + b.first;}) / mOutlierData.size();
+ // ALOGD("typicalDiff %f", kTypicalDiff);
+
+ // iterator at the beginning of a sequence, or updated to the most recent peak
+ std::deque<std::pair<uint64_t, uint64_t>>::iterator start = mOutlierData.begin();
+ // the mean and standard deviation are updated every time a peak is detected
+ // initialize first time. The mean from the previous sequence is stored
+ // for the next sequence. Here, they are initialized for the first time.
+ if (mPeakDetectorMean < 0) {
+ mPeakDetectorMean = static_cast<double>(start->first);
+ mPeakDetectorSd = 0;
+ }
+ auto sqr = [](auto x){ return x * x; };
+ for (auto it = mOutlierData.begin(); it != mOutlierData.end(); ++it) {
+ // no surprise occurred:
+ // the new element is a small number of standard deviations from the mean
+ if ((fabs(it->first - mPeakDetectorMean) < kStddevThreshold * mPeakDetectorSd) ||
+ // or: right after peak has been detected, the delta is smaller than average
+ (mPeakDetectorSd == 0 && fabs(it->first - mPeakDetectorMean) < kTypicalDiff)) {
+ // update the mean and sd:
+ // count number of elements (distance between start interator and current)
+ const int kN = std::distance(start, it) + 1;
+ // usual formulas for mean and sd
+ mPeakDetectorMean = std::accumulate(start, it + 1, 0.0,
+ [](auto &a, auto &b){return a + b.first;}) / kN;
+ mPeakDetectorSd = sqrt(std::accumulate(start, it + 1, 0.0,
+ [=](auto &a, auto &b){ return a + sqr(b.first - mPeakDetectorMean);})) /
+ ((kN > 1)? kN - 1 : kN); // kN - 1: mean is correlated with variance
+ }
+ // surprising value: store peak timestamp and reset mean, sd, and start iterator
+ else {
+ mPeakTimestamps.emplace_back(it->second);
+ // TODO: remove pop_front once a circular buffer is in place
+ if (mPeakTimestamps.size() >= kPeakSeriesSize) {
+ mPeakTimestamps.pop_front();
+ }
+ mPeakDetectorMean = static_cast<double>(it->first);
+ mPeakDetectorSd = 0;
+ start = it;
+ }
+ }
+ return;
+}
+
+// Called by LogTsEntry. The input is a vector of timestamps.
+// Finds outliers and writes to mOutlierdata.
+// Each value in mOutlierdata consists of: <outlier timestamp, time elapsed since previous outlier>.
+// e.g. timestamps (ms) 1, 4, 5, 16, 18, 28 will produce pairs (4, 5), (13, 18).
+// This function is applied to the time series before it is converted into a histogram.
+void PerformanceAnalysis::storeOutlierData(const std::vector<int64_t> ×tamps) {
+ if (timestamps.size() < 1) {
+ return;
+ }
+ // first pass: need to initialize
+ if (mElapsed == 0) {
+ mPrevNs = timestamps[0];
+ }
+ for (const auto &ts: timestamps) {
+ const uint64_t diffMs = static_cast<uint64_t>(deltaMs(mPrevNs, ts));
+ if (diffMs >= static_cast<uint64_t>(kOutlierMs)) {
+ mOutlierData.emplace_back(mElapsed, static_cast<uint64_t>(mPrevNs));
+ // Remove oldest value if the vector is full
+ // TODO: remove pop_front once circular buffer is in place
+ // FIXME: make sure kShortHistSize is large enough that that data will never be lost
+ // before being written to file or to a FIFO
+ if (mOutlierData.size() >= kOutlierSeriesSize) {
+ mOutlierData.pop_front();
+ }
+ mElapsed = 0;
+ }
+ mElapsed += diffMs;
+ mPrevNs = ts;
+ }
+}
+
+
+// FIXME: delete this temporary test code, recycled for various new functions
+void PerformanceAnalysis::testFunction() {
+ // produces values (4: 5000000), (13: 18000000)
+ // ns timestamps of buffer periods
+ const std::vector<int64_t>kTempTestData = {1000000, 4000000, 5000000,
+ 16000000, 18000000, 28000000};
+ PerformanceAnalysis::storeOutlierData(kTempTestData);
+ for (const auto &outlier: mOutlierData) {
+ ALOGE("PerformanceAnalysis test %lld: %lld",
+ static_cast<long long>(outlier.first), static_cast<long long>(outlier.second));
+ }
+ detectPeaks();
+}
+
+// TODO Make it return a std::string instead of modifying body --> is this still relevant?
+// TODO consider changing all ints to uint32_t or uint64_t
+// TODO: move this to ReportPerformance, probably make it a friend function of PerformanceAnalysis
+void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) {
+ if (mRecentHists.size() < 1) {
+ ALOGD("reportPerformance: mRecentHists is empty");
+ return;
+ }
+ ALOGD("reportPerformance: hists size %d", static_cast<int>(mRecentHists.size()));
+ // TODO: more elaborate data analysis
+ std::map<int, int> buckets;
+ for (const auto &shortHist: mRecentHists) {
+ for (const auto &countPair : shortHist.second) {
+ buckets[countPair.first] += countPair.second;
+ }
+ }
+
+ // underscores and spaces length corresponds to maximum width of histogram
+ static const int kLen = 40;
+ std::string underscores(kLen, '_');
+ std::string spaces(kLen, ' ');
+
+ auto it = buckets.begin();
+ int maxDelta = it->first;
+ int maxCount = it->second;
+ // Compute maximum values
+ while (++it != buckets.end()) {
+ if (it->first > maxDelta) {
+ maxDelta = it->first;
+ }
+ if (it->second > maxCount) {
+ maxCount = it->second;
+ }
+ }
+ int height = log2(maxCount) + 1; // maxCount > 0, safe to call log2
+ const int leftPadding = widthOf(1 << height);
+ const int colWidth = std::max(std::max(widthOf(maxDelta) + 1, 3), leftPadding + 2);
+ int scalingFactor = 1;
+ // scale data if it exceeds maximum height
+ if (height > maxHeight) {
+ scalingFactor = (height + maxHeight) / maxHeight;
+ height /= scalingFactor;
+ }
+ body->appendFormat("\n%*s", leftPadding + 11, "Occurrences");
+ // write histogram label line with bucket values
+ body->appendFormat("\n%s", " ");
+ body->appendFormat("%*s", leftPadding, " ");
+ for (auto const &x : buckets) {
+ body->appendFormat("%*d", colWidth, x.second);
+ }
+ // write histogram ascii art
+ body->appendFormat("\n%s", " ");
+ for (int row = height * scalingFactor; row >= 0; row -= scalingFactor) {
+ const int value = 1 << row;
+ body->appendFormat("%.*s", leftPadding, spaces.c_str());
+ for (auto const &x : buckets) {
+ body->appendFormat("%.*s%s", colWidth - 1, spaces.c_str(), x.second < value ? " " : "|");
+ }
+ body->appendFormat("\n%s", " ");
+ }
+ // print x-axis
+ const int columns = static_cast<int>(buckets.size());
+ body->appendFormat("%*c", leftPadding, ' ');
+ body->appendFormat("%.*s", (columns + 1) * colWidth, underscores.c_str());
+ body->appendFormat("\n%s", " ");
+
+ // write footer with bucket labels
+ body->appendFormat("%*s", leftPadding, " ");
+ for (auto const &x : buckets) {
+ body->appendFormat("%*d", colWidth, x.first);
+ }
+ body->appendFormat("%.*s%s", colWidth, spaces.c_str(), "ms\n");
+
+ // Now report glitches
+ body->appendFormat("\ntime elapsed between glitches and glitch timestamps\n");
+ for (const auto &outlier: mOutlierData) {
+ body->appendFormat("%lld: %lld\n", static_cast<long long>(outlier.first),
+ static_cast<long long>(outlier.second));
+ }
+
+}
+
+
+// Produces a log warning if the timing of recent buffer periods caused a glitch
+// Computes sum of running window of three buffer periods
+// Checks whether the buffer periods leave enough CPU time for the next one
+// e.g. if a buffer period is expected to be 4 ms and a buffer requires 3 ms of CPU time,
+// here are some glitch cases:
+// 4 + 4 + 6 ; 5 + 4 + 5; 2 + 2 + 10
+// TODO: develop this code to track changes in histogram distribution in addition
+// to / instead of glitches.
+void PerformanceAnalysis::alertIfGlitch(const std::vector<int64_t> &samples) {
+ std::deque<int> periods(kNumBuff, kPeriodMs);
+ for (size_t i = 2; i < samples.size(); ++i) { // skip first time entry
+ periods.push_front(deltaMs(samples[i - 1], samples[i]));
+ periods.pop_back();
+ // TODO: check that all glitch cases are covered
+ if (std::accumulate(periods.begin(), periods.end(), 0) > kNumBuff * kPeriodMs +
+ kPeriodMs - kPeriodMsCPU) {
+ ALOGW("A glitch occurred");
+ periods.assign(kNumBuff, kPeriodMs);
+ }
+ }
+ return;
+}
+
+} // namespace ReportPerformance
+
+} // namespace android
diff --git a/media/libnbaio/ReportPerformance.cpp b/media/libnbaio/ReportPerformance.cpp
new file mode 100644
index 0000000..dc50ada
--- /dev/null
+++ b/media/libnbaio/ReportPerformance.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 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_TAG "ReportPerformance"
+
+#include <fstream>
+#include <iostream>
+#include <queue>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <utility>
+#include <media/nbaio/NBLog.h>
+#include <media/nbaio/PerformanceAnalysis.h>
+#include <media/nbaio/ReportPerformance.h>
+// #include <utils/CallStack.h> // used to print callstack
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+namespace android {
+
+namespace ReportPerformance {
+
+// Writes outlier intervals, timestamps, and histograms spanning long time intervals to a file.
+// TODO: format the data efficiently and write different types of data to different files
+void writeToFile(std::deque<std::pair<outlierInterval, timestamp>> &outlierData,
+ std::deque<std::pair<timestamp, Histogram>> &hists,
+ const char * kName,
+ bool append) {
+ ALOGD("writing performance data to file");
+ if (outlierData.empty() || hists.empty()) {
+ return;
+ }
+
+ std::ofstream ofs;
+ ofs.open(kName, append ? std::ios::app : std::ios::trunc);
+ if (!ofs.is_open()) {
+ ALOGW("couldn't open file %s", kName);
+ return;
+ }
+ ofs << "Outlier data: interval and timestamp\n";
+ for (const auto &outlier : outlierData) {
+ ofs << outlier.first << ": " << outlier.second << "\n";
+ }
+ ofs << "Histogram data\n";
+ for (const auto &hist : hists) {
+ ofs << "\ttimestamp\n";
+ ofs << hist.first << "\n";
+ ofs << "\tbuckets and counts\n";
+ for (const auto &bucket : hist.second) {
+ ofs << bucket.first << ": " << bucket.second << "\n";
+ }
+ }
+ ofs.close();
+}
+
+} // namespace ReportPerformance
+
+} // namespace android
diff --git a/media/libnbaio/include/AudioBufferProviderSource.h b/media/libnbaio/include/media/nbaio/AudioBufferProviderSource.h
similarity index 98%
rename from media/libnbaio/include/AudioBufferProviderSource.h
rename to media/libnbaio/include/media/nbaio/AudioBufferProviderSource.h
index 4747dcf..71182bb 100644
--- a/media/libnbaio/include/AudioBufferProviderSource.h
+++ b/media/libnbaio/include/media/nbaio/AudioBufferProviderSource.h
@@ -19,8 +19,8 @@
#ifndef ANDROID_AUDIO_BUFFER_PROVIDER_SOURCE_H
#define ANDROID_AUDIO_BUFFER_PROVIDER_SOURCE_H
-#include "NBAIO.h"
#include <media/AudioBufferProvider.h>
+#include <media/nbaio/NBAIO.h>
namespace android {
diff --git a/media/libnbaio/include/AudioStreamInSource.h b/media/libnbaio/include/media/nbaio/AudioStreamInSource.h
similarity index 98%
rename from media/libnbaio/include/AudioStreamInSource.h
rename to media/libnbaio/include/media/nbaio/AudioStreamInSource.h
index 508e0fe..8a3ffbe 100644
--- a/media/libnbaio/include/AudioStreamInSource.h
+++ b/media/libnbaio/include/media/nbaio/AudioStreamInSource.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_AUDIO_STREAM_IN_SOURCE_H
#define ANDROID_AUDIO_STREAM_IN_SOURCE_H
-#include "NBAIO.h"
+#include <media/nbaio/NBAIO.h>
namespace android {
diff --git a/media/libnbaio/include/AudioStreamOutSink.h b/media/libnbaio/include/media/nbaio/AudioStreamOutSink.h
similarity index 98%
rename from media/libnbaio/include/AudioStreamOutSink.h
rename to media/libnbaio/include/media/nbaio/AudioStreamOutSink.h
index 56a2a38..348b4f8 100644
--- a/media/libnbaio/include/AudioStreamOutSink.h
+++ b/media/libnbaio/include/media/nbaio/AudioStreamOutSink.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_AUDIO_STREAM_OUT_SINK_H
#define ANDROID_AUDIO_STREAM_OUT_SINK_H
-#include "NBAIO.h"
+#include <media/nbaio/NBAIO.h>
namespace android {
diff --git a/media/libnbaio/include/LibsndfileSink.h b/media/libnbaio/include/media/nbaio/LibsndfileSink.h
similarity index 97%
rename from media/libnbaio/include/LibsndfileSink.h
rename to media/libnbaio/include/media/nbaio/LibsndfileSink.h
index 97a57e0..535e3f5 100644
--- a/media/libnbaio/include/LibsndfileSink.h
+++ b/media/libnbaio/include/media/nbaio/LibsndfileSink.h
@@ -17,7 +17,8 @@
#ifndef ANDROID_AUDIO_LIBSNDFILE_SINK_H
#define ANDROID_AUDIO_LIBSNDFILE_SINK_H
-#include "NBAIO.h"
+#include <media/nbaio/NBAIO.h>
+
#include "sndfile.h"
// Implementation of NBAIO_Sink that wraps a libsndfile opened in SFM_WRITE mode
diff --git a/media/libnbaio/include/LibsndfileSource.h b/media/libnbaio/include/media/nbaio/LibsndfileSource.h
similarity index 97%
rename from media/libnbaio/include/LibsndfileSource.h
rename to media/libnbaio/include/media/nbaio/LibsndfileSource.h
index 4fbdb4b..bc6aa9d 100644
--- a/media/libnbaio/include/LibsndfileSource.h
+++ b/media/libnbaio/include/media/nbaio/LibsndfileSource.h
@@ -17,7 +17,8 @@
#ifndef ANDROID_AUDIO_LIBSNDFILE_SOURCE_H
#define ANDROID_AUDIO_LIBSNDFILE_SOURCE_H
-#include "NBAIO.h"
+#include <media/nbaio/NBAIO.h>
+
#include "sndfile.h"
// Implementation of NBAIO_Source that wraps a libsndfile opened in SFM_READ mode
diff --git a/media/libnbaio/include/NBLog.h b/media/libnbaio/include/media/nbaio/NBLog.h
similarity index 95%
rename from media/libnbaio/include/NBLog.h
rename to media/libnbaio/include/media/nbaio/NBLog.h
index 785b9c2..3e48ee1 100644
--- a/media/libnbaio/include/NBLog.h
+++ b/media/libnbaio/include/media/nbaio/NBLog.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -25,6 +25,7 @@
#include <utils/threads.h>
#include <map>
+#include <deque>
#include <set>
#include <vector>
@@ -43,8 +44,6 @@
class Writer;
class Reader;
-private:
-
enum Event : uint8_t {
EVENT_RESERVED,
EVENT_STRING, // ASCII string, not NUL-terminated
@@ -59,12 +58,13 @@
EVENT_HASH, // unique HASH of log origin, originates from hash of file name
// and line number
EVENT_HISTOGRAM_ENTRY_TS, // single datum for timestamp histogram
- EVENT_HISTOGRAM_FLUSH, // show histogram on log
+ EVENT_AUDIO_STATE, // audio on/off event: logged upon FastMixer::onStateChange() call
EVENT_END_FMT, // end of logFormat argument list
EVENT_UPPER_BOUND, // to check for invalid events
};
+private:
// ---------------------------------------------------------------------------
// API for handling format entry operations
@@ -248,6 +248,8 @@
int author;
}; //TODO __attribute__((packed));
+using StateTsEntryWithAuthor = HistTsEntryWithAuthor;
+
struct HistIntEntry {
log_hash_t hash;
int value;
@@ -341,8 +343,7 @@
virtual void logStart(const char *fmt);
virtual void logEnd();
virtual void logHash(log_hash_t hash);
- virtual void logHistTS(log_hash_t hash);
- virtual void logHistFlush(log_hash_t hash);
+ virtual void logEventHistTs(Event event, log_hash_t hash);
virtual bool isEnabled() const;
@@ -407,6 +408,7 @@
public:
// A snapshot of a readers buffer
+ // This is raw data. No analysis has been done on it
class Snapshot {
public:
Snapshot() : mData(NULL), mLost(0) {}
@@ -443,20 +445,17 @@
virtual ~Reader();
- void alertIfGlitch(const std::vector<int64_t> &samples);
-
// get snapshot of readers fifo buffer, effectively consuming the buffer
std::unique_ptr<Snapshot> getSnapshot();
// dump a particular snapshot of the reader
+ // TODO: move dump to PerformanceAnalysis. Model/view/controller design
void dump(int fd, size_t indent, Snapshot & snap);
// dump the current content of the reader's buffer (call getSnapshot() and previous dump())
void dump(int fd, size_t indent = 0);
bool isIMemory(const sp<IMemory>& iMemory) const;
- // if findGlitch is true, log warning when buffer periods caused glitch
- void setFindGlitch(bool s);
- bool isFindGlitch() const;
private:
+
static const std::set<Event> startingTypes;
static const std::set<Event> endingTypes;
/*const*/ Shared* const mShared; // raw pointer to shared memory, actually const but not
@@ -469,10 +468,6 @@
audio_utils_fifo_reader * const mFifoReader; // used to read from FIFO,
// non-NULL unless constructor fails
- // each pair contains a sequence of timestamps (one histogram's worth)
- // pair's log_hash_t is the hash of the source code location where the timestamp was taken
- // pair's int points to the Reader that originated the entry
- std::map<std::pair<log_hash_t, int>, std::vector<int64_t>> mHists;
// TODO: it might be clearer, instead of a direct map from source location to vector of
// timestamps, if we instead first mapped from source location to an object that
// represented that location. And one_of its fields would be a vector of timestamps.
@@ -485,17 +480,12 @@
// dummy method for handling absent author entry
virtual void handleAuthor(const AbstractEntry& /*fmtEntry*/, String8* /*body*/) {}
- static void drawHistogram(String8 *body, const std::vector<int64_t> &samples,
- bool logScale, int indent = 0, int maxHeight = 10);
-
// Searches for the last entry of type <type> in the range [front, back)
// back has to be entry-aligned. Returns nullptr if none enconuntered.
static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
const std::set<Event> &types);
static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
-
- bool findGlitch; // alert if a local buffer period sequence caused an audio glitch
};
// Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
diff --git a/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h b/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
new file mode 100644
index 0000000..b0dc148
--- /dev/null
+++ b/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+// Non-blocking event logger intended for safe communication between processes via shared memory
+
+#ifndef ANDROID_MEDIA_PERFORMANCEANALYSIS_H
+#define ANDROID_MEDIA_PERFORMANCEANALYSIS_H
+
+#include <map>
+#include <deque>
+#include <vector>
+#include "NBLog.h"
+#include "ReportPerformance.h"
+
+namespace android {
+
+namespace ReportPerformance {
+
+class PerformanceAnalysis {
+ // This class stores and analyzes audio processing wakeup timestamps from NBLog
+ // FIXME: currently, all performance data is stored in deques. Need to add a mutex.
+ // FIXME: continue this way until analysis is done in a separate thread. Then, use
+ // the fifo writer utilities.
+public:
+
+ PerformanceAnalysis();
+
+ // Given a series of audio processing wakeup timestamps,
+ // compresses and and analyzes the data, and flushes
+ // the timestamp series from memory.
+ void processAndFlushTimeStampSeries();
+
+ // Called when an audio on/off event is read from the buffer,
+ // e.g. EVENT_AUDIO_STATE.
+ // calls flushTimeStampSeries on the data up to the event,
+ // effectively discarding the idle audio time interval
+ void handleStateChange();
+
+ // When the short-term histogram array mRecentHists has reached capacity,
+ // merges histograms for data compression and stores them in mLongTermHists
+ void processAndFlushRecentHists();
+
+ // Writes wakeup timestamp entry to log and runs analysis
+ // TODO: make this thread safe. Each thread should have its own instance
+ // of PerformanceAnalysis.
+ void logTsEntry(timestamp_raw ts);
+
+ // FIXME: make peakdetector and storeOutlierData a single function
+ // Input: mOutlierData. Looks at time elapsed between outliers
+ // finds significant changes in the distribution
+ // writes timestamps of significant changes to mPeakTimestamps
+ void detectPeaks();
+
+ // runs analysis on timestamp series before it is converted to a histogram
+ // finds outliers
+ // writes to mOutlierData <time elapsed since previous outlier, outlier timestamp>
+ void storeOutlierData(const std::vector<timestamp_raw> ×tamps);
+
+ // input: series of short histograms. Generates a string of analysis of the buffer periods
+ // TODO: WIP write more detailed analysis
+ // FIXME: move this data visualization to a separate class. Model/view/controller
+ void reportPerformance(String8 *body, int maxHeight = 10);
+
+ // TODO: delete this. temp for testing
+ void testFunction();
+
+ // This function used to detect glitches in a time series
+ // TODO incorporate this into the analysis (currently unused)
+ void alertIfGlitch(const std::vector<timestamp_raw> &samples);
+
+private:
+
+ // stores outlier analysis: <elapsed time between outliers in ms, outlier timestamp>
+ std::deque<std::pair<outlierInterval, timestamp>> mOutlierData;
+
+ // stores each timestamp at which a peak was detected
+ // a peak is a moment at which the average outlier interval changed significantly
+ std::deque<timestamp> mPeakTimestamps;
+
+ // TODO: turn these into circular buffers for better data flow
+ // FIFO of small histograms
+ // stores fixed-size short buffer period histograms with timestamp of first sample
+ std::deque<std::pair<timestamp, Histogram>> mRecentHists;
+
+ // FIFO of small histograms
+ // stores fixed-size long-term buffer period histograms with timestamp of first sample
+ std::deque<std::pair<timestamp, Histogram>> mLongTermHists;
+
+ // vector of timestamps, collected from NBLog for a (TODO) specific thread
+ // when a vector reaches its maximum size, the data is processed and flushed
+ std::vector<timestamp_raw> mTimeStampSeries;
+
+ static const int kMsPerSec = 1000;
+
+ // Parameters used when detecting outliers
+ // TODO: learn some of these from the data, delete unused ones
+ // FIXME: decide whether to make kPeriodMs static.
+ static const int kNumBuff = 3; // number of buffers considered in local history
+ int kPeriodMs; // current period length is ideally 4 ms
+ static const int kOutlierMs = 7; // values greater or equal to this cause glitches
+ // DAC processing time for 4 ms buffer
+ static constexpr double kRatio = 0.75; // estimate of CPU time as ratio of period length
+ int kPeriodMsCPU; // compute based on kPeriodLen and kRatio
+
+ // Peak detection: number of standard deviations from mean considered a significant change
+ static const int kStddevThreshold = 5;
+
+ // capacity allocated to data structures
+ // TODO: adjust all of these values
+ static const int kRecentHistsCapacity = 100; // number of short-term histograms stored in memory
+ static const int kShortHistSize = 50; // number of samples in a short-term histogram
+ static const int kOutlierSeriesSize = 100; // number of values stored in outlier array
+ static const int kPeakSeriesSize = 100; // number of values stored in peak array
+ static const int kLongTermHistsCapacity = 20; // number of long-term histogram stored in memory
+ // maximum elapsed time between first and last timestamp of a long-term histogram
+ static const int kMaxHistTimespanMs = 5 * kMsPerSec;
+
+ // these variables are stored in-class to ensure continuity while analyzing the timestamp
+ // series one short sequence at a time: the variables are not re-initialized every time.
+ // FIXME: create inner class for these variables and decide which other ones to add to it
+ double mPeakDetectorMean = -1;
+ double mPeakDetectorSd = -1;
+ // variables for storeOutlierData
+ uint64_t mElapsed = 0;
+ int64_t mPrevNs = -1;
+
+};
+
+} // namespace ReportPerformance
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_PERFORMANCEANALYSIS_H
diff --git a/media/libnbaio/include/Pipe.h b/media/libnbaio/include/media/nbaio/Pipe.h
similarity index 98%
rename from media/libnbaio/include/Pipe.h
rename to media/libnbaio/include/media/nbaio/Pipe.h
index 58b9750..0431976 100644
--- a/media/libnbaio/include/Pipe.h
+++ b/media/libnbaio/include/media/nbaio/Pipe.h
@@ -18,7 +18,7 @@
#define ANDROID_AUDIO_PIPE_H
#include <audio_utils/fifo.h>
-#include "NBAIO.h"
+#include <media/nbaio/NBAIO.h>
namespace android {
diff --git a/media/libnbaio/include/PipeReader.h b/media/libnbaio/include/media/nbaio/PipeReader.h
similarity index 100%
rename from media/libnbaio/include/PipeReader.h
rename to media/libnbaio/include/media/nbaio/PipeReader.h
diff --git a/media/libnbaio/include/media/nbaio/ReportPerformance.h b/media/libnbaio/include/media/nbaio/ReportPerformance.h
new file mode 100644
index 0000000..27d2810
--- /dev/null
+++ b/media/libnbaio/include/media/nbaio/ReportPerformance.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 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_MEDIA_REPORTPERFORMANCE_H
+#define ANDROID_MEDIA_REPORTPERFORMANCE_H
+
+#include <deque>
+#include <map>
+#include <vector>
+
+namespace android {
+
+// This class is used by reportPerformance function
+// TODO move reportPerformance function to ReportPerformance.cpp
+class String8;
+
+namespace ReportPerformance {
+
+// stores a histogram: key: observed buffer period. value: count
+// TODO: unsigned, unsigned
+using Histogram = std::map<int, int>;
+
+using outlierInterval = uint64_t;
+// int64_t timestamps are converted to uint64_t in PerformanceAnalysis::storeOutlierData,
+// and all analysis functions use uint64_t.
+using timestamp = uint64_t;
+using timestamp_raw = int64_t;
+
+// FIXME: decide whether to use 64 or 32 bits
+// TODO: the code has a mix of typedef and using. Standardize to one or the other.
+typedef uint64_t log_hash_t;
+
+static inline int deltaMs(int64_t ns1, int64_t ns2) {
+ return (ns2 - ns1) / (1000 * 1000);
+}
+
+static inline uint32_t log2(uint32_t x) {
+ // This works for x > 0
+ return 31 - __builtin_clz(x);
+}
+
+// Writes outlier intervals, timestamps, and histograms spanning long time
+// intervals to a file.
+void writeToFile(std::deque<std::pair<outlierInterval, timestamp>> &outlierData,
+ std::deque<std::pair<timestamp, Histogram>> &hists,
+ const char * kName,
+ bool append);
+
+} // namespace ReportPerformance
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_REPORTPERFORMANCE_H
diff --git a/media/libnbaio/include/SourceAudioBufferProvider.h b/media/libnbaio/include/media/nbaio/SourceAudioBufferProvider.h
similarity index 98%
rename from media/libnbaio/include/SourceAudioBufferProvider.h
rename to media/libnbaio/include/media/nbaio/SourceAudioBufferProvider.h
index ae49903..cc2d019 100644
--- a/media/libnbaio/include/SourceAudioBufferProvider.h
+++ b/media/libnbaio/include/media/nbaio/SourceAudioBufferProvider.h
@@ -19,7 +19,7 @@
#ifndef ANDROID_SOURCE_AUDIO_BUFFER_PROVIDER_H
#define ANDROID_SOURCE_AUDIO_BUFFER_PROVIDER_H
-#include "NBAIO.h"
+#include <media/nbaio/NBAIO.h>
#include <media/ExtendedAudioBufferProvider.h>
namespace android {
diff --git a/media/libnbaio/include/MonoPipe.h b/media/libnbaio/include_mono/media/nbaio/MonoPipe.h
similarity index 98%
rename from media/libnbaio/include/MonoPipe.h
rename to media/libnbaio/include_mono/media/nbaio/MonoPipe.h
index 60ae92e..c51d0fe 100644
--- a/media/libnbaio/include/MonoPipe.h
+++ b/media/libnbaio/include_mono/media/nbaio/MonoPipe.h
@@ -20,7 +20,7 @@
#include <time.h>
#include <audio_utils/fifo.h>
#include <media/SingleStateQueue.h>
-#include "NBAIO.h"
+#include <media/nbaio/NBAIO.h>
namespace android {
diff --git a/media/libnbaio/include/MonoPipeReader.h b/media/libnbaio/include_mono/media/nbaio/MonoPipeReader.h
similarity index 100%
rename from media/libnbaio/include/MonoPipeReader.h
rename to media/libnbaio/include_mono/media/nbaio/MonoPipeReader.h
diff --git a/media/libnbaio/include/NBAIO.h b/media/libnbaio/include_mono/media/nbaio/NBAIO.h
similarity index 100%
rename from media/libnbaio/include/NBAIO.h
rename to media/libnbaio/include_mono/media/nbaio/NBAIO.h
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 01f09be..a2eb9a8 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -49,21 +49,18 @@
#include <hidlmemory/mapping.h>
-#include <OMX_AudioExt.h>
-#include <OMX_VideoExt.h>
-#include <OMX_Component.h>
-#include <OMX_IndexExt.h>
-#include <OMX_AsString.h>
+#include <media/openmax/OMX_AudioExt.h>
+#include <media/openmax/OMX_VideoExt.h>
+#include <media/openmax/OMX_Component.h>
+#include <media/openmax/OMX_IndexExt.h>
+#include <media/openmax/OMX_AsString.h>
#include "include/avc_utils.h"
#include "include/ACodecBufferChannel.h"
#include "include/DataConverter.h"
#include "include/SecureBuffer.h"
#include "include/SharedMemoryBuffer.h"
-#include "omx/OMXUtils.h"
-
-#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <android/hidl/memory/1.0/IMemory.h>
+#include <media/stagefright/omx/OMXUtils.h>
namespace android {
@@ -1866,16 +1863,15 @@
mFlags |= kFlagIsGrallocUsageProtected;
mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown;
}
+ }
+ if (mFlags & kFlagIsSecure) {
+ // use native_handles for secure input buffers
+ err = setPortMode(kPortIndexInput, IOMX::kPortModePresetSecureBuffer);
- if (mFlags & kFlagIsSecure) {
- // use native_handles for secure input buffers
- err = setPortMode(kPortIndexInput, IOMX::kPortModePresetSecureBuffer);
-
- if (err != OK) {
- ALOGI("falling back to non-native_handles");
- setPortMode(kPortIndexInput, IOMX::kPortModePresetByteBuffer);
- err = OK; // ignore error for now
- }
+ if (err != OK) {
+ ALOGI("falling back to non-native_handles");
+ setPortMode(kPortIndexInput, IOMX::kPortModePresetByteBuffer);
+ err = OK; // ignore error for now
}
}
if (haveNativeWindow) {
@@ -4174,11 +4170,12 @@
// static
int /* OMX_VIDEO_AVCLEVELTYPE */ ACodec::getAVCLevelFor(
int width, int height, int rate, int bitrate,
- OMX_VIDEO_AVCPROFILETYPE profile) {
+ OMX_VIDEO_AVCPROFILEEXTTYPE profile) {
// convert bitrate to main/baseline profile kbps equivalent
- switch (profile) {
+ switch ((uint32_t)profile) {
case OMX_VIDEO_AVCProfileHigh10:
bitrate = divUp(bitrate, 3000); break;
+ case OMX_VIDEO_AVCProfileConstrainedHigh:
case OMX_VIDEO_AVCProfileHigh:
bitrate = divUp(bitrate, 1250); break;
default:
@@ -4322,9 +4319,14 @@
h264type.bUseHadamard = OMX_TRUE;
h264type.nRefFrames = 2;
h264type.nBFrames = mLatency == 0 ? 1 : std::min(1U, mLatency - 1);
+
+ // disable B-frames until MPEG4Writer can guarantee finalizing files with B-frames
+ h264type.nRefFrames = 1;
+ h264type.nBFrames = 0;
+
h264type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate, h264type.nBFrames);
h264type.nAllowedPictureTypes =
- OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP | OMX_VIDEO_PictureTypeB;
+ OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
h264type.nRefIdx10ActiveMinus1 = 0;
h264type.nRefIdx11ActiveMinus1 = 0;
h264type.bEntropyCodingCABAC = OMX_TRUE;
@@ -4843,9 +4845,9 @@
rect.nTop < 0 ||
rect.nLeft + rect.nWidth > videoDef->nFrameWidth ||
rect.nTop + rect.nHeight > videoDef->nFrameHeight) {
- ALOGE("Wrong cropped rect (%d, %d) - (%u, %u) vs. frame (%u, %u)",
+ ALOGE("Wrong cropped rect (%d, %d, %u, %u) vs. frame (%u, %u)",
rect.nLeft, rect.nTop,
- rect.nLeft + rect.nWidth, rect.nTop + rect.nHeight,
+ rect.nWidth, rect.nHeight,
videoDef->nFrameWidth, videoDef->nFrameHeight);
return BAD_VALUE;
}
@@ -6340,19 +6342,10 @@
CHECK(mCodec->mOMXNode == NULL);
- OMXClient client;
- bool trebleFlag;
- if (client.connect(&trebleFlag) != OK) {
- mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
- return false;
- }
- mCodec->setTrebleFlag(trebleFlag);
-
- sp<IOMX> omx = client.interface();
-
sp<AMessage> notify = new AMessage(kWhatOMXDied, mCodec);
Vector<AString> matchingCodecs;
+ Vector<AString> owners;
AString mime;
@@ -6360,9 +6353,31 @@
int32_t encoder = false;
if (msg->findString("componentName", &componentName)) {
sp<IMediaCodecList> list = MediaCodecList::getInstance();
- if (list != NULL && list->findCodecByName(componentName.c_str()) >= 0) {
- matchingCodecs.add(componentName);
+ if (list == nullptr) {
+ ALOGE("Unable to obtain MediaCodecList while "
+ "attempting to create codec \"%s\"",
+ componentName.c_str());
+ mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
+ return false;
}
+ ssize_t index = list->findCodecByName(componentName.c_str());
+ if (index < 0) {
+ ALOGE("Unable to find codec \"%s\"",
+ componentName.c_str());
+ mCodec->signalError(OMX_ErrorInvalidComponent, NAME_NOT_FOUND);
+ return false;
+ }
+ sp<MediaCodecInfo> info = list->getCodecInfo(index);
+ if (info == nullptr) {
+ ALOGE("Unexpected error (index out-of-bound) while "
+ "retrieving information for codec \"%s\"",
+ componentName.c_str());
+ mCodec->signalError(OMX_ErrorUndefined, UNKNOWN_ERROR);
+ return false;
+ }
+ matchingCodecs.add(info->getCodecName());
+ owners.add(info->getOwnerName() == nullptr ?
+ "default" : info->getOwnerName());
} else {
CHECK(msg->findString("mime", &mime));
@@ -6374,10 +6389,12 @@
mime.c_str(),
encoder, // createEncoder
0, // flags
- &matchingCodecs);
+ &matchingCodecs,
+ &owners);
}
sp<CodecObserver> observer = new CodecObserver;
+ sp<IOMX> omx;
sp<IOMXNode> omxNode;
status_t err = NAME_NOT_FOUND;
@@ -6385,6 +6402,14 @@
++matchIndex) {
componentName = matchingCodecs[matchIndex];
+ OMXClient client;
+ bool trebleFlag;
+ if (client.connect(owners[matchIndex].c_str(), &trebleFlag) != OK) {
+ mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
+ return false;
+ }
+ omx = client.interface();
+
pid_t tid = gettid();
int prevPriority = androidGetThreadPriority(tid);
androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
@@ -6392,6 +6417,7 @@
androidSetThreadPriority(tid, prevPriority);
if (err == OK) {
+ mCodec->setTrebleFlag(trebleFlag);
break;
} else {
ALOGW("Allocating component '%s' failed, try next one.", componentName.c_str());
@@ -8215,16 +8241,15 @@
}
status_t ACodec::queryCapabilities(
- const AString &name, const AString &mime, bool isEncoder,
- sp<MediaCodecInfo::Capabilities> *caps) {
- (*caps).clear();
- const char *role = GetComponentRole(isEncoder, mime.c_str());
+ const char* owner, const char* name, const char* mime, bool isEncoder,
+ MediaCodecInfo::CapabilitiesWriter* caps) {
+ const char *role = GetComponentRole(isEncoder, mime);
if (role == NULL) {
return BAD_VALUE;
}
OMXClient client;
- status_t err = client.connect();
+ status_t err = client.connect(owner);
if (err != OK) {
return err;
}
@@ -8233,7 +8258,7 @@
sp<CodecObserver> observer = new CodecObserver;
sp<IOMXNode> omxNode;
- err = omx->allocateNode(name.c_str(), observer, &omxNode);
+ err = omx->allocateNode(name, observer, &omxNode);
if (err != OK) {
client.disconnect();
return err;
@@ -8246,8 +8271,7 @@
return err;
}
- sp<MediaCodecInfo::CapabilitiesBuilder> builder = new MediaCodecInfo::CapabilitiesBuilder();
- bool isVideo = mime.startsWithIgnoreCase("video/");
+ bool isVideo = strncasecmp(mime, "video/", 6) == 0;
if (isVideo) {
OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
@@ -8262,11 +8286,22 @@
if (err != OK) {
break;
}
- builder->addProfileLevel(param.eProfile, param.eLevel);
+ caps->addProfileLevel(param.eProfile, param.eLevel);
+
+ // AVC components may not list the constrained profiles explicitly, but
+ // decoders that support a profile also support its constrained version.
+ // Encoders must explicitly support constrained profiles.
+ if (!isEncoder && strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) == 0) {
+ if (param.eProfile == OMX_VIDEO_AVCProfileHigh) {
+ caps->addProfileLevel(OMX_VIDEO_AVCProfileConstrainedHigh, param.eLevel);
+ } else if (param.eProfile == OMX_VIDEO_AVCProfileBaseline) {
+ caps->addProfileLevel(OMX_VIDEO_AVCProfileConstrainedBaseline, param.eLevel);
+ }
+ }
if (index == kMaxIndicesToCheck) {
ALOGW("[%s] stopping checking profiles after %u: %x/%x",
- name.c_str(), index,
+ name, index,
param.eProfile, param.eLevel);
}
}
@@ -8277,7 +8312,6 @@
OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
InitOMXParams(&portFormat);
portFormat.nPortIndex = isEncoder ? kPortIndexInput : kPortIndexOutput;
- Vector<uint32_t> supportedColors; // shadow copy to check for duplicates
for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
portFormat.nIndex = index;
status_t err = omxNode->getParameter(
@@ -8291,28 +8325,17 @@
if (IsFlexibleColorFormat(
omxNode, portFormat.eColorFormat, false /* usingNativeWindow */,
&flexibleEquivalent)) {
- bool marked = false;
- for (size_t i = 0; i < supportedColors.size(); ++i) {
- if (supportedColors[i] == flexibleEquivalent) {
- marked = true;
- break;
- }
- }
- if (!marked) {
- supportedColors.push(flexibleEquivalent);
- builder->addColorFormat(flexibleEquivalent);
- }
+ caps->addColorFormat(flexibleEquivalent);
}
- supportedColors.push(portFormat.eColorFormat);
- builder->addColorFormat(portFormat.eColorFormat);
+ caps->addColorFormat(portFormat.eColorFormat);
if (index == kMaxIndicesToCheck) {
ALOGW("[%s] stopping checking formats after %u: %s(%x)",
- name.c_str(), index,
+ name, index,
asString(portFormat.eColorFormat), portFormat.eColorFormat);
}
}
- } else if (mime.equalsIgnoreCase(MEDIA_MIMETYPE_AUDIO_AAC)) {
+ } else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC) == 0) {
// More audio codecs if they have profiles.
OMX_AUDIO_PARAM_ANDROID_PROFILETYPE param;
InitOMXParams(¶m);
@@ -8326,11 +8349,11 @@
break;
}
// For audio, level is ignored.
- builder->addProfileLevel(param.eProfile, 0 /* level */);
+ caps->addProfileLevel(param.eProfile, 0 /* level */);
if (index == kMaxIndicesToCheck) {
ALOGW("[%s] stopping checking profiles after %u: %x",
- name.c_str(), index,
+ name, index,
param.eProfile);
}
}
@@ -8338,7 +8361,7 @@
// NOTE: Without Android extensions, OMX does not provide a way to query
// AAC profile support
if (param.nProfileIndex == 0) {
- ALOGW("component %s doesn't support profile query.", name.c_str());
+ ALOGW("component %s doesn't support profile query.", name);
}
}
@@ -8347,14 +8370,14 @@
if (omxNode->configureVideoTunnelMode(
kPortIndexOutput, OMX_TRUE, 0, &sidebandHandle) == OK) {
// tunneled playback includes adaptive playback
- builder->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback
+ caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback
| MediaCodecInfo::Capabilities::kFlagSupportsTunneledPlayback);
} else if (omxNode->setPortMode(
kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer) == OK ||
omxNode->prepareForAdaptivePlayback(
kPortIndexOutput, OMX_TRUE,
1280 /* width */, 720 /* height */) == OK) {
- builder->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback);
+ caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback);
}
}
@@ -8366,11 +8389,10 @@
if (omxNode->getConfig(
(OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh,
¶ms, sizeof(params)) == OK) {
- builder->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsIntraRefresh);
+ caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsIntraRefresh);
}
}
- *caps = builder;
omxNode->freeNode();
client.disconnect();
return OK;
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 0d9696f..3c7ae3e 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -20,7 +20,7 @@
#include <numeric>
-#include <android/media/IDescrambler.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <binder/MemoryDealer.h>
#include <media/openmax/OMX_Core.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -34,8 +34,11 @@
#include "include/SharedMemoryBuffer.h"
namespace android {
-using binder::Status;
-using MediaDescrambler::DescrambleInfo;
+using hardware::hidl_handle;
+using hardware::hidl_string;
+using hardware::hidl_vec;
+using namespace hardware::cas::V1_0;
+using namespace hardware::cas::native::V1_0;
using BufferInfo = ACodecBufferChannel::BufferInfo;
using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
@@ -114,74 +117,97 @@
return -ENOENT;
}
- ICrypto::DestinationBuffer destination;
+ native_handle_t *secureHandle = NULL;
if (secure) {
sp<SecureBuffer> secureData =
static_cast<SecureBuffer *>(it->mCodecBuffer.get());
- destination.mType = secureData->getDestinationType();
- if (destination.mType != ICrypto::kDestinationTypeNativeHandle) {
+ if (secureData->getDestinationType() != ICrypto::kDestinationTypeNativeHandle) {
return BAD_VALUE;
}
- destination.mHandle =
- static_cast<native_handle_t *>(secureData->getDestinationPointer());
- } else {
- destination.mType = ICrypto::kDestinationTypeSharedMemory;
- destination.mSharedMemory = mDecryptDestination;
+ secureHandle = static_cast<native_handle_t *>(secureData->getDestinationPointer());
}
-
- ICrypto::SourceBuffer source;
- source.mSharedMemory = it->mSharedEncryptedBuffer;
- source.mHeapSeqNum = mHeapSeqNum;
-
ssize_t result = -1;
if (mCrypto != NULL) {
+ ICrypto::DestinationBuffer destination;
+ if (secure) {
+ destination.mType = ICrypto::kDestinationTypeNativeHandle;
+ destination.mHandle = secureHandle;
+ } else {
+ destination.mType = ICrypto::kDestinationTypeSharedMemory;
+ destination.mSharedMemory = mDecryptDestination;
+ }
+
+ ICrypto::SourceBuffer source;
+ source.mSharedMemory = it->mSharedEncryptedBuffer;
+ source.mHeapSeqNum = mHeapSeqNum;
+
result = mCrypto->decrypt(key, iv, mode, pattern,
source, it->mClientBuffer->offset(),
subSamples, numSubSamples, destination, errorDetailMsg);
- } else {
- DescrambleInfo descrambleInfo;
- descrambleInfo.dstType = destination.mType ==
- ICrypto::kDestinationTypeSharedMemory ?
- DescrambleInfo::kDestinationTypeVmPointer :
- DescrambleInfo::kDestinationTypeNativeHandle;
- descrambleInfo.scramblingControl = key != NULL ?
- (DescramblerPlugin::ScramblingControl)key[0] :
- DescramblerPlugin::kScrambling_Unscrambled;
- descrambleInfo.numSubSamples = numSubSamples;
- descrambleInfo.subSamples = (DescramblerPlugin::SubSample *)subSamples;
- descrambleInfo.srcMem = it->mSharedEncryptedBuffer;
- descrambleInfo.srcOffset = 0;
- descrambleInfo.dstPtr = NULL;
- descrambleInfo.dstOffset = 0;
-
- int32_t descrambleResult = -1;
- Status status = mDescrambler->descramble(descrambleInfo, &descrambleResult);
-
- if (status.isOk()) {
- result = descrambleResult;
- }
if (result < 0) {
- ALOGE("descramble failed, exceptionCode=%d, err=%d, result=%zd",
- status.exceptionCode(), status.transactionError(), result);
- } else {
- ALOGV("descramble succeeded, result=%zd", result);
+ return result;
}
- if (result > 0 && destination.mType == ICrypto::kDestinationTypeSharedMemory) {
- memcpy(destination.mSharedMemory->pointer(),
+ if (destination.mType == ICrypto::kDestinationTypeSharedMemory) {
+ memcpy(it->mCodecBuffer->base(), destination.mSharedMemory->pointer(), result);
+ }
+ } else {
+ // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
+ // directly, the structure definitions should match as checked in DescramblerImpl.cpp.
+ hidl_vec<SubSample> hidlSubSamples;
+ hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/);
+
+ ssize_t offset;
+ size_t size;
+ it->mSharedEncryptedBuffer->getMemory(&offset, &size);
+ hardware::cas::native::V1_0::SharedBuffer srcBuffer = {
+ .heapBase = mHidlMemory,
+ .offset = (uint64_t) offset,
+ .size = size
+ };
+
+ DestinationBuffer dstBuffer;
+ if (secure) {
+ dstBuffer.type = BufferType::NATIVE_HANDLE;
+ dstBuffer.secureMemory = hidl_handle(secureHandle);
+ } else {
+ dstBuffer.type = BufferType::SHARED_MEMORY;
+ dstBuffer.nonsecureMemory = srcBuffer;
+ }
+
+ Status status = Status::OK;
+ hidl_string detailedError;
+
+ auto returnVoid = mDescrambler->descramble(
+ key != NULL ? (ScramblingControl)key[0] : ScramblingControl::UNSCRAMBLED,
+ hidlSubSamples,
+ srcBuffer,
+ 0,
+ dstBuffer,
+ 0,
+ [&status, &result, &detailedError] (
+ Status _status, uint32_t _bytesWritten,
+ const hidl_string& _detailedError) {
+ status = _status;
+ result = (ssize_t)_bytesWritten;
+ detailedError = _detailedError;
+ });
+
+ if (!returnVoid.isOk() || status != Status::OK || result < 0) {
+ ALOGE("descramble failed, trans=%s, status=%d, result=%zd",
+ returnVoid.description().c_str(), status, result);
+ return UNKNOWN_ERROR;
+ }
+
+ ALOGV("descramble succeeded, %zd bytes", result);
+
+ if (dstBuffer.type == BufferType::SHARED_MEMORY) {
+ memcpy(it->mCodecBuffer->base(),
(uint8_t*)it->mSharedEncryptedBuffer->pointer(), result);
}
}
- if (result < 0) {
- return result;
- }
-
- if (destination.mType == ICrypto::kDestinationTypeSharedMemory) {
- memcpy(it->mCodecBuffer->base(), destination.mSharedMemory->pointer(), result);
- }
-
it->mCodecBuffer->setRange(0, result);
// Copy metadata from client to codec buffer.
@@ -275,10 +301,21 @@
int32_t seqNum = mCrypto->setHeap(dealer->getMemoryHeap());
if (seqNum >= 0) {
mHeapSeqNum = seqNum;
- ALOGD("setHeap returned mHeapSeqNum=%d", mHeapSeqNum);
+ ALOGV("setHeap returned mHeapSeqNum=%d", mHeapSeqNum);
} else {
mHeapSeqNum = -1;
- ALOGD("setHeap failed, setting mHeapSeqNum=-1");
+ ALOGE("setHeap failed, setting mHeapSeqNum=-1");
+ }
+ } else if (mDescrambler != nullptr) {
+ sp<IMemoryHeap> heap = dealer->getMemoryHeap();
+ native_handle_t* nativeHandle = native_handle_create(1, 0);
+ if (nativeHandle != nullptr) {
+ int fd = heap->getHeapID();
+ nativeHandle->data[0] = fd;
+ mHidlMemory = hidl_memory("ashmem", hidl_handle(nativeHandle), heap->getSize());
+ ALOGV("created hidl_memory for descrambler");
+ } else {
+ ALOGE("failed to create hidl_memory for descrambler");
}
}
return dealer;
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 6cc1ace..c8d4e4a 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -17,6 +17,7 @@
"AudioPlayer.cpp",
"AudioSource.cpp",
"BufferImpl.cpp",
+ "CodecBase.cpp",
"CallbackDataSource.cpp",
"CameraSource.cpp",
"CameraSourceTimeLapse.cpp",
@@ -29,6 +30,7 @@
"FrameRenderTracker.cpp",
"HTTPBase.cpp",
"HevcUtils.cpp",
+ "ItemTable.cpp",
"JPEGSource.cpp",
"MP3Extractor.cpp",
"MPEG2TSWriter.cpp",
@@ -49,6 +51,7 @@
"NuCachedSource2.cpp",
"NuMediaExtractor.cpp",
"OMXClient.cpp",
+ "OmxInfoBuilder.cpp",
"OggExtractor.cpp",
"SampleIterator.cpp",
"SampleTable.cpp",
@@ -67,11 +70,6 @@
"avc_utils.cpp",
],
- include_dirs: [
- "frameworks/native/include/media/openmax",
- "frameworks/native/include/media/hardware",
- ],
-
shared_libs: [
"libaudioutils",
"libbinder",
@@ -96,16 +94,20 @@
"libnativewindow",
"libmedia_helper",
+ "libstagefright_omx_utils",
"libstagefright_flacdec",
"libstagefright_foundation",
+ "libstagefright_xmlparser",
"libdl",
"libRScpp",
"libhidlbase",
"libhidlmemory",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
+ "android.hidl.token@1.0-utils",
+ "android.hardware.cas@1.0",
+ "android.hardware.cas.native@1.0",
"android.hardware.media.omx@1.0",
- "libstagefright_xmlparser@1.0",
],
static_libs: [
@@ -114,7 +116,6 @@
"libstagefright_aacenc",
"libstagefright_matroska",
"libstagefright_mediafilter",
- "libstagefright_omx_utils",
"libstagefright_webm",
"libstagefright_timedtext",
"libvpx",
@@ -124,9 +125,12 @@
"libFLAC",
],
- export_shared_lib_headers: ["libmedia"],
+ export_shared_lib_headers: [
+ "libmedia",
+ "android.hidl.allocator@1.0",
+ ],
+
export_include_dirs: [
- ".",
"include",
],
@@ -173,4 +177,5 @@
"timedtext",
"webm",
"wifi-display",
+ "xmlparser",
]
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index 4309372..6dfe2de 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -127,10 +127,6 @@
}
ssize_t TinyCacheSource::readAt(off64_t offset, void* data, size_t size) {
- if (size >= kCacheSize) {
- return mSource->readAt(offset, data, size);
- }
-
// Check if the cache satisfies the read.
if (mCachedOffset <= offset
&& offset < (off64_t) (mCachedOffset + mCachedSize)) {
@@ -154,6 +150,9 @@
}
}
+ if (size >= kCacheSize) {
+ return mSource->readAt(offset, data, size);
+ }
// Fill the cache and copy to the caller.
const ssize_t numRead = mSource->readAt(offset, mCache, kCacheSize);
diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp
new file mode 100644
index 0000000..d0610b2
--- /dev/null
+++ b/media/libstagefright/CodecBase.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017, 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 "CodecBase"
+
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <media/ICrypto.h>
+#include <media/stagefright/CodecBase.h>
+#include <utils/Log.h>
+
+namespace android {
+
+void BufferChannelBase::setCrypto(const sp<ICrypto> &crypto) {
+ mCrypto = crypto;
+}
+
+void BufferChannelBase::setDescrambler(const sp<IDescrambler> &descrambler) {
+ mDescrambler = descrambler;
+}
+
+} // namespace android
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index a5760d1..c22053e 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -92,6 +92,48 @@
return true;
}
+bool DataSource::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 DataSource::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 DataSource::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 DataSource::getSize(off64_t *size) {
*size = 0;
diff --git a/media/libstagefright/FrameRenderTracker.cpp b/media/libstagefright/FrameRenderTracker.cpp
index 917870f..1aa3bad 100644
--- a/media/libstagefright/FrameRenderTracker.cpp
+++ b/media/libstagefright/FrameRenderTracker.cpp
@@ -88,7 +88,9 @@
status_t FrameRenderTracker::onFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) {
// ensure monotonic timestamps
- if (mLastRenderTimeNs >= systemNano) {
+ if (mLastRenderTimeNs > systemNano ||
+ // EOS is normally marked on the last frame
+ (mLastRenderTimeNs == systemNano && mediaTimeUs != INT64_MAX)) {
ALOGW("[%s] Ignoring out of order/stale system nano %lld for media time %lld from codec.",
mComponentName.c_str(), (long long)systemNano, (long long)mediaTimeUs);
return BAD_VALUE;
diff --git a/media/libstagefright/ItemTable.cpp b/media/libstagefright/ItemTable.cpp
new file mode 100644
index 0000000..f589f4f
--- /dev/null
+++ b/media/libstagefright/ItemTable.cpp
@@ -0,0 +1,1556 @@
+/*
+ * Copyright (C) 2017 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 "ItemTable"
+
+#include <include/ItemTable.h>
+#include <media/MediaDefs.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <utils/Log.h>
+
+namespace android {
+
+namespace heif {
+
+/////////////////////////////////////////////////////////////////////
+//
+// struct to keep track of one image item
+//
+
+struct ImageItem {
+ friend struct ItemReference;
+ friend struct ItemProperty;
+
+ ImageItem() : ImageItem(0) {}
+ ImageItem(uint32_t _type) : type(_type),
+ rows(0), columns(0), width(0), height(0), rotation(0),
+ offset(0), size(0), nextTileIndex(0) {}
+
+ bool isGrid() const {
+ return type == FOURCC('g', 'r', 'i', 'd');
+ }
+
+ status_t getNextTileItemId(uint32_t *nextTileItemId, bool reset) {
+ if (reset) {
+ nextTileIndex = 0;
+ }
+ if (nextTileIndex >= dimgRefs.size()) {
+ return ERROR_END_OF_STREAM;
+ }
+ *nextTileItemId = dimgRefs[nextTileIndex++];
+ return OK;
+ }
+
+ uint32_t type;
+ int32_t rows;
+ int32_t columns;
+ int32_t width;
+ int32_t height;
+ int32_t rotation;
+ off64_t offset;
+ size_t size;
+ sp<ABuffer> hvcc;
+ sp<ABuffer> icc;
+
+ Vector<uint32_t> thumbnails;
+ Vector<uint32_t> dimgRefs;
+ size_t nextTileIndex;
+};
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// ISO boxes
+//
+
+struct Box {
+protected:
+ Box(const sp<DataSource> source, uint32_t type) :
+ mDataSource(source), mType(type) {}
+
+ virtual ~Box() {}
+
+ virtual status_t onChunkData(
+ uint32_t /*type*/, off64_t /*offset*/, size_t /*size*/) {
+ return OK;
+ }
+
+ inline uint32_t type() const { return mType; }
+
+ inline sp<DataSource> source() const { return mDataSource; }
+
+ status_t parseChunk(off64_t *offset);
+
+ status_t parseChunks(off64_t offset, size_t size);
+
+private:
+ sp<DataSource> mDataSource;
+ uint32_t mType;
+};
+
+status_t Box::parseChunk(off64_t *offset) {
+ if (*offset < 0) {
+ ALOGE("b/23540914");
+ return ERROR_MALFORMED;
+ }
+ uint32_t hdr[2];
+ if (mDataSource->readAt(*offset, hdr, 8) < 8) {
+ return ERROR_IO;
+ }
+ uint64_t chunk_size = ntohl(hdr[0]);
+ int32_t chunk_type = ntohl(hdr[1]);
+ off64_t data_offset = *offset + 8;
+
+ if (chunk_size == 1) {
+ if (mDataSource->readAt(*offset + 8, &chunk_size, 8) < 8) {
+ return ERROR_IO;
+ }
+ chunk_size = ntoh64(chunk_size);
+ data_offset += 8;
+
+ if (chunk_size < 16) {
+ // The smallest valid chunk is 16 bytes long in this case.
+ return ERROR_MALFORMED;
+ }
+ } else if (chunk_size == 0) {
+ // This shouldn't happen since we should never be top level
+ ALOGE("invalid chunk size 0 for non-top level box");
+ return ERROR_MALFORMED;
+ } else if (chunk_size < 8) {
+ // The smallest valid chunk is 8 bytes long.
+ ALOGE("invalid chunk size: %lld", (long long)chunk_size);
+ return ERROR_MALFORMED;
+ }
+
+ char chunk[5];
+ MakeFourCCString(chunk_type, chunk);
+ ALOGV("chunk: %s @ %lld", chunk, (long long)*offset);
+
+ off64_t chunk_data_size = chunk_size - (data_offset - *offset);
+ if (chunk_data_size < 0) {
+ ALOGE("b/23540914");
+ return ERROR_MALFORMED;
+ }
+
+ status_t err = onChunkData(chunk_type, data_offset, chunk_data_size);
+
+ if (err != OK) {
+ return err;
+ }
+ *offset += chunk_size;
+ return OK;
+}
+
+status_t Box::parseChunks(off64_t offset, size_t size) {
+ off64_t stopOffset = offset + size;
+ while (offset < stopOffset) {
+ status_t err = parseChunk(&offset);
+ if (err != OK) {
+ return err;
+ }
+ }
+ if (offset != stopOffset) {
+ return ERROR_MALFORMED;
+ }
+ return OK;
+}
+
+///////////////////////////////////////////////////////////////////////
+
+struct FullBox : public Box {
+protected:
+ FullBox(const sp<DataSource> source, uint32_t type) :
+ Box(source, type), mVersion(0), mFlags(0) {}
+
+ inline uint8_t version() const { return mVersion; }
+
+ inline uint32_t flags() const { return mFlags; }
+
+ status_t parseFullBoxHeader(off64_t *offset, size_t *size);
+
+private:
+ uint8_t mVersion;
+ uint32_t mFlags;
+};
+
+status_t FullBox::parseFullBoxHeader(off64_t *offset, size_t *size) {
+ if (*size < 4) {
+ return ERROR_MALFORMED;
+ }
+ if (!source()->readAt(*offset, &mVersion, 1)) {
+ return ERROR_IO;
+ }
+ if (!source()->getUInt24(*offset + 1, &mFlags)) {
+ return ERROR_IO;
+ }
+ *offset += 4;
+ *size -= 4;
+ return OK;
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// PrimaryImage box
+//
+
+struct PitmBox : public FullBox {
+ PitmBox(const sp<DataSource> source) :
+ FullBox(source, FOURCC('p', 'i', 't', 'm')) {}
+
+ status_t parse(off64_t offset, size_t size, uint32_t *primaryItemId);
+};
+
+status_t PitmBox::parse(off64_t offset, size_t size, uint32_t *primaryItemId) {
+ status_t err = parseFullBoxHeader(&offset, &size);
+ if (err != OK) {
+ return err;
+ }
+
+ size_t itemIdSize = (version() == 0) ? 2 : 4;
+ if (size < itemIdSize) {
+ return ERROR_MALFORMED;
+ }
+ uint32_t itemId;
+ if (!source()->getUInt32Var(offset, &itemId, itemIdSize)) {
+ return ERROR_IO;
+ }
+
+ ALOGV("primary id %d", itemId);
+ *primaryItemId = itemId;
+
+ return OK;
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// ItemLocation related boxes
+//
+
+struct ExtentEntry {
+ uint64_t extentIndex;
+ uint64_t extentOffset;
+ uint64_t extentLength;
+};
+
+struct ItemLoc {
+ ItemLoc() : ItemLoc(0, 0, 0, 0) {}
+ ItemLoc(uint32_t item_id, uint16_t construction_method,
+ uint16_t data_reference_index, uint64_t base_offset) :
+ itemId(item_id),
+ constructionMethod(construction_method),
+ dataReferenceIndex(data_reference_index),
+ baseOffset(base_offset) {}
+
+ void addExtent(const ExtentEntry& extent) {
+ extents.push_back(extent);
+ }
+
+ status_t getLoc(off64_t *offset, size_t *size,
+ off64_t idatOffset, size_t idatSize) const {
+ // TODO: fix extent handling, fix constructionMethod = 2
+ CHECK(extents.size() == 1);
+ if (constructionMethod == 0) {
+ *offset = baseOffset + extents[0].extentOffset;
+ *size = extents[0].extentLength;
+ return OK;
+ } else if (constructionMethod == 1) {
+ if (baseOffset + extents[0].extentOffset + extents[0].extentLength
+ > idatSize) {
+ return ERROR_MALFORMED;
+ }
+ *offset = baseOffset + extents[0].extentOffset + idatOffset;
+ *size = extents[0].extentLength;
+ return OK;
+ }
+ return ERROR_UNSUPPORTED;
+ }
+
+ // parsed info
+ uint32_t itemId;
+ uint16_t constructionMethod;
+ uint16_t dataReferenceIndex;
+ off64_t baseOffset;
+ Vector<ExtentEntry> extents;
+};
+
+struct IlocBox : public FullBox {
+ IlocBox(const sp<DataSource> source, KeyedVector<uint32_t, ItemLoc> *itemLocs) :
+ FullBox(source, FOURCC('i', 'l', 'o', 'c')),
+ mItemLocs(itemLocs), mHasConstructMethod1(false) {}
+
+ status_t parse(off64_t offset, size_t size);
+
+ bool hasConstructMethod1() { return mHasConstructMethod1; }
+
+private:
+ static bool isSizeFieldValid(uint32_t offset_size) {
+ return offset_size == 0 || offset_size == 4 || offset_size == 8;
+ }
+ KeyedVector<uint32_t, ItemLoc> *mItemLocs;
+ bool mHasConstructMethod1;
+};
+
+status_t IlocBox::parse(off64_t offset, size_t size) {
+ status_t err = parseFullBoxHeader(&offset, &size);
+ if (err != OK) {
+ return err;
+ }
+ if (version() > 2) {
+ ALOGE("%s: invalid version %d", __FUNCTION__, version());
+ return ERROR_MALFORMED;
+ }
+
+ if (size < 2) {
+ return ERROR_MALFORMED;
+ }
+ uint8_t offset_size;
+ if (!source()->readAt(offset++, &offset_size, 1)) {
+ return ERROR_IO;
+ }
+ uint8_t length_size = (offset_size & 0xF);
+ offset_size >>= 4;
+
+ uint8_t base_offset_size;
+ if (!source()->readAt(offset++, &base_offset_size, 1)) {
+ return ERROR_IO;
+ }
+ uint8_t index_size = 0;
+ if (version() == 1 || version() == 2) {
+ index_size = (base_offset_size & 0xF);
+ }
+ base_offset_size >>= 4;
+ size -= 2;
+
+ if (!isSizeFieldValid(offset_size)
+ || !isSizeFieldValid(length_size)
+ || !isSizeFieldValid(base_offset_size)
+ || !isSizeFieldValid((index_size))) {
+ ALOGE("%s: offset size not valid: %d, %d, %d, %d", __FUNCTION__,
+ offset_size, length_size, base_offset_size, index_size);
+ return ERROR_MALFORMED;
+ }
+
+ uint32_t item_count;
+ size_t itemFieldSize = version() < 2 ? 2 : 4;
+ if (size < itemFieldSize) {
+ return ERROR_MALFORMED;
+ }
+ if (!source()->getUInt32Var(offset, &item_count, itemFieldSize)) {
+ return ERROR_IO;
+ }
+
+ ALOGV("item_count %lld", (long long) item_count);
+ offset += itemFieldSize;
+ size -= itemFieldSize;
+
+ for (size_t i = 0; i < item_count; i++) {
+ uint32_t item_id;
+ if (!source()->getUInt32Var(offset, &item_id, itemFieldSize)) {
+ return ERROR_IO;
+ }
+ ALOGV("item[%zu]: id %lld", i, (long long)item_id);
+ offset += itemFieldSize;
+
+ uint8_t construction_method = 0;
+ if (version() == 1 || version() == 2) {
+ uint8_t buf[2];
+ if (!source()->readAt(offset, buf, 2)) {
+ return ERROR_IO;
+ }
+ construction_method = (buf[1] & 0xF);
+ ALOGV("construction_method %d", construction_method);
+ if (construction_method == 1) {
+ mHasConstructMethod1 = true;
+ }
+
+ offset += 2;
+ }
+
+ uint16_t data_reference_index;
+ if (!source()->getUInt16(offset, &data_reference_index)) {
+ return ERROR_IO;
+ }
+ ALOGV("data_reference_index %d", data_reference_index);
+ if (data_reference_index != 0) {
+ // we don't support reference to other files
+ return ERROR_UNSUPPORTED;
+ }
+ offset += 2;
+
+ uint64_t base_offset = 0;
+ if (base_offset_size != 0) {
+ if (!source()->getUInt64Var(offset, &base_offset, base_offset_size)) {
+ return ERROR_IO;
+ }
+ offset += base_offset_size;
+ }
+ ALOGV("base_offset %lld", (long long) base_offset);
+
+ ssize_t index = mItemLocs->add(item_id, ItemLoc(
+ item_id, construction_method, data_reference_index, base_offset));
+ ItemLoc &item = mItemLocs->editValueAt(index);
+
+ uint16_t extent_count;
+ if (!source()->getUInt16(offset, &extent_count)) {
+ return ERROR_IO;
+ }
+ ALOGV("extent_count %d", extent_count);
+
+ if (extent_count > 1 && (offset_size == 0 || length_size == 0)) {
+ // if the item is dividec into more than one extents, offset and
+ // length must be present.
+ return ERROR_MALFORMED;
+ }
+ offset += 2;
+
+ for (size_t j = 0; j < extent_count; j++) {
+ uint64_t extent_index = 1; // default=1
+ if ((version() == 1 || version() == 2) && (index_size > 0)) {
+ if (!source()->getUInt64Var(offset, &extent_index, index_size)) {
+ return ERROR_IO;
+ }
+ // TODO: add support for this mode
+ offset += index_size;
+ ALOGV("extent_index %lld", (long long)extent_index);
+ }
+
+ uint64_t extent_offset = 0; // default=0
+ if (offset_size > 0) {
+ if (!source()->getUInt64Var(offset, &extent_offset, offset_size)) {
+ return ERROR_IO;
+ }
+ offset += offset_size;
+ }
+ ALOGV("extent_offset %lld", (long long)extent_offset);
+
+ uint64_t extent_length = 0; // this indicates full length of file
+ if (length_size > 0) {
+ if (!source()->getUInt64Var(offset, &extent_length, length_size)) {
+ return ERROR_IO;
+ }
+ offset += length_size;
+ }
+ ALOGV("extent_length %lld", (long long)extent_length);
+
+ item.addExtent({ extent_index, extent_offset, extent_length });
+ }
+ }
+ return OK;
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// ItemReference related boxes
+//
+
+struct ItemReference : public Box, public RefBase {
+ ItemReference(const sp<DataSource> source, uint32_t type, uint32_t itemIdSize) :
+ Box(source, type), mItemId(0), mRefIdSize(itemIdSize) {}
+
+ status_t parse(off64_t offset, size_t size);
+
+ uint32_t itemId() { return mItemId; }
+
+ void apply(KeyedVector<uint32_t, ImageItem> &itemIdToImageMap) const {
+ ssize_t imageIndex = itemIdToImageMap.indexOfKey(mItemId);
+
+ // ignore non-image items
+ if (imageIndex < 0) {
+ return;
+ }
+
+ ALOGV("attach reference type 0x%x to item id %d)", type(), mItemId);
+
+ if (type() == FOURCC('d', 'i', 'm', 'g')) {
+ ImageItem &image = itemIdToImageMap.editValueAt(imageIndex);
+ if (!image.dimgRefs.empty()) {
+ ALOGW("dimgRefs if not clean!");
+ }
+ image.dimgRefs.appendVector(mRefs);
+ } else if (type() == FOURCC('t', 'h', 'm', 'b')) {
+ for (size_t i = 0; i < mRefs.size(); i++) {
+ imageIndex = itemIdToImageMap.indexOfKey(mRefs[i]);
+
+ // ignore non-image items
+ if (imageIndex < 0) {
+ continue;
+ }
+ ALOGV("Image item id %d uses thumbnail item id %d", mRefs[i], mItemId);
+ ImageItem &image = itemIdToImageMap.editValueAt(imageIndex);
+ if (!image.thumbnails.empty()) {
+ ALOGW("already has thumbnails!");
+ }
+ image.thumbnails.push_back(mItemId);
+ }
+ } else {
+ ALOGW("ignoring unsupported ref type 0x%x", type());
+ }
+ }
+
+private:
+ uint32_t mItemId;
+ uint32_t mRefIdSize;
+ Vector<uint32_t> mRefs;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ItemReference);
+};
+
+status_t ItemReference::parse(off64_t offset, size_t size) {
+ if (size < mRefIdSize + 2) {
+ return ERROR_MALFORMED;
+ }
+ if (!source()->getUInt32Var(offset, &mItemId, mRefIdSize)) {
+ return ERROR_IO;
+ }
+ offset += mRefIdSize;
+
+ uint16_t count;
+ if (!source()->getUInt16(offset, &count)) {
+ return ERROR_IO;
+ }
+ offset += 2;
+ size -= (mRefIdSize + 2);
+
+ if (size < count * mRefIdSize) {
+ return ERROR_MALFORMED;
+ }
+
+ for (size_t i = 0; i < count; i++) {
+ uint32_t refItemId;
+ if (!source()->getUInt32Var(offset, &refItemId, mRefIdSize)) {
+ return ERROR_IO;
+ }
+ offset += mRefIdSize;
+ mRefs.push_back(refItemId);
+ ALOGV("item id %d: referencing item id %d", mItemId, refItemId);
+ }
+
+ return OK;
+}
+
+struct IrefBox : public FullBox {
+ IrefBox(const sp<DataSource> source, Vector<sp<ItemReference> > *itemRefs) :
+ FullBox(source, FOURCC('i', 'r', 'e', 'f')), mRefIdSize(0), mItemRefs(itemRefs) {}
+
+ status_t parse(off64_t offset, size_t size);
+
+protected:
+ status_t onChunkData(uint32_t type, off64_t offset, size_t size) override;
+
+private:
+ uint32_t mRefIdSize;
+ Vector<sp<ItemReference> > *mItemRefs;
+};
+
+status_t IrefBox::parse(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+ status_t err = parseFullBoxHeader(&offset, &size);
+ if (err != OK) {
+ return err;
+ }
+
+ mRefIdSize = (version() == 0) ? 2 : 4;
+ return parseChunks(offset, size);
+}
+
+status_t IrefBox::onChunkData(uint32_t type, off64_t offset, size_t size) {
+ sp<ItemReference> itemRef = new ItemReference(source(), type, mRefIdSize);
+
+ status_t err = itemRef->parse(offset, size);
+ if (err != OK) {
+ return err;
+ }
+ mItemRefs->push_back(itemRef);
+ return OK;
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// ItemProperty related boxes
+//
+
+struct AssociationEntry {
+ uint32_t itemId;
+ bool essential;
+ uint16_t index;
+};
+
+struct ItemProperty : public RefBase {
+ ItemProperty() {}
+
+ virtual void attachTo(ImageItem &/*image*/) const {
+ ALOGW("Unrecognized property");
+ }
+ virtual status_t parse(off64_t /*offset*/, size_t /*size*/) {
+ ALOGW("Unrecognized property");
+ return OK;
+ }
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(ItemProperty);
+};
+
+struct IspeBox : public FullBox, public ItemProperty {
+ IspeBox(const sp<DataSource> source) :
+ FullBox(source, FOURCC('i', 's', 'p', 'e')), mWidth(0), mHeight(0) {}
+
+ status_t parse(off64_t offset, size_t size) override;
+
+ void attachTo(ImageItem &image) const override {
+ image.width = mWidth;
+ image.height = mHeight;
+ }
+
+private:
+ uint32_t mWidth;
+ uint32_t mHeight;
+};
+
+status_t IspeBox::parse(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+
+ status_t err = parseFullBoxHeader(&offset, &size);
+ if (err != OK) {
+ return err;
+ }
+
+ if (size < 8) {
+ return ERROR_MALFORMED;
+ }
+ if (!source()->getUInt32(offset, &mWidth)
+ || !source()->getUInt32(offset + 4, &mHeight)) {
+ return ERROR_IO;
+ }
+ ALOGV("property ispe: %dx%d", mWidth, mHeight);
+
+ return OK;
+}
+
+struct HvccBox : public Box, public ItemProperty {
+ HvccBox(const sp<DataSource> source) :
+ Box(source, FOURCC('h', 'v', 'c', 'C')) {}
+
+ status_t parse(off64_t offset, size_t size) override;
+
+ void attachTo(ImageItem &image) const override {
+ image.hvcc = mHVCC;
+ }
+
+private:
+ sp<ABuffer> mHVCC;
+};
+
+status_t HvccBox::parse(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+
+ mHVCC = new ABuffer(size);
+
+ if (mHVCC->data() == NULL) {
+ ALOGE("b/28471206");
+ return NO_MEMORY;
+ }
+
+ if (source()->readAt(offset, mHVCC->data(), size) < (ssize_t)size) {
+ return ERROR_IO;
+ }
+
+ ALOGV("property hvcC");
+
+ return OK;
+}
+
+struct IrotBox : public Box, public ItemProperty {
+ IrotBox(const sp<DataSource> source) :
+ Box(source, FOURCC('i', 'r', 'o', 't')), mAngle(0) {}
+
+ status_t parse(off64_t offset, size_t size) override;
+
+ void attachTo(ImageItem &image) const override {
+ image.rotation = mAngle * 90;
+ }
+
+private:
+ uint8_t mAngle;
+};
+
+status_t IrotBox::parse(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+
+ if (size < 1) {
+ return ERROR_MALFORMED;
+ }
+ if (source()->readAt(offset, &mAngle, 1) != 1) {
+ return ERROR_IO;
+ }
+ mAngle &= 0x3;
+ ALOGV("property irot: %d", mAngle);
+
+ return OK;
+}
+
+struct ColrBox : public Box, public ItemProperty {
+ ColrBox(const sp<DataSource> source) :
+ Box(source, FOURCC('c', 'o', 'l', 'r')) {}
+
+ status_t parse(off64_t offset, size_t size) override;
+
+ void attachTo(ImageItem &image) const override {
+ image.icc = mICCData;
+ }
+
+private:
+ sp<ABuffer> mICCData;
+};
+
+status_t ColrBox::parse(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+
+ if (size < 4) {
+ return ERROR_MALFORMED;
+ }
+ uint32_t colour_type;
+ if (!source()->getUInt32(offset, &colour_type)) {
+ return ERROR_IO;
+ }
+ offset += 4;
+ size -= 4;
+ if (colour_type == FOURCC('n', 'c', 'l', 'x')) {
+ return OK;
+ }
+ if ((colour_type != FOURCC('r', 'I', 'C', 'C')) &&
+ (colour_type != FOURCC('p', 'r', 'o', 'f'))) {
+ return ERROR_MALFORMED;
+ }
+
+ mICCData = new ABuffer(size);
+ if (mICCData->data() == NULL) {
+ ALOGE("b/28471206");
+ return NO_MEMORY;
+ }
+
+ if (source()->readAt(offset, mICCData->data(), size) != (ssize_t)size) {
+ return ERROR_IO;
+ }
+
+ ALOGV("property Colr: size %zd", size);
+ return OK;
+}
+
+struct IpmaBox : public FullBox {
+ IpmaBox(const sp<DataSource> source, Vector<AssociationEntry> *associations) :
+ FullBox(source, FOURCC('i', 'p', 'm', 'a')), mAssociations(associations) {}
+
+ status_t parse(off64_t offset, size_t size);
+private:
+ Vector<AssociationEntry> *mAssociations;
+};
+
+status_t IpmaBox::parse(off64_t offset, size_t size) {
+ status_t err = parseFullBoxHeader(&offset, &size);
+ if (err != OK) {
+ return err;
+ }
+
+ if (size < 4) {
+ return ERROR_MALFORMED;
+ }
+ uint32_t entryCount;
+ if (!source()->getUInt32(offset, &entryCount)) {
+ return ERROR_IO;
+ }
+ offset += 4;
+ size -= 4;
+
+ for (size_t k = 0; k < entryCount; ++k) {
+ uint32_t itemId = 0;
+ size_t itemIdSize = (version() < 1) ? 2 : 4;
+
+ if (size < itemIdSize + 1) {
+ return ERROR_MALFORMED;
+ }
+
+ if (!source()->getUInt32Var(offset, &itemId, itemIdSize)) {
+ return ERROR_IO;
+ }
+ offset += itemIdSize;
+ size -= itemIdSize;
+
+ uint8_t associationCount;
+ if (!source()->readAt(offset, &associationCount, 1)) {
+ return ERROR_IO;
+ }
+ offset++;
+ size--;
+
+ for (size_t i = 0; i < associationCount; ++i) {
+ size_t propIndexSize = (flags() & 1) ? 2 : 1;
+ if (size < propIndexSize) {
+ return ERROR_MALFORMED;
+ }
+ uint16_t propIndex;
+ if (!source()->getUInt16Var(offset, &propIndex, propIndexSize)) {
+ return ERROR_IO;
+ }
+ offset += propIndexSize;
+ size -= propIndexSize;
+ uint16_t bitmask = (1 << (8 * propIndexSize - 1));
+ AssociationEntry entry = {
+ .itemId = itemId,
+ .essential = !!(propIndex & bitmask),
+ .index = (uint16_t) (propIndex & ~bitmask)
+ };
+
+ ALOGV("item id %d associated to property %d (essential %d)",
+ itemId, entry.index, entry.essential);
+
+ mAssociations->push_back(entry);
+ }
+ }
+
+ return OK;
+}
+
+struct IpcoBox : public Box {
+ IpcoBox(const sp<DataSource> source, Vector<sp<ItemProperty> > *properties) :
+ Box(source, FOURCC('i', 'p', 'c', 'o')), mItemProperties(properties) {}
+
+ status_t parse(off64_t offset, size_t size);
+protected:
+ status_t onChunkData(uint32_t type, off64_t offset, size_t size) override;
+
+private:
+ Vector<sp<ItemProperty> > *mItemProperties;
+};
+
+status_t IpcoBox::parse(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+ // push dummy as the index is 1-based
+ mItemProperties->push_back(new ItemProperty());
+ return parseChunks(offset, size);
+}
+
+status_t IpcoBox::onChunkData(uint32_t type, off64_t offset, size_t size) {
+ sp<ItemProperty> itemProperty;
+ switch(type) {
+ case FOURCC('h', 'v', 'c', 'C'):
+ {
+ itemProperty = new HvccBox(source());
+ break;
+ }
+ case FOURCC('i', 's', 'p', 'e'):
+ {
+ itemProperty = new IspeBox(source());
+ break;
+ }
+ case FOURCC('i', 'r', 'o', 't'):
+ {
+ itemProperty = new IrotBox(source());
+ break;
+ }
+ case FOURCC('c', 'o', 'l', 'r'):
+ {
+ itemProperty = new ColrBox(source());
+ break;
+ }
+ default:
+ {
+ // push dummy to maintain correct item property index
+ itemProperty = new ItemProperty();
+ break;
+ }
+ }
+ status_t err = itemProperty->parse(offset, size);
+ if (err != OK) {
+ return err;
+ }
+ mItemProperties->push_back(itemProperty);
+ return OK;
+}
+
+struct IprpBox : public Box {
+ IprpBox(const sp<DataSource> source,
+ Vector<sp<ItemProperty> > *properties,
+ Vector<AssociationEntry> *associations) :
+ Box(source, FOURCC('i', 'p', 'r', 'p')),
+ mProperties(properties), mAssociations(associations) {}
+
+ status_t parse(off64_t offset, size_t size);
+protected:
+ status_t onChunkData(uint32_t type, off64_t offset, size_t size) override;
+
+private:
+ Vector<sp<ItemProperty> > *mProperties;
+ Vector<AssociationEntry> *mAssociations;
+};
+
+status_t IprpBox::parse(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+
+ status_t err = parseChunks(offset, size);
+ if (err != OK) {
+ return err;
+ }
+ return OK;
+}
+
+status_t IprpBox::onChunkData(uint32_t type, off64_t offset, size_t size) {
+ switch(type) {
+ case FOURCC('i', 'p', 'c', 'o'):
+ {
+ IpcoBox ipcoBox(source(), mProperties);
+ return ipcoBox.parse(offset, size);
+ }
+ case FOURCC('i', 'p', 'm', 'a'):
+ {
+ IpmaBox ipmaBox(source(), mAssociations);
+ return ipmaBox.parse(offset, size);
+ }
+ default:
+ {
+ ALOGW("Unrecognized box.");
+ break;
+ }
+ }
+ return OK;
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// ItemInfo related boxes
+//
+struct ItemInfo {
+ uint32_t itemId;
+ uint32_t itemType;
+};
+
+struct InfeBox : public FullBox {
+ InfeBox(const sp<DataSource> source) :
+ FullBox(source, FOURCC('i', 'n', 'f', 'e')) {}
+
+ status_t parse(off64_t offset, size_t size, ItemInfo *itemInfo);
+
+private:
+ bool parseNullTerminatedString(off64_t *offset, size_t *size, String8 *out);
+};
+
+bool InfeBox::parseNullTerminatedString(
+ off64_t *offset, size_t *size, String8 *out) {
+ char tmp[256];
+ size_t len = 0;
+ off64_t newOffset = *offset;
+ off64_t stopOffset = *offset + *size;
+ while (newOffset < stopOffset) {
+ if (!source()->readAt(newOffset++, &tmp[len], 1)) {
+ return false;
+ }
+ if (tmp[len] == 0) {
+ out->append(tmp, len);
+
+ *offset = newOffset;
+ *size = stopOffset - newOffset;
+
+ return true;
+ }
+ if (++len >= sizeof(tmp)) {
+ out->append(tmp, len);
+ len = 0;
+ }
+ }
+ return false;
+}
+
+status_t InfeBox::parse(off64_t offset, size_t size, ItemInfo *itemInfo) {
+ status_t err = parseFullBoxHeader(&offset, &size);
+ if (err != OK) {
+ return err;
+ }
+
+ if (version() == 0 || version() == 1) {
+ if (size < 4) {
+ return ERROR_MALFORMED;
+ }
+ uint16_t item_id;
+ if (!source()->getUInt16(offset, &item_id)) {
+ return ERROR_IO;
+ }
+ ALOGV("item_id %d", item_id);
+ uint16_t item_protection_index;
+ if (!source()->getUInt16(offset + 2, &item_protection_index)) {
+ return ERROR_IO;
+ }
+ offset += 4;
+ size -= 4;
+
+ String8 item_name;
+ if (!parseNullTerminatedString(&offset, &size, &item_name)) {
+ return ERROR_MALFORMED;
+ }
+
+ String8 content_type;
+ if (!parseNullTerminatedString(&offset, &size, &content_type)) {
+ return ERROR_MALFORMED;
+ }
+
+ String8 content_encoding;
+ if (!parseNullTerminatedString(&offset, &size, &content_encoding)) {
+ return ERROR_MALFORMED;
+ }
+
+ if (version() == 1) {
+ uint32_t extension_type;
+ if (!source()->getUInt32(offset, &extension_type)) {
+ return ERROR_IO;
+ }
+ offset++;
+ size--;
+ // TODO: handle this case
+ }
+ } else { // version >= 2
+ uint32_t item_id;
+ size_t itemIdSize = (version() == 2) ? 2 : 4;
+ if (size < itemIdSize + 6) {
+ return ERROR_MALFORMED;
+ }
+ if (!source()->getUInt32Var(offset, &item_id, itemIdSize)) {
+ return ERROR_IO;
+ }
+ ALOGV("item_id %d", item_id);
+ offset += itemIdSize;
+ uint16_t item_protection_index;
+ if (!source()->getUInt16(offset, &item_protection_index)) {
+ return ERROR_IO;
+ }
+ ALOGV("item_protection_index %d", item_protection_index);
+ offset += 2;
+ uint32_t item_type;
+ if (!source()->getUInt32(offset, &item_type)) {
+ return ERROR_IO;
+ }
+
+ itemInfo->itemId = item_id;
+ itemInfo->itemType = item_type;
+
+ char itemTypeString[5];
+ MakeFourCCString(item_type, itemTypeString);
+ ALOGV("item_type %s", itemTypeString);
+ offset += 4;
+ size -= itemIdSize + 6;
+
+ String8 item_name;
+ if (!parseNullTerminatedString(&offset, &size, &item_name)) {
+ return ERROR_MALFORMED;
+ }
+ ALOGV("item_name %s", item_name.c_str());
+
+ if (item_type == FOURCC('m', 'i', 'm', 'e')) {
+ String8 content_type;
+ if (!parseNullTerminatedString(&offset, &size, &content_type)) {
+ return ERROR_MALFORMED;
+ }
+
+ String8 content_encoding;
+ if (!parseNullTerminatedString(&offset, &size, &content_encoding)) {
+ return ERROR_MALFORMED;
+ }
+ } else if (item_type == FOURCC('u', 'r', 'i', ' ')) {
+ String8 item_uri_type;
+ if (!parseNullTerminatedString(&offset, &size, &item_uri_type)) {
+ return ERROR_MALFORMED;
+ }
+ }
+ }
+ return OK;
+}
+
+struct IinfBox : public FullBox {
+ IinfBox(const sp<DataSource> source, Vector<ItemInfo> *itemInfos) :
+ FullBox(source, FOURCC('i', 'i', 'n', 'f')),
+ mItemInfos(itemInfos), mHasGrids(false) {}
+
+ status_t parse(off64_t offset, size_t size);
+
+ bool hasGrids() { return mHasGrids; }
+
+protected:
+ status_t onChunkData(uint32_t type, off64_t offset, size_t size) override;
+
+private:
+ Vector<ItemInfo> *mItemInfos;
+ bool mHasGrids;
+};
+
+status_t IinfBox::parse(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+
+ status_t err = parseFullBoxHeader(&offset, &size);
+ if (err != OK) {
+ return err;
+ }
+
+ size_t entryCountSize = version() == 0 ? 2 : 4;
+ if (size < entryCountSize) {
+ return ERROR_MALFORMED;
+ }
+ uint32_t entry_count;
+ if (!source()->getUInt32Var(offset, &entry_count, entryCountSize)) {
+ return ERROR_IO;
+ }
+ ALOGV("entry_count %d", entry_count);
+
+ off64_t stopOffset = offset + size;
+ offset += entryCountSize;
+ for (size_t i = 0; i < entry_count && offset < stopOffset; i++) {
+ ALOGV("entry %zu", i);
+ status_t err = parseChunk(&offset);
+ if (err != OK) {
+ return err;
+ }
+ }
+ if (offset != stopOffset) {
+ return ERROR_MALFORMED;
+ }
+
+ return OK;
+}
+
+status_t IinfBox::onChunkData(uint32_t type, off64_t offset, size_t size) {
+ if (type != FOURCC('i', 'n', 'f', 'e')) {
+ return OK;
+ }
+
+ InfeBox infeBox(source());
+ ItemInfo itemInfo;
+ status_t err = infeBox.parse(offset, size, &itemInfo);
+ if (err != OK) {
+ return err;
+ }
+ mItemInfos->push_back(itemInfo);
+ mHasGrids |= (itemInfo.itemType == FOURCC('g', 'r', 'i', 'd'));
+ return OK;
+}
+
+//////////////////////////////////////////////////////////////////
+
+ItemTable::ItemTable(const sp<DataSource> &source)
+ : mDataSource(source),
+ mPrimaryItemId(0),
+ mIdatOffset(0),
+ mIdatSize(0),
+ mImageItemsValid(false),
+ mCurrentImageIndex(0) {
+ mRequiredBoxes.insert('iprp');
+ mRequiredBoxes.insert('iloc');
+ mRequiredBoxes.insert('pitm');
+ mRequiredBoxes.insert('iinf');
+}
+
+ItemTable::~ItemTable() {}
+
+status_t ItemTable::parse(uint32_t type, off64_t data_offset, size_t chunk_data_size) {
+ switch(type) {
+ case FOURCC('i', 'l', 'o', 'c'):
+ {
+ return parseIlocBox(data_offset, chunk_data_size);
+ }
+ case FOURCC('i', 'i', 'n', 'f'):
+ {
+ return parseIinfBox(data_offset, chunk_data_size);
+ }
+ case FOURCC('i', 'p', 'r', 'p'):
+ {
+ return parseIprpBox(data_offset, chunk_data_size);
+ }
+ case FOURCC('p', 'i', 't', 'm'):
+ {
+ return parsePitmBox(data_offset, chunk_data_size);
+ }
+ case FOURCC('i', 'd', 'a', 't'):
+ {
+ return parseIdatBox(data_offset, chunk_data_size);
+ }
+ case FOURCC('i', 'r', 'e', 'f'):
+ {
+ return parseIrefBox(data_offset, chunk_data_size);
+ }
+ case FOURCC('i', 'p', 'r', 'o'):
+ {
+ ALOGW("ipro box not supported!");
+ break;
+ }
+ default:
+ {
+ ALOGW("unrecognized box type: 0x%x", type);
+ break;
+ }
+ }
+ return ERROR_UNSUPPORTED;
+}
+
+status_t ItemTable::parseIlocBox(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+
+ IlocBox ilocBox(mDataSource, &mItemLocs);
+ status_t err = ilocBox.parse(offset, size);
+ if (err != OK) {
+ return err;
+ }
+
+ if (ilocBox.hasConstructMethod1()) {
+ mRequiredBoxes.insert('idat');
+ }
+
+ return buildImageItemsIfPossible('iloc');
+}
+
+status_t ItemTable::parseIinfBox(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+
+ IinfBox iinfBox(mDataSource, &mItemInfos);
+ status_t err = iinfBox.parse(offset, size);
+ if (err != OK) {
+ return err;
+ }
+
+ if (iinfBox.hasGrids()) {
+ mRequiredBoxes.insert('iref');
+ }
+
+ return buildImageItemsIfPossible('iinf');
+}
+
+status_t ItemTable::parsePitmBox(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+
+ PitmBox pitmBox(mDataSource);
+ status_t err = pitmBox.parse(offset, size, &mPrimaryItemId);
+ if (err != OK) {
+ return err;
+ }
+
+ return buildImageItemsIfPossible('pitm');
+}
+
+status_t ItemTable::parseIprpBox(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+
+ IprpBox iprpBox(mDataSource, &mItemProperties, &mAssociations);
+ status_t err = iprpBox.parse(offset, size);
+ if (err != OK) {
+ return err;
+ }
+
+ return buildImageItemsIfPossible('iprp');
+}
+
+status_t ItemTable::parseIdatBox(off64_t offset, size_t size) {
+ ALOGV("%s: idat offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+
+ // only remember the offset and size of idat box for later use
+ mIdatOffset = offset;
+ mIdatSize = size;
+
+ return buildImageItemsIfPossible('idat');
+}
+
+status_t ItemTable::parseIrefBox(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+
+ IrefBox irefBox(mDataSource, &mItemReferences);
+ status_t err = irefBox.parse(offset, size);
+ if (err != OK) {
+ return err;
+ }
+
+ return buildImageItemsIfPossible('iref');
+}
+
+status_t ItemTable::buildImageItemsIfPossible(uint32_t type) {
+ if (mImageItemsValid) {
+ return OK;
+ }
+
+ mBoxesSeen.insert(type);
+
+ // need at least 'iprp', 'iloc', 'pitm', 'iinf';
+ // need 'idat' if any items used construction_method of 2;
+ // need 'iref' if there are grids.
+ if (!std::includes(
+ mBoxesSeen.begin(), mBoxesSeen.end(),
+ mRequiredBoxes.begin(), mRequiredBoxes.end())) {
+ return OK;
+ }
+
+ ALOGV("building image table...");
+
+ for (size_t i = 0; i < mItemInfos.size(); i++) {
+ const ItemInfo &info = mItemInfos[i];
+
+
+ // ignore non-image items
+ if (info.itemType != FOURCC('g', 'r', 'i', 'd') &&
+ info.itemType != FOURCC('h', 'v', 'c', '1')) {
+ continue;
+ }
+
+ ssize_t imageIndex = mItemIdToImageMap.indexOfKey(info.itemId);
+ if (imageIndex >= 0) {
+ ALOGW("ignoring duplicate image item id %d", info.itemId);
+ continue;
+ }
+
+ ssize_t ilocIndex = mItemLocs.indexOfKey(info.itemId);
+ if (ilocIndex < 0) {
+ ALOGE("iloc missing for image item id %d", info.itemId);
+ continue;
+ }
+ const ItemLoc &iloc = mItemLocs[ilocIndex];
+
+ off64_t offset;
+ size_t size;
+ if (iloc.getLoc(&offset, &size, mIdatOffset, mIdatSize) != OK) {
+ return ERROR_MALFORMED;
+ }
+
+ ImageItem image(info.itemType);
+
+ ALOGV("adding %s: itemId %d", image.isGrid() ? "grid" : "image", info.itemId);
+
+ if (image.isGrid()) {
+ // ImageGrid struct is at least 8-byte, at most 12-byte (if flags&1)
+ if (size < 8 || size > 12) {
+ return ERROR_MALFORMED;
+ }
+ uint8_t buf[12];
+ if (!mDataSource->readAt(offset, buf, size)) {
+ return ERROR_IO;
+ }
+
+ image.rows = buf[2] + 1;
+ image.columns = buf[3] + 1;
+
+ ALOGV("rows %d, columans %d", image.rows, image.columns);
+ } else {
+ image.offset = offset;
+ image.size = size;
+ }
+ mItemIdToImageMap.add(info.itemId, image);
+ }
+
+ for (size_t i = 0; i < mAssociations.size(); i++) {
+ attachProperty(mAssociations[i]);
+ }
+
+ for (size_t i = 0; i < mItemReferences.size(); i++) {
+ mItemReferences[i]->apply(mItemIdToImageMap);
+ }
+
+ mImageItemsValid = true;
+ return OK;
+}
+
+void ItemTable::attachProperty(const AssociationEntry &association) {
+ ssize_t imageIndex = mItemIdToImageMap.indexOfKey(association.itemId);
+
+ // ignore non-image items
+ if (imageIndex < 0) {
+ return;
+ }
+
+ uint16_t propertyIndex = association.index;
+ if (propertyIndex >= mItemProperties.size()) {
+ ALOGW("Ignoring invalid property index %d", propertyIndex);
+ return;
+ }
+
+ ALOGV("attach property %d to item id %d)",
+ propertyIndex, association.itemId);
+
+ mItemProperties[propertyIndex]->attachTo(
+ mItemIdToImageMap.editValueAt(imageIndex));
+}
+
+sp<MetaData> ItemTable::getImageMeta() {
+ if (!mImageItemsValid) {
+ return NULL;
+ }
+
+ ssize_t imageIndex = mItemIdToImageMap.indexOfKey(mPrimaryItemId);
+ if (imageIndex < 0) {
+ ALOGE("Primary item id %d not found!", mPrimaryItemId);
+ return NULL;
+ }
+
+ ALOGV("primary image index %zu", imageIndex);
+
+ const ImageItem *image = &mItemIdToImageMap[imageIndex];
+
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC);
+
+ ALOGV("setting image size %dx%d", image->width, image->height);
+ meta->setInt32(kKeyWidth, image->width);
+ meta->setInt32(kKeyHeight, image->height);
+ if (image->rotation != 0) {
+ // Rotation angle in HEIF is CCW, convert to CW here to be
+ // consistent with the other media formats.
+ switch(image->rotation) {
+ case 90: meta->setInt32(kKeyRotation, 270); break;
+ case 180: meta->setInt32(kKeyRotation, 180); break;
+ case 270: meta->setInt32(kKeyRotation, 90); break;
+ default: break; // don't set if invalid
+ }
+ }
+ meta->setInt32(kKeyMaxInputSize, image->width * image->height * 1.5);
+
+ if (!image->thumbnails.empty()) {
+ ssize_t thumbnailIndex = mItemIdToImageMap.indexOfKey(image->thumbnails[0]);
+ if (thumbnailIndex >= 0) {
+ const ImageItem &thumbnail = mItemIdToImageMap[thumbnailIndex];
+
+ meta->setInt32(kKeyThumbnailWidth, thumbnail.width);
+ meta->setInt32(kKeyThumbnailHeight, thumbnail.height);
+ meta->setData(kKeyThumbnailHVCC, kTypeHVCC,
+ thumbnail.hvcc->data(), thumbnail.hvcc->size());
+ ALOGV("thumbnail meta: %dx%d, index %zd",
+ thumbnail.width, thumbnail.height, thumbnailIndex);
+ } else {
+ ALOGW("Referenced thumbnail does not exist!");
+ }
+ }
+
+ if (image->isGrid()) {
+ ssize_t tileIndex = mItemIdToImageMap.indexOfKey(image->dimgRefs[0]);
+ if (tileIndex < 0) {
+ return NULL;
+ }
+ meta->setInt32(kKeyGridRows, image->rows);
+ meta->setInt32(kKeyGridCols, image->columns);
+
+ // point image to the first tile for grid size and HVCC
+ image = &mItemIdToImageMap.editValueAt(tileIndex);
+ meta->setInt32(kKeyGridWidth, image->width);
+ meta->setInt32(kKeyGridHeight, image->height);
+ meta->setInt32(kKeyMaxInputSize, image->width * image->height * 1.5);
+ }
+
+ if (image->hvcc == NULL) {
+ ALOGE("hvcc is missing!");
+ return NULL;
+ }
+ meta->setData(kKeyHVCC, kTypeHVCC, image->hvcc->data(), image->hvcc->size());
+
+ if (image->icc != NULL) {
+ meta->setData(kKeyIccProfile, 0, image->icc->data(), image->icc->size());
+ }
+ return meta;
+}
+
+uint32_t ItemTable::countImages() const {
+ return mImageItemsValid ? mItemIdToImageMap.size() : 0;
+}
+
+status_t ItemTable::findPrimaryImage(uint32_t *imageIndex) {
+ if (!mImageItemsValid) {
+ return INVALID_OPERATION;
+ }
+
+ ssize_t index = mItemIdToImageMap.indexOfKey(mPrimaryItemId);
+ if (index < 0) {
+ return ERROR_MALFORMED;
+ }
+
+ *imageIndex = index;
+ return OK;
+}
+
+status_t ItemTable::findThumbnail(uint32_t *imageIndex) {
+ if (!mImageItemsValid) {
+ return INVALID_OPERATION;
+ }
+
+ ssize_t primaryIndex = mItemIdToImageMap.indexOfKey(mPrimaryItemId);
+ if (primaryIndex < 0) {
+ ALOGE("Primary item id %d not found!", mPrimaryItemId);
+ return ERROR_MALFORMED;
+ }
+
+ const ImageItem &primaryImage = mItemIdToImageMap[primaryIndex];
+ if (primaryImage.thumbnails.empty()) {
+ ALOGW("Using primary in place of thumbnail.");
+ *imageIndex = primaryIndex;
+ return OK;
+ }
+
+ ssize_t thumbnailIndex = mItemIdToImageMap.indexOfKey(
+ primaryImage.thumbnails[0]);
+ if (thumbnailIndex < 0) {
+ ALOGE("Thumbnail item id %d not found!", primaryImage.thumbnails[0]);
+ return ERROR_MALFORMED;
+ }
+
+ *imageIndex = thumbnailIndex;
+ return OK;
+}
+
+status_t ItemTable::getImageOffsetAndSize(
+ uint32_t *imageIndex, off64_t *offset, size_t *size) {
+ if (!mImageItemsValid) {
+ return INVALID_OPERATION;
+ }
+
+ if (imageIndex != NULL) {
+ if (*imageIndex >= mItemIdToImageMap.size()) {
+ ALOGE("Bad image index!");
+ return BAD_VALUE;
+ }
+ mCurrentImageIndex = *imageIndex;
+ }
+
+ ImageItem &image = mItemIdToImageMap.editValueAt(mCurrentImageIndex);
+ if (image.isGrid()) {
+ uint32_t tileItemId;
+ status_t err = image.getNextTileItemId(&tileItemId, imageIndex != NULL);
+ if (err != OK) {
+ return err;
+ }
+ ssize_t tileImageIndex = mItemIdToImageMap.indexOfKey(tileItemId);
+ if (tileImageIndex < 0) {
+ return ERROR_END_OF_STREAM;
+ }
+ *offset = mItemIdToImageMap[tileImageIndex].offset;
+ *size = mItemIdToImageMap[tileImageIndex].size;
+ } else {
+ if (imageIndex == NULL) {
+ // For single images, we only allow it to be read once, after that
+ // it's EOS. New image index must be requested each time.
+ return ERROR_END_OF_STREAM;
+ }
+ *offset = mItemIdToImageMap[mCurrentImageIndex].offset;
+ *size = mItemIdToImageMap[mCurrentImageIndex].size;
+ }
+
+ return OK;
+}
+
+} // namespace heif
+
+} // namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 87abb6a..9c777b3 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -19,6 +19,7 @@
#include <ctype.h>
#include <inttypes.h>
+#include <memory>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -27,6 +28,7 @@
#include "include/MPEG4Extractor.h"
#include "include/SampleTable.h"
+#include "include/ItemTable.h"
#include "include/ESDS.h"
#include <media/stagefright/foundation/ABitReader.h>
@@ -35,6 +37,7 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/ColorUtils.h>
+#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
@@ -71,7 +74,8 @@
const sp<SampleTable> &sampleTable,
Vector<SidxEntry> &sidx,
const Trex *trex,
- off64_t firstMoofOffset);
+ off64_t firstMoofOffset,
+ const sp<ItemTable> &itemTable);
virtual status_t init();
virtual status_t start(MetaData *params = NULL);
@@ -133,6 +137,9 @@
uint8_t *mSrcBuffer;
+ bool mIsHEIF;
+ sp<ItemTable> mItemTable;
+
size_t parseNALSize(const uint8_t *data) const;
status_t parseChunk(off64_t *offset);
status_t parseTrackFragmentHeader(off64_t offset, off64_t size);
@@ -284,45 +291,6 @@
static const bool kUseHexDump = false;
-static void hexdump(const void *_data, size_t size) {
- const uint8_t *data = (const uint8_t *)_data;
- size_t offset = 0;
- while (offset < size) {
- printf("0x%04zx ", offset);
-
- size_t n = size - offset;
- if (n > 16) {
- n = 16;
- }
-
- for (size_t i = 0; i < 16; ++i) {
- if (i == 8) {
- printf(" ");
- }
-
- if (offset + i < size) {
- printf("%02x ", data[offset + i]);
- } else {
- printf(" ");
- }
- }
-
- printf(" ");
-
- for (size_t i = 0; i < n; ++i) {
- if (isprint(data[offset + i])) {
- printf("%c", data[offset + i]);
- } else {
- printf(".");
- }
- }
-
- printf("\n");
-
- offset += 16;
- }
-}
-
static const char *FourCC2MIME(uint32_t fourcc) {
switch (fourcc) {
case FOURCC('m', 'p', '4', 'a'):
@@ -377,6 +345,7 @@
mInitCheck(NO_INIT),
mHeaderTimescale(0),
mIsQT(false),
+ mIsHEIF(false),
mFirstTrack(NULL),
mLastTrack(NULL),
mFileMetaData(new MetaData),
@@ -385,6 +354,10 @@
}
MPEG4Extractor::~MPEG4Extractor() {
+ release();
+}
+
+void MPEG4Extractor::release() {
Track *track = mFirstTrack;
while (track) {
Track *next = track->next;
@@ -406,6 +379,12 @@
for (size_t i = 0; i < mPssh.size(); i++) {
delete [] mPssh[i].data;
}
+ mPssh.clear();
+
+ if (mDataSource != NULL) {
+ mDataSource->close();
+ mDataSource.clear();
+ }
}
uint32_t MPEG4Extractor::flags() const {
@@ -511,14 +490,6 @@
return track->meta;
}
-static void MakeFourCCString(uint32_t x, char *s) {
- s[0] = x >> 24;
- s[1] = (x >> 16) & 0xff;
- s[2] = (x >> 8) & 0xff;
- s[3] = x & 0xff;
- s[4] = '\0';
-}
-
status_t MPEG4Extractor::readMetaData() {
if (mInitCheck != NO_INIT) {
return mInitCheck;
@@ -528,7 +499,8 @@
status_t err;
bool sawMoovOrSidx = false;
- while (!(sawMoovOrSidx && (mMdatFound || mMoofFound))) {
+ while (!((sawMoovOrSidx && (mMdatFound || mMoofFound)) ||
+ (mIsHEIF && (mItemTable != NULL) && mItemTable->isValid()))) {
off64_t orig_offset = offset;
err = parseChunk(&offset, 0);
@@ -580,6 +552,29 @@
mFileMetaData->setData(kKeyPssh, 'pssh', buf, psshsize);
free(buf);
}
+
+ if (mIsHEIF) {
+ sp<MetaData> meta = mItemTable->getImageMeta();
+ if (meta == NULL) {
+ return ERROR_MALFORMED;
+ }
+
+ Track *track = mLastTrack;
+ if (track != NULL) {
+ ALOGW("track is set before metadata is fully processed");
+ } else {
+ track = new Track;
+ track->next = NULL;
+ mFirstTrack = mLastTrack = track;
+ }
+
+ track->meta = meta;
+ track->meta->setInt32(kKeyTrackID, 0);
+ track->includes_expensive_metadata = false;
+ track->skipTrack = false;
+ track->timescale = 0;
+ }
+
return mInitCheck;
}
@@ -966,8 +961,9 @@
}
}
- if (mLastTrack == NULL)
+ if (mLastTrack == NULL) {
return ERROR_MALFORMED;
+ }
mLastTrack->sampleTable = new SampleTable(mDataSource);
}
@@ -1139,8 +1135,9 @@
original_fourcc = ntohl(original_fourcc);
ALOGV("read original format: %d", original_fourcc);
- if (mLastTrack == NULL)
+ if (mLastTrack == NULL) {
return ERROR_MALFORMED;
+ }
mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(original_fourcc));
uint32_t num_channels = 0;
@@ -1580,8 +1577,9 @@
case FOURCC('s', 't', 'c', 'o'):
case FOURCC('c', 'o', '6', '4'):
{
- if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL)) {
return ERROR_MALFORMED;
+ }
status_t err =
mLastTrack->sampleTable->setChunkOffsetParams(
@@ -1617,8 +1615,9 @@
case FOURCC('s', 't', 's', 'z'):
case FOURCC('s', 't', 'z', '2'):
{
- if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL)) {
return ERROR_MALFORMED;
+ }
status_t err =
mLastTrack->sampleTable->setSampleSizeParams(
@@ -1779,35 +1778,49 @@
{
*offset += chunk_size;
- // Best case the total data length inside "\xA9xyz" box
- // would be 8, for instance "\xA9xyz" + "\x00\x04\x15\xc7" + "0+0/",
- // where "\x00\x04" is the text string length with value = 4,
- // "\0x15\xc7" is the language code = en, and "0+0" is a
+ // Best case the total data length inside "\xA9xyz" box would
+ // be 9, for instance "\xA9xyz" + "\x00\x05\x15\xc7" + "+0+0/",
+ // where "\x00\x05" is the text string length with value = 5,
+ // "\0x15\xc7" is the language code = en, and "+0+0/" is a
// location (string) value with longitude = 0 and latitude = 0.
- if (chunk_data_size < 8) {
+ // Since some devices encountered in the wild omit the trailing
+ // slash, we'll allow that.
+ if (chunk_data_size < 8) { // 8 instead of 9 to allow for missing /
return ERROR_MALFORMED;
}
- // Worst case the location string length would be 18,
- // for instance +90.0000-180.0000, without the trailing "/" and
- // the string length + language code, and some devices include
- // an additional 8 bytes of altitude, e.g. +007.186
- char buffer[18 + 8];
-
- // Substracting 5 from the data size is because the text string length +
- // language code takes 4 bytes, and the trailing slash "/" takes 1 byte.
- off64_t location_length = chunk_data_size - 5;
- if (location_length >= (off64_t) sizeof(buffer)) {
- return ERROR_MALFORMED;
- }
-
- if (mDataSource->readAt(
- data_offset + 4, buffer, location_length) < location_length) {
+ uint16_t len;
+ if (!mDataSource->getUInt16(data_offset, &len)) {
return ERROR_IO;
}
- buffer[location_length] = '\0';
- mFileMetaData->setCString(kKeyLocation, buffer);
+ // allow "+0+0" without trailing slash
+ if (len < 4 || len > chunk_data_size - 4) {
+ return ERROR_MALFORMED;
+ }
+ // The location string following the language code is formatted
+ // according to ISO 6709:2008 (https://en.wikipedia.org/wiki/ISO_6709).
+ // Allocate 2 extra bytes, in case we need to add a trailing slash,
+ // and to add a terminating 0.
+ std::unique_ptr<char[]> buffer(new (std::nothrow) char[len+2]());
+ if (!buffer) {
+ return NO_MEMORY;
+ }
+
+ if (mDataSource->readAt(
+ data_offset + 4, &buffer[0], len) < len) {
+ return ERROR_IO;
+ }
+
+ len = strlen(&buffer[0]);
+ if (len < 4) {
+ return ERROR_MALFORMED;
+ }
+ // Add a trailing slash if there wasn't one.
+ if (buffer[len - 1] != '/') {
+ buffer[len] = '/';
+ }
+ mFileMetaData->setCString(kKeyLocation, &buffer[0]);
break;
}
@@ -2023,6 +2036,28 @@
break;
}
+ case FOURCC('i', 'l', 'o', 'c'):
+ case FOURCC('i', 'i', 'n', 'f'):
+ case FOURCC('i', 'p', 'r', 'p'):
+ case FOURCC('p', 'i', 't', 'm'):
+ case FOURCC('i', 'd', 'a', 't'):
+ case FOURCC('i', 'r', 'e', 'f'):
+ case FOURCC('i', 'p', 'r', 'o'):
+ {
+ if (mIsHEIF) {
+ if (mItemTable == NULL) {
+ mItemTable = new ItemTable(mDataSource);
+ }
+ status_t err = mItemTable->parse(
+ chunk_type, data_offset, chunk_data_size);
+ if (err != OK) {
+ return err;
+ }
+ }
+ *offset += chunk_size;
+ break;
+ }
+
case FOURCC('m', 'e', 'a', 'n'):
case FOURCC('n', 'a', 'm', 'e'):
case FOURCC('d', 'a', 't', 'a'):
@@ -2370,6 +2405,7 @@
off64_t stop_offset = *offset + chunk_size;
uint32_t numCompatibleBrands = (chunk_data_size - 8) / 4;
+ std::set<uint32_t> brandSet;
for (size_t i = 0; i < numCompatibleBrands + 2; ++i) {
if (i == 1) {
// Skip this index, it refers to the minorVersion,
@@ -2383,10 +2419,15 @@
}
brand = ntohl(brand);
- if (brand == FOURCC('q', 't', ' ', ' ')) {
- mIsQT = true;
- break;
- }
+ brandSet.insert(brand);
+ }
+
+ if (brandSet.count(FOURCC('q', 't', ' ', ' ')) > 0) {
+ mIsQT = true;
+ } else if (brandSet.count(FOURCC('m', 'i', 'f', '1')) > 0
+ && brandSet.count(FOURCC('h', 'e', 'i', 'c')) > 0) {
+ mIsHEIF = true;
+ ALOGV("identified HEIF image");
}
*offset = stop_offset;
@@ -3335,7 +3376,7 @@
sp<MPEG4Source> source = new MPEG4Source(this,
track->meta, mDataSource, track->timescale, track->sampleTable,
- mSidxEntries, trex, mMoofOffset);
+ mSidxEntries, trex, mMoofOffset, mItemTable);
if (source->init() != OK) {
return NULL;
}
@@ -3724,7 +3765,8 @@
const sp<SampleTable> &sampleTable,
Vector<SidxEntry> &sidx,
const Trex *trex,
- off64_t firstMoofOffset)
+ off64_t firstMoofOffset,
+ const sp<ItemTable> &itemTable)
: mOwner(owner),
mFormat(format),
mDataSource(dataSource),
@@ -3749,7 +3791,9 @@
mGroup(NULL),
mBuffer(NULL),
mWantsNALFragments(false),
- mSrcBuffer(NULL) {
+ mSrcBuffer(NULL),
+ mIsHEIF(itemTable != NULL),
+ mItemTable(itemTable) {
memset(&mTrackFragmentHeaderInfo, 0, sizeof(mTrackFragmentHeaderInfo));
@@ -4524,77 +4568,93 @@
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- uint32_t findFlags = 0;
- switch (mode) {
- case ReadOptions::SEEK_PREVIOUS_SYNC:
- findFlags = SampleTable::kFlagBefore;
- break;
- case ReadOptions::SEEK_NEXT_SYNC:
- findFlags = SampleTable::kFlagAfter;
- break;
- case ReadOptions::SEEK_CLOSEST_SYNC:
- case ReadOptions::SEEK_CLOSEST:
- findFlags = SampleTable::kFlagClosest;
- break;
- default:
- CHECK(!"Should not be here.");
- break;
- }
+ if (mIsHEIF) {
+ CHECK(mSampleTable == NULL);
+ CHECK(mItemTable != NULL);
- uint32_t sampleIndex;
- status_t err = mSampleTable->findSampleAtTime(
- seekTimeUs, 1000000, mTimescale,
- &sampleIndex, findFlags);
-
- if (mode == ReadOptions::SEEK_CLOSEST) {
- // We found the closest sample already, now we want the sync
- // sample preceding it (or the sample itself of course), even
- // if the subsequent sync sample is closer.
- findFlags = SampleTable::kFlagBefore;
- }
-
- uint32_t syncSampleIndex;
- if (err == OK) {
- err = mSampleTable->findSyncSampleNear(
- sampleIndex, &syncSampleIndex, findFlags);
- }
-
- uint32_t sampleTime;
- if (err == OK) {
- err = mSampleTable->getMetaDataForSample(
- sampleIndex, NULL, NULL, &sampleTime);
- }
-
- if (err != OK) {
- if (err == ERROR_OUT_OF_RANGE) {
- // An attempt to seek past the end of the stream would
- // normally cause this ERROR_OUT_OF_RANGE error. Propagating
- // this all the way to the MediaPlayer would cause abnormal
- // termination. Legacy behaviour appears to be to behave as if
- // we had seeked to the end of stream, ending normally.
- err = ERROR_END_OF_STREAM;
+ status_t err;
+ if (seekTimeUs >= 0) {
+ err = mItemTable->findPrimaryImage(&mCurrentSampleIndex);
+ } else {
+ err = mItemTable->findThumbnail(&mCurrentSampleIndex);
}
- ALOGV("end of stream");
- return err;
- }
+ if (err != OK) {
+ return err;
+ }
+ } else {
+ uint32_t findFlags = 0;
+ switch (mode) {
+ case ReadOptions::SEEK_PREVIOUS_SYNC:
+ findFlags = SampleTable::kFlagBefore;
+ break;
+ case ReadOptions::SEEK_NEXT_SYNC:
+ findFlags = SampleTable::kFlagAfter;
+ break;
+ case ReadOptions::SEEK_CLOSEST_SYNC:
+ case ReadOptions::SEEK_CLOSEST:
+ findFlags = SampleTable::kFlagClosest;
+ break;
+ default:
+ CHECK(!"Should not be here.");
+ break;
+ }
- if (mode == ReadOptions::SEEK_CLOSEST) {
- targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale;
- }
+ uint32_t sampleIndex;
+ status_t err = mSampleTable->findSampleAtTime(
+ seekTimeUs, 1000000, mTimescale,
+ &sampleIndex, findFlags);
+
+ if (mode == ReadOptions::SEEK_CLOSEST) {
+ // We found the closest sample already, now we want the sync
+ // sample preceding it (or the sample itself of course), even
+ // if the subsequent sync sample is closer.
+ findFlags = SampleTable::kFlagBefore;
+ }
+
+ uint32_t syncSampleIndex;
+ if (err == OK) {
+ err = mSampleTable->findSyncSampleNear(
+ sampleIndex, &syncSampleIndex, findFlags);
+ }
+
+ uint32_t sampleTime;
+ if (err == OK) {
+ err = mSampleTable->getMetaDataForSample(
+ sampleIndex, NULL, NULL, &sampleTime);
+ }
+
+ if (err != OK) {
+ if (err == ERROR_OUT_OF_RANGE) {
+ // An attempt to seek past the end of the stream would
+ // normally cause this ERROR_OUT_OF_RANGE error. Propagating
+ // this all the way to the MediaPlayer would cause abnormal
+ // termination. Legacy behaviour appears to be to behave as if
+ // we had seeked to the end of stream, ending normally.
+ err = ERROR_END_OF_STREAM;
+ }
+ ALOGV("end of stream");
+ return err;
+ }
+
+ if (mode == ReadOptions::SEEK_CLOSEST) {
+ targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale;
+ }
#if 0
- uint32_t syncSampleTime;
- CHECK_EQ(OK, mSampleTable->getMetaDataForSample(
- syncSampleIndex, NULL, NULL, &syncSampleTime));
+ uint32_t syncSampleTime;
+ CHECK_EQ(OK, mSampleTable->getMetaDataForSample(
+ syncSampleIndex, NULL, NULL, &syncSampleTime));
- ALOGI("seek to time %lld us => sample at time %lld us, "
- "sync sample at time %lld us",
- seekTimeUs,
- sampleTime * 1000000ll / mTimescale,
- syncSampleTime * 1000000ll / mTimescale);
+ ALOGI("seek to time %lld us => sample at time %lld us, "
+ "sync sample at time %lld us",
+ seekTimeUs,
+ sampleTime * 1000000ll / mTimescale,
+ syncSampleTime * 1000000ll / mTimescale);
#endif
- mCurrentSampleIndex = syncSampleIndex;
+ mCurrentSampleIndex = syncSampleIndex;
+ }
+
if (mBuffer != NULL) {
mBuffer->release();
mBuffer = NULL;
@@ -4611,9 +4671,19 @@
if (mBuffer == NULL) {
newBuffer = true;
- status_t err =
- mSampleTable->getMetaDataForSample(
+ status_t err;
+ if (!mIsHEIF) {
+ err = mSampleTable->getMetaDataForSample(
mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample, &stts);
+ } else {
+ err = mItemTable->getImageOffsetAndSize(
+ options && options->getSeekTo(&seekTimeUs, &mode) ?
+ &mCurrentSampleIndex : NULL, &offset, &size);
+
+ cts = stts = 0;
+ isSyncSample = 0;
+ ALOGV("image offset %lld, size %zu", (long long)offset, size);
+ }
if (err != OK) {
return err;
@@ -5171,6 +5241,7 @@
void MPEG4Extractor::populateMetrics() {
ALOGV("MPEG4Extractor::populateMetrics");
+ // write into mAnalyticsItem
}
static bool LegacySniffMPEG4(
@@ -5187,7 +5258,8 @@
|| !memcmp(header, "ftyp3ge6", 8) || !memcmp(header, "ftyp3gg6", 8)
|| !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)
|| !memcmp(header, "ftypM4A ", 8) || !memcmp(header, "ftypf4v ", 8)
- || !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)) {
+ || !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)
+ || !memcmp(header, "ftypmif1", 8) || !memcmp(header, "ftypheic", 8)) {
*mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
*confidence = 0.4;
@@ -5216,6 +5288,8 @@
FOURCC('3', 'g', '2', 'a'), // 3GPP2
FOURCC('3', 'g', '2', 'b'),
+ FOURCC('m', 'i', 'f', '1'), // HEIF image
+ FOURCC('h', 'e', 'i', 'c'), // HEIF image
};
for (size_t i = 0;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 93d4f57..7786c4d 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -432,7 +432,7 @@
};
MPEG4Writer::MPEG4Writer(int fd) {
- initInternal(fd);
+ initInternal(fd, true /*isFirstSession*/);
}
MPEG4Writer::~MPEG4Writer() {
@@ -451,19 +451,26 @@
}
}
-void MPEG4Writer::initInternal(int fd) {
+void MPEG4Writer::initInternal(int fd, bool isFirstSession) {
ALOGV("initInternal");
mFd = dup(fd);
mNextFd = -1;
mInitCheck = mFd < 0? NO_INIT: OK;
- mIsRealTimeRecording = true;
- mUse4ByteNalLength = true;
- mUse32BitOffset = true;
- mIsFileSizeLimitExplicitlyRequested = false;
+
+ mInterleaveDurationUs = 1000000;
+
+ mStartTimestampUs = -1ll;
+ mStartTimeOffsetMs = -1;
mPaused = false;
mStarted = false;
mWriterThreadStarted = false;
mSendNotify = false;
+
+ // Reset following variables for all the sessions and they will be
+ // initialized in start(MetaData *param).
+ mIsRealTimeRecording = true;
+ mUse4ByteNalLength = true;
+ mUse32BitOffset = true;
mOffset = 0;
mMdatOffset = 0;
mMoovBoxBuffer = NULL;
@@ -472,17 +479,21 @@
mFreeBoxOffset = 0;
mStreamableFile = false;
mEstimatedMoovBoxSize = 0;
- mMoovExtraSize = 0;
- mInterleaveDurationUs = 1000000;
mTimeScale = -1;
- mStartTimestampUs = -1ll;
- mLatitudex10000 = 0;
- mLongitudex10000 = 0;
- mAreGeoTagsAvailable = false;
- mStartTimeOffsetMs = -1;
- mSwitchPending = false;
- mMetaKeys = new AMessage();
- addDeviceMeta();
+
+ // Following variables only need to be set for the first recording session.
+ // And they will stay the same for all the recording sessions.
+ if (isFirstSession) {
+ mMoovExtraSize = 0;
+ mMetaKeys = new AMessage();
+ addDeviceMeta();
+ mLatitudex10000 = 0;
+ mLongitudex10000 = 0;
+ mAreGeoTagsAvailable = false;
+ mSwitchPending = false;
+ mIsFileSizeLimitExplicitlyRequested = false;
+ }
+
// Verify mFd is seekable
off64_t off = lseek64(mFd, 0, SEEK_SET);
if (off < 0) {
@@ -873,19 +884,8 @@
}
status_t MPEG4Writer::pause() {
- if (mInitCheck != OK) {
- return OK;
- }
- mPaused = true;
- status_t err = OK;
- for (List<Track *>::iterator it = mTracks.begin();
- it != mTracks.end(); ++it) {
- status_t status = (*it)->pause();
- if (status != OK) {
- err = status;
- }
- }
- return err;
+ ALOGW("MPEG4Writer: pause is not supported");
+ return ERROR_UNSUPPORTED;
}
void MPEG4Writer::stopWriterThread() {
@@ -1833,7 +1833,7 @@
int fd = mNextFd;
mNextFd = -1;
mLock.unlock();
- initInternal(fd);
+ initInternal(fd, false /*isFirstSession*/);
start(mStartMeta.get());
mSwitchPending = false;
notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED, 0);
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index bd71632..759e42d 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -23,7 +23,8 @@
#include "include/SharedMemoryBuffer.h"
#include "include/SoftwareRenderer.h"
-#include <android/media/IDescrambler.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+
#include <binder/IMemory.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -72,6 +73,13 @@
static const char *kCodecCrypto = "android.media.mediacodec.crypto"; /* 0,1 */
static const char *kCodecEncoder = "android.media.mediacodec.encoder"; /* 0,1 */
+static const char *kCodecBytesIn = "android.media.mediacodec.bytesin"; /* 0..n */
+static const char *kCodecProfile = "android.media.mediacodec.profile"; /* 0..n */
+static const char *kCodecLevel = "android.media.mediacodec.level"; /* 0..n */
+static const char *kCodecMaxWidth = "android.media.mediacodec.maxwidth"; /* 0..n */
+static const char *kCodecMaxHeight = "android.media.mediacodec.maxheight"; /* 0..n */
+static const char *kCodecError = "android.media.mediacodec.errcode";
+static const char *kCodecErrorState = "android.media.mediacodec.errstate";
static int64_t getId(const sp<IResourceManagerClient> &client) {
@@ -428,22 +436,6 @@
}
// static
-status_t MediaCodec::QueryCapabilities(
- const AString &name, const AString &mime, bool isEncoder,
- sp<MediaCodecInfo::Capabilities> *caps /* nonnull */) {
- // TRICKY: this method is used by MediaCodecList/Info during its
- // initialization. As such, we cannot create a MediaCodec instance
- // because that requires an initialized MediaCodecList.
-
- sp<CodecBase> codec = GetCodecBase(name);
- if (codec == NULL) {
- return NAME_NOT_FOUND;
- }
-
- return codec->queryCapabilities(name, mime, isEncoder, caps);
-}
-
-// static
sp<PersistentSurface> MediaCodec::CreatePersistentInputSurface() {
OMXClient client;
if (client.connect() != OK) {
@@ -475,6 +467,7 @@
mFlags(0),
mStickyError(OK),
mSoftRenderer(NULL),
+ mAnalyticsItem(NULL),
mResourceManagerClient(new ResourceManagerClient(this)),
mResourceManagerService(new ResourceManagerServiceProxy(pid)),
mBatteryStatNotified(false),
@@ -493,6 +486,18 @@
} else {
mUid = uid;
}
+ initAnalyticsItem();
+}
+
+MediaCodec::~MediaCodec() {
+ CHECK_EQ(mState, UNINITIALIZED);
+ mResourceManagerService->removeResource(getId(mResourceManagerClient));
+
+ flushAnalyticsItem();
+}
+
+void MediaCodec::initAnalyticsItem() {
+ CHECK(mAnalyticsItem == NULL);
// set up our new record, get a sessionID, put it into the in-progress list
mAnalyticsItem = new MediaAnalyticsItem(kCodecKeyName);
if (mAnalyticsItem != NULL) {
@@ -502,11 +507,9 @@
}
}
-MediaCodec::~MediaCodec() {
- CHECK_EQ(mState, UNINITIALIZED);
- mResourceManagerService->removeResource(getId(mResourceManagerClient));
-
- if (mAnalyticsItem != NULL ) {
+void MediaCodec::flushAnalyticsItem() {
+ if (mAnalyticsItem != NULL) {
+ // don't log empty records
if (mAnalyticsItem->count() > 0) {
mAnalyticsItem->setFinalized(true);
mAnalyticsItem->selfrecord();
@@ -699,10 +702,21 @@
uint32_t flags) {
sp<AMessage> msg = new AMessage(kWhatConfigure, this);
+ if (mAnalyticsItem != NULL) {
+ int32_t profile = 0;
+ if (format->findInt32("profile", &profile)) {
+ mAnalyticsItem->setInt32(kCodecProfile, profile);
+ }
+ int32_t level = 0;
+ if (format->findInt32("level", &level)) {
+ mAnalyticsItem->setInt32(kCodecLevel, level);
+ }
+ }
+
if (mIsVideo) {
format->findInt32("width", &mVideoWidth);
format->findInt32("height", &mVideoHeight);
- if (!format->findInt32(kCodecRotation, &mRotationDegrees)) {
+ if (!format->findInt32("rotation-degrees", &mRotationDegrees)) {
mRotationDegrees = 0;
}
@@ -710,6 +724,14 @@
mAnalyticsItem->setInt32(kCodecWidth, mVideoWidth);
mAnalyticsItem->setInt32(kCodecHeight, mVideoHeight);
mAnalyticsItem->setInt32(kCodecRotation, mRotationDegrees);
+ int32_t maxWidth = 0;
+ if (format->findInt32("max-width", &maxWidth)) {
+ mAnalyticsItem->setInt32(kCodecMaxWidth, maxWidth);
+ }
+ int32_t maxHeight = 0;
+ if (format->findInt32("max-height", &maxHeight)) {
+ mAnalyticsItem->setInt32(kCodecMaxHeight, maxHeight);
+ }
}
// Prevent possible integer overflow in downstream code.
@@ -1416,6 +1438,12 @@
case CONFIGURING:
{
+ if (actionCode == ACTION_CODE_FATAL) {
+ mAnalyticsItem->setInt32(kCodecError, err);
+ mAnalyticsItem->setInt32(kCodecErrorState, mState);
+ flushAnalyticsItem();
+ initAnalyticsItem();
+ }
setState(actionCode == ACTION_CODE_FATAL ?
UNINITIALIZED : INITIALIZED);
break;
@@ -1423,6 +1451,12 @@
case STARTING:
{
+ if (actionCode == ACTION_CODE_FATAL) {
+ mAnalyticsItem->setInt32(kCodecError, err);
+ mAnalyticsItem->setInt32(kCodecErrorState, mState);
+ flushAnalyticsItem();
+ initAnalyticsItem();
+ }
setState(actionCode == ACTION_CODE_FATAL ?
UNINITIALIZED : CONFIGURED);
break;
@@ -1459,6 +1493,11 @@
case FLUSHING:
{
if (actionCode == ACTION_CODE_FATAL) {
+ mAnalyticsItem->setInt32(kCodecError, err);
+ mAnalyticsItem->setInt32(kCodecErrorState, mState);
+ flushAnalyticsItem();
+ initAnalyticsItem();
+
setState(UNINITIALIZED);
} else {
setState(
@@ -1487,6 +1526,10 @@
setState(INITIALIZED);
break;
default:
+ mAnalyticsItem->setInt32(kCodecError, err);
+ mAnalyticsItem->setInt32(kCodecErrorState, mState);
+ flushAnalyticsItem();
+ initAnalyticsItem();
setState(UNINITIALIZED);
break;
}
@@ -1591,6 +1634,19 @@
}
setState(CONFIGURED);
(new AMessage)->postReply(mReplyID);
+
+ // augment our media metrics info, now that we know more things
+ if (mAnalyticsItem != NULL) {
+ sp<AMessage> format;
+ if (mConfigureMsg != NULL &&
+ mConfigureMsg->findMessage("format", &format)) {
+ // format includes: mime
+ AString mime;
+ if (format->findString("mime", &mime)) {
+ mAnalyticsItem->setCString(kCodecMime, mime.c_str());
+ }
+ }
+ }
break;
}
@@ -2816,6 +2872,9 @@
Mutex::Autolock al(mBufferLock);
info->mOwnedByClient = false;
info->mData.clear();
+ if (mAnalyticsItem != NULL) {
+ mAnalyticsItem->addInt64(kCodecBytesIn, size);
+ }
}
return err;
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 1dcba29..4652594 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -24,17 +24,17 @@
#include <media/IMediaCodecList.h>
#include <media/IMediaPlayerService.h>
-#include <media/IResourceManagerService.h>
+#include <media/IMediaCodecService.h>
#include <media/MediaCodecInfo.h>
-#include <media/MediaResourcePolicy.h>
+#include <media/MediaDefs.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/ACodec.h>
-#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OmxInfoBuilder.h>
+#include <media/stagefright/omx/OMXUtils.h>
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
#include <sys/stat.h>
#include <utils/threads.h>
@@ -42,20 +42,20 @@
#include <cutils/properties.h>
#include <expat.h>
+#include <algorithm>
+
namespace android {
-static Mutex sInitMutex;
+namespace {
-static bool parseBoolean(const char *s) {
- if (!strcasecmp(s, "true") || !strcasecmp(s, "yes") || !strcasecmp(s, "y")) {
- return true;
- }
- char *end;
- unsigned long res = strtoul(s, &end, 10);
- return *s != '\0' && *end == '\0' && res > 0;
-}
+Mutex sInitMutex;
-static bool isProfilingNeeded() {
+Mutex sRemoteInitMutex;
+
+constexpr const char* kProfilingResults =
+ MediaCodecsXmlParser::defaultProfilingResultsXmlPath;
+
+bool isProfilingNeeded() {
int8_t value = property_get_bool("debug.stagefright.profilecodec", 0);
if (value == 0) {
return false;
@@ -78,6 +78,10 @@
return profilingNeeded;
}
+OmxInfoBuilder sOmxInfoBuilder;
+
+} // unnamed namespace
+
// static
sp<IMediaCodecList> MediaCodecList::sCodecList;
@@ -86,42 +90,42 @@
ALOGV("Enter profilerThreadWrapper.");
remove(kProfilingResults); // remove previous result so that it won't be loaded to
// the new MediaCodecList
- MediaCodecList *codecList = new MediaCodecList();
+ sp<MediaCodecList> codecList(new MediaCodecList(&sOmxInfoBuilder));
if (codecList->initCheck() != OK) {
ALOGW("Failed to create a new MediaCodecList, skipping codec profiling.");
- delete codecList;
- return NULL;
+ return nullptr;
}
- Vector<sp<MediaCodecInfo>> infos;
- for (size_t i = 0; i < codecList->countCodecs(); ++i) {
- infos.push_back(codecList->getCodecInfo(i));
- }
+ const auto& infos = codecList->mCodecInfos;
ALOGV("Codec profiling started.");
- profileCodecs(infos);
+ profileCodecs(infos, kProfilingResults);
ALOGV("Codec profiling completed.");
- codecList->parseTopLevelXMLFile(kProfilingResults, true /* ignore_errors */);
+ codecList = new MediaCodecList(&sOmxInfoBuilder);
+ if (codecList->initCheck() != OK) {
+ ALOGW("Failed to parse profiling results.");
+ return nullptr;
+ }
{
Mutex::Autolock autoLock(sInitMutex);
sCodecList = codecList;
}
- return NULL;
+ return nullptr;
}
// static
sp<IMediaCodecList> MediaCodecList::getLocalInstance() {
Mutex::Autolock autoLock(sInitMutex);
- if (sCodecList == NULL) {
- MediaCodecList *codecList = new MediaCodecList;
+ if (sCodecList == nullptr) {
+ MediaCodecList *codecList = new MediaCodecList(&sOmxInfoBuilder);
if (codecList->initCheck() == OK) {
sCodecList = codecList;
if (isProfilingNeeded()) {
ALOGV("Codec profiling needed, will be run in separated thread.");
pthread_t profiler;
- if (pthread_create(&profiler, NULL, profilerThreadWrapper, NULL) != 0) {
+ if (pthread_create(&profiler, nullptr, profilerThreadWrapper, nullptr) != 0) {
ALOGW("Failed to create thread for codec profiling.");
}
}
@@ -134,8 +138,6 @@
return sCodecList;
}
-static Mutex sRemoteInitMutex;
-
sp<IMediaCodecList> MediaCodecList::sRemoteList;
sp<MediaCodecList::BinderDeathObserver> MediaCodecList::sBinderDeathObserver;
@@ -149,19 +151,19 @@
// static
sp<IMediaCodecList> MediaCodecList::getInstance() {
Mutex::Autolock _l(sRemoteInitMutex);
- if (sRemoteList == NULL) {
+ if (sRemoteList == nullptr) {
sp<IBinder> binder =
defaultServiceManager()->getService(String16("media.player"));
sp<IMediaPlayerService> service =
interface_cast<IMediaPlayerService>(binder);
- if (service.get() != NULL) {
+ if (service.get() != nullptr) {
sRemoteList = service->getCodecList();
- if (sRemoteList != NULL) {
+ if (sRemoteList != nullptr) {
sBinderDeathObserver = new BinderDeathObserver();
binder->linkToDeath(sBinderDeathObserver.get());
}
}
- if (sRemoteList == NULL) {
+ if (sRemoteList == nullptr) {
// if failed to get remote list, create local list
sRemoteList = getLocalInstance();
}
@@ -169,175 +171,11 @@
return sRemoteList;
}
-// Treblized media codec list will be located in /odm/etc or /vendor/etc.
-static const char *kConfigLocationList[] =
- {"/odm/etc", "/vendor/etc", "/etc"};
-static const int kConfigLocationListSize =
- (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
-
-#define MEDIA_CODECS_CONFIG_FILE_PATH_MAX_LENGTH 128
-
-static bool findMediaCodecListFileFullPath(const char *file_name, char *out_path) {
- for (int i = 0; i < kConfigLocationListSize; i++) {
- snprintf(out_path,
- MEDIA_CODECS_CONFIG_FILE_PATH_MAX_LENGTH,
- "%s/%s",
- kConfigLocationList[i],
- file_name);
- struct stat file_stat;
- if (stat(out_path, &file_stat) == 0 && S_ISREG(file_stat.st_mode)) {
- return true;
- }
- }
- return false;
-}
-
-MediaCodecList::MediaCodecList()
- : mInitCheck(NO_INIT),
- mUpdate(false),
- mGlobalSettings(new AMessage()) {
- char config_file_path[MEDIA_CODECS_CONFIG_FILE_PATH_MAX_LENGTH];
- if (findMediaCodecListFileFullPath("media_codecs.xml", config_file_path)) {
- parseTopLevelXMLFile(config_file_path);
- }
- if (findMediaCodecListFileFullPath("media_codecs_performance.xml",
- config_file_path)) {
- parseTopLevelXMLFile(config_file_path, true/* ignore_errors */);
- }
- parseTopLevelXMLFile(kProfilingResults, true/* ignore_errors */);
-}
-
-void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml, bool ignore_errors) {
- // get href_base
- const char *href_base_end = strrchr(codecs_xml, '/');
- if (href_base_end != NULL) {
- mHrefBase = AString(codecs_xml, href_base_end - codecs_xml + 1);
- }
-
- mInitCheck = OK; // keeping this here for safety
- mCurrentSection = SECTION_TOPLEVEL;
- mDepth = 0;
-
- OMXClient client;
- mInitCheck = client.connect();
- if (mInitCheck != OK) {
- return; // this may fail if IMediaPlayerService is not available.
- }
- parseXMLFile(codecs_xml);
-
- if (mInitCheck != OK) {
- if (ignore_errors) {
- mInitCheck = OK;
- return;
- }
- mCodecInfos.clear();
- return;
- }
-
- Vector<MediaResourcePolicy> policies;
- AString value;
- if (mGlobalSettings->findString(kPolicySupportsMultipleSecureCodecs, &value)) {
- policies.push_back(
- MediaResourcePolicy(
- String8(kPolicySupportsMultipleSecureCodecs),
- String8(value.c_str())));
- }
- if (mGlobalSettings->findString(kPolicySupportsSecureWithNonSecureCodec, &value)) {
- policies.push_back(
- MediaResourcePolicy(
- String8(kPolicySupportsSecureWithNonSecureCodec),
- String8(value.c_str())));
- }
- if (policies.size() > 0) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.resource_manager"));
- sp<IResourceManagerService> service = interface_cast<IResourceManagerService>(binder);
- if (service == NULL) {
- ALOGE("MediaCodecList: failed to get ResourceManagerService");
- } else {
- service->config(policies);
- }
- }
-
- for (size_t i = mCodecInfos.size(); i > 0;) {
- i--;
- const MediaCodecInfo &info = *mCodecInfos.itemAt(i).get();
- if (info.mCaps.size() == 0) {
- // No types supported by this component???
- ALOGW("Component %s does not support any type of media?",
- info.mName.c_str());
-
- mCodecInfos.removeAt(i);
-#if LOG_NDEBUG == 0
- } else {
- for (size_t type_ix = 0; type_ix < info.mCaps.size(); ++type_ix) {
- AString mime = info.mCaps.keyAt(type_ix);
- const sp<MediaCodecInfo::Capabilities> &caps = info.mCaps.valueAt(type_ix);
-
- ALOGV("%s codec info for %s: %s", info.mName.c_str(), mime.c_str(),
- caps->getDetails()->debugString().c_str());
- ALOGV(" flags=%d", caps->getFlags());
- {
- Vector<uint32_t> colorFormats;
- caps->getSupportedColorFormats(&colorFormats);
- AString nice;
- for (size_t ix = 0; ix < colorFormats.size(); ix++) {
- if (ix > 0) {
- nice.append(", ");
- }
- nice.append(colorFormats.itemAt(ix));
- }
- ALOGV(" colors=[%s]", nice.c_str());
- }
- {
- Vector<MediaCodecInfo::ProfileLevel> profileLevels;
- caps->getSupportedProfileLevels(&profileLevels);
- AString nice;
- for (size_t ix = 0; ix < profileLevels.size(); ix++) {
- if (ix > 0) {
- nice.append(", ");
- }
- const MediaCodecInfo::ProfileLevel &pl =
- profileLevels.itemAt(ix);
- nice.append(pl.mProfile);
- nice.append("/");
- nice.append(pl.mLevel);
- }
- ALOGV(" levels=[%s]", nice.c_str());
- }
- {
- AString quirks;
- for (size_t ix = 0; ix < info.mQuirks.size(); ix++) {
- if (ix > 0) {
- quirks.append(", ");
- }
- quirks.append(info.mQuirks[ix]);
- }
- ALOGV(" quirks=[%s]", quirks.c_str());
- }
- }
-#endif
- }
- }
-
-#if 0
- for (size_t i = 0; i < mCodecInfos.size(); ++i) {
- const CodecInfo &info = mCodecInfos.itemAt(i);
-
- AString line = info.mName;
- line.append(" supports ");
- for (size_t j = 0; j < mTypes.size(); ++j) {
- uint32_t value = mTypes.valueAt(j);
-
- if (info.mTypes & (1ul << value)) {
- line.append(mTypes.keyAt(j));
- line.append(" ");
- }
- }
-
- ALOGI("%s", line.c_str());
- }
-#endif
+MediaCodecList::MediaCodecList(MediaCodecListBuilderBase* builder) {
+ mGlobalSettings = new AMessage();
+ mCodecInfos.clear();
+ MediaCodecListWriter writer(this);
+ mInitCheck = builder->buildMediaCodecList(&writer);
}
MediaCodecList::~MediaCodecList() {
@@ -347,531 +185,21 @@
return mInitCheck;
}
-void MediaCodecList::parseXMLFile(const char *path) {
- FILE *file = fopen(path, "r");
-
- if (file == NULL) {
- ALOGW("unable to open media codecs configuration xml file: %s", path);
- mInitCheck = NAME_NOT_FOUND;
- return;
- }
-
- XML_Parser parser = ::XML_ParserCreate(NULL);
- CHECK(parser != NULL);
-
- ::XML_SetUserData(parser, this);
- ::XML_SetElementHandler(
- parser, StartElementHandlerWrapper, EndElementHandlerWrapper);
-
- const int BUFF_SIZE = 512;
- while (mInitCheck == OK) {
- void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
- if (buff == NULL) {
- ALOGE("failed in call to XML_GetBuffer()");
- mInitCheck = UNKNOWN_ERROR;
- break;
- }
-
- int bytes_read = ::fread(buff, 1, BUFF_SIZE, file);
- if (bytes_read < 0) {
- ALOGE("failed in call to read");
- mInitCheck = ERROR_IO;
- break;
- }
-
- XML_Status status = ::XML_ParseBuffer(parser, bytes_read, bytes_read == 0);
- if (status != XML_STATUS_OK) {
- ALOGE("malformed (%s)", ::XML_ErrorString(::XML_GetErrorCode(parser)));
- mInitCheck = ERROR_MALFORMED;
- break;
- }
-
- if (bytes_read == 0) {
- break;
- }
- }
-
- ::XML_ParserFree(parser);
-
- fclose(file);
- file = NULL;
+MediaCodecListWriter::MediaCodecListWriter(MediaCodecList* list) :
+ mList(list) {
}
-// static
-void MediaCodecList::StartElementHandlerWrapper(
- void *me, const char *name, const char **attrs) {
- static_cast<MediaCodecList *>(me)->startElementHandler(name, attrs);
+void MediaCodecListWriter::addGlobalSetting(
+ const char* key, const char* value) {
+ mList->mGlobalSettings->setString(key, value);
}
-// static
-void MediaCodecList::EndElementHandlerWrapper(void *me, const char *name) {
- static_cast<MediaCodecList *>(me)->endElementHandler(name);
-}
-
-status_t MediaCodecList::includeXMLFile(const char **attrs) {
- const char *href = NULL;
- size_t i = 0;
- while (attrs[i] != NULL) {
- if (!strcmp(attrs[i], "href")) {
- if (attrs[i + 1] == NULL) {
- return -EINVAL;
- }
- href = attrs[i + 1];
- ++i;
- } else {
- return -EINVAL;
- }
- ++i;
- }
-
- // For security reasons and for simplicity, file names can only contain
- // [a-zA-Z0-9_.] and must start with media_codecs_ and end with .xml
- for (i = 0; href[i] != '\0'; i++) {
- if (href[i] == '.' || href[i] == '_' ||
- (href[i] >= '0' && href[i] <= '9') ||
- (href[i] >= 'A' && href[i] <= 'Z') ||
- (href[i] >= 'a' && href[i] <= 'z')) {
- continue;
- }
- ALOGE("invalid include file name: %s", href);
- return -EINVAL;
- }
-
- AString filename = href;
- if (!filename.startsWith("media_codecs_") ||
- !filename.endsWith(".xml")) {
- ALOGE("invalid include file name: %s", href);
- return -EINVAL;
- }
- filename.insert(mHrefBase, 0);
-
- parseXMLFile(filename.c_str());
- return mInitCheck;
-}
-
-void MediaCodecList::startElementHandler(
- const char *name, const char **attrs) {
- if (mInitCheck != OK) {
- return;
- }
-
- bool inType = true;
-
- if (!strcmp(name, "Include")) {
- mInitCheck = includeXMLFile(attrs);
- if (mInitCheck == OK) {
- mPastSections.push(mCurrentSection);
- mCurrentSection = SECTION_INCLUDE;
- }
- ++mDepth;
- return;
- }
-
- switch (mCurrentSection) {
- case SECTION_TOPLEVEL:
- {
- if (!strcmp(name, "Decoders")) {
- mCurrentSection = SECTION_DECODERS;
- } else if (!strcmp(name, "Encoders")) {
- mCurrentSection = SECTION_ENCODERS;
- } else if (!strcmp(name, "Settings")) {
- mCurrentSection = SECTION_SETTINGS;
- }
- break;
- }
-
- case SECTION_SETTINGS:
- {
- if (!strcmp(name, "Setting")) {
- mInitCheck = addSettingFromAttributes(attrs);
- }
- break;
- }
-
- case SECTION_DECODERS:
- {
- if (!strcmp(name, "MediaCodec")) {
- mInitCheck =
- addMediaCodecFromAttributes(false /* encoder */, attrs);
-
- mCurrentSection = SECTION_DECODER;
- }
- break;
- }
-
- case SECTION_ENCODERS:
- {
- if (!strcmp(name, "MediaCodec")) {
- mInitCheck =
- addMediaCodecFromAttributes(true /* encoder */, attrs);
-
- mCurrentSection = SECTION_ENCODER;
- }
- break;
- }
-
- case SECTION_DECODER:
- case SECTION_ENCODER:
- {
- if (!strcmp(name, "Quirk")) {
- mInitCheck = addQuirk(attrs);
- } else if (!strcmp(name, "Type")) {
- mInitCheck = addTypeFromAttributes(attrs);
- mCurrentSection =
- (mCurrentSection == SECTION_DECODER
- ? SECTION_DECODER_TYPE : SECTION_ENCODER_TYPE);
- }
- }
- inType = false;
- // fall through
-
- case SECTION_DECODER_TYPE:
- case SECTION_ENCODER_TYPE:
- {
- // ignore limits and features specified outside of type
- bool outside = !inType && !mCurrentInfo->mHasSoleMime;
- if (outside && (!strcmp(name, "Limit") || !strcmp(name, "Feature"))) {
- ALOGW("ignoring %s specified outside of a Type", name);
- } else if (!strcmp(name, "Limit")) {
- mInitCheck = addLimit(attrs);
- } else if (!strcmp(name, "Feature")) {
- mInitCheck = addFeature(attrs);
- }
- break;
- }
-
- default:
- break;
- }
-
- ++mDepth;
-}
-
-void MediaCodecList::endElementHandler(const char *name) {
- if (mInitCheck != OK) {
- return;
- }
-
- switch (mCurrentSection) {
- case SECTION_SETTINGS:
- {
- if (!strcmp(name, "Settings")) {
- mCurrentSection = SECTION_TOPLEVEL;
- }
- break;
- }
-
- case SECTION_DECODERS:
- {
- if (!strcmp(name, "Decoders")) {
- mCurrentSection = SECTION_TOPLEVEL;
- }
- break;
- }
-
- case SECTION_ENCODERS:
- {
- if (!strcmp(name, "Encoders")) {
- mCurrentSection = SECTION_TOPLEVEL;
- }
- break;
- }
-
- case SECTION_DECODER_TYPE:
- case SECTION_ENCODER_TYPE:
- {
- if (!strcmp(name, "Type")) {
- mCurrentSection =
- (mCurrentSection == SECTION_DECODER_TYPE
- ? SECTION_DECODER : SECTION_ENCODER);
-
- mCurrentInfo->complete();
- }
- break;
- }
-
- case SECTION_DECODER:
- {
- if (!strcmp(name, "MediaCodec")) {
- mCurrentSection = SECTION_DECODERS;
- mCurrentInfo->complete();
- mCurrentInfo = NULL;
- }
- break;
- }
-
- case SECTION_ENCODER:
- {
- if (!strcmp(name, "MediaCodec")) {
- mCurrentSection = SECTION_ENCODERS;
- mCurrentInfo->complete();;
- mCurrentInfo = NULL;
- }
- break;
- }
-
- case SECTION_INCLUDE:
- {
- if (!strcmp(name, "Include") && mPastSections.size() > 0) {
- mCurrentSection = mPastSections.top();
- mPastSections.pop();
- }
- break;
- }
-
- default:
- break;
- }
-
- --mDepth;
-}
-
-status_t MediaCodecList::addSettingFromAttributes(const char **attrs) {
- const char *name = NULL;
- const char *value = NULL;
- const char *update = NULL;
-
- size_t i = 0;
- while (attrs[i] != NULL) {
- if (!strcmp(attrs[i], "name")) {
- if (attrs[i + 1] == NULL) {
- return -EINVAL;
- }
- name = attrs[i + 1];
- ++i;
- } else if (!strcmp(attrs[i], "value")) {
- if (attrs[i + 1] == NULL) {
- return -EINVAL;
- }
- value = attrs[i + 1];
- ++i;
- } else if (!strcmp(attrs[i], "update")) {
- if (attrs[i + 1] == NULL) {
- return -EINVAL;
- }
- update = attrs[i + 1];
- ++i;
- } else {
- return -EINVAL;
- }
-
- ++i;
- }
-
- if (name == NULL || value == NULL) {
- return -EINVAL;
- }
-
- mUpdate = (update != NULL) && parseBoolean(update);
- if (mUpdate != mGlobalSettings->contains(name)) {
- return -EINVAL;
- }
-
- mGlobalSettings->setString(name, value);
- return OK;
-}
-
-void MediaCodecList::setCurrentCodecInfo(bool encoder, const char *name, const char *type) {
- for (size_t i = 0; i < mCodecInfos.size(); ++i) {
- if (AString(name) == mCodecInfos[i]->getCodecName()) {
- if (mCodecInfos[i]->getCapabilitiesFor(type) == NULL) {
- ALOGW("Overrides with an unexpected mime %s", type);
- // Create a new MediaCodecInfo (but don't add it to mCodecInfos) to hold the
- // overrides we don't want.
- mCurrentInfo = new MediaCodecInfo(name, encoder, type);
- } else {
- mCurrentInfo = mCodecInfos.editItemAt(i);
- mCurrentInfo->updateMime(type); // to set the current cap
- }
- return;
- }
- }
- mCurrentInfo = new MediaCodecInfo(name, encoder, type);
- // The next step involves trying to load the codec, which may
- // fail. Only list the codec if this succeeds.
- // However, keep mCurrentInfo object around until parsing
- // of full codec info is completed.
- if (initializeCapabilities(type) == OK) {
- mCodecInfos.push_back(mCurrentInfo);
- }
-}
-
-status_t MediaCodecList::addMediaCodecFromAttributes(
- bool encoder, const char **attrs) {
- const char *name = NULL;
- const char *type = NULL;
- const char *update = NULL;
-
- size_t i = 0;
- while (attrs[i] != NULL) {
- if (!strcmp(attrs[i], "name")) {
- if (attrs[i + 1] == NULL) {
- return -EINVAL;
- }
- name = attrs[i + 1];
- ++i;
- } else if (!strcmp(attrs[i], "type")) {
- if (attrs[i + 1] == NULL) {
- return -EINVAL;
- }
- type = attrs[i + 1];
- ++i;
- } else if (!strcmp(attrs[i], "update")) {
- if (attrs[i + 1] == NULL) {
- return -EINVAL;
- }
- update = attrs[i + 1];
- ++i;
- } else {
- return -EINVAL;
- }
-
- ++i;
- }
-
- if (name == NULL) {
- return -EINVAL;
- }
-
- mUpdate = (update != NULL) && parseBoolean(update);
- ssize_t index = -1;
- for (size_t i = 0; i < mCodecInfos.size(); ++i) {
- if (AString(name) == mCodecInfos[i]->getCodecName()) {
- index = i;
- }
- }
- if (mUpdate != (index >= 0)) {
- return -EINVAL;
- }
-
- if (index >= 0) {
- // existing codec
- mCurrentInfo = mCodecInfos.editItemAt(index);
- if (type != NULL) {
- // existing type
- if (mCodecInfos[index]->getCapabilitiesFor(type) == NULL) {
- return -EINVAL;
- }
- mCurrentInfo->updateMime(type);
- }
- } else {
- // new codec
- mCurrentInfo = new MediaCodecInfo(name, encoder, type);
- // The next step involves trying to load the codec, which may
- // fail. Only list the codec if this succeeds.
- // However, keep mCurrentInfo object around until parsing
- // of full codec info is completed.
- if (initializeCapabilities(type) == OK) {
- mCodecInfos.push_back(mCurrentInfo);
- }
- }
-
- return OK;
-}
-
-status_t MediaCodecList::initializeCapabilities(const char *type) {
- if (type == NULL) {
- return OK;
- }
-
- ALOGV("initializeCapabilities %s:%s",
- mCurrentInfo->mName.c_str(), type);
-
- sp<MediaCodecInfo::Capabilities> caps;
- status_t err = MediaCodec::QueryCapabilities(
- mCurrentInfo->mName,
- type,
- mCurrentInfo->mIsEncoder,
- &caps);
- if (err != OK) {
- return err;
- } else if (caps == NULL) {
- ALOGE("MediaCodec::QueryCapabilities returned OK but no capabilities for '%s':'%s':'%s'",
- mCurrentInfo->mName.c_str(), type,
- mCurrentInfo->mIsEncoder ? "encoder" : "decoder");
- return UNKNOWN_ERROR;
- }
-
- return mCurrentInfo->initializeCapabilities(caps);
-}
-
-status_t MediaCodecList::addQuirk(const char **attrs) {
- const char *name = NULL;
-
- size_t i = 0;
- while (attrs[i] != NULL) {
- if (!strcmp(attrs[i], "name")) {
- if (attrs[i + 1] == NULL) {
- return -EINVAL;
- }
- name = attrs[i + 1];
- ++i;
- } else {
- return -EINVAL;
- }
-
- ++i;
- }
-
- if (name == NULL) {
- return -EINVAL;
- }
-
- mCurrentInfo->addQuirk(name);
- return OK;
-}
-
-status_t MediaCodecList::addTypeFromAttributes(const char **attrs) {
- const char *name = NULL;
- const char *update = NULL;
-
- size_t i = 0;
- while (attrs[i] != NULL) {
- if (!strcmp(attrs[i], "name")) {
- if (attrs[i + 1] == NULL) {
- return -EINVAL;
- }
- name = attrs[i + 1];
- ++i;
- } else if (!strcmp(attrs[i], "update")) {
- if (attrs[i + 1] == NULL) {
- return -EINVAL;
- }
- update = attrs[i + 1];
- ++i;
- } else {
- return -EINVAL;
- }
-
- ++i;
- }
-
- if (name == NULL) {
- return -EINVAL;
- }
-
- bool isExistingType = (mCurrentInfo->getCapabilitiesFor(name) != NULL);
- if (mUpdate != isExistingType) {
- return -EINVAL;
- }
-
- status_t ret;
- if (mUpdate) {
- ret = mCurrentInfo->updateMime(name);
- } else {
- ret = mCurrentInfo->addMime(name);
- }
-
- if (ret != OK) {
- return ret;
- }
-
- // The next step involves trying to load the codec, which may
- // fail. Handle this gracefully (by not reporting such mime).
- if (!mUpdate && initializeCapabilities(name) != OK) {
- mCurrentInfo->removeMime(name);
- }
- return OK;
+std::unique_ptr<MediaCodecInfoWriter>
+ MediaCodecListWriter::addMediaCodecInfo() {
+ sp<MediaCodecInfo> info = new MediaCodecInfo();
+ mList->mCodecInfos.push_back(info);
+ return std::unique_ptr<MediaCodecInfoWriter>(
+ new MediaCodecInfoWriter(info.get()));
}
// legacy method for non-advanced codecs
@@ -882,15 +210,15 @@
"feature-tunneled-playback",
};
- size_t numCodecs = mCodecInfos.size();
- for (; startIndex < numCodecs; ++startIndex) {
- const MediaCodecInfo &info = *mCodecInfos.itemAt(startIndex).get();
+ size_t numCodecInfos = mCodecInfos.size();
+ for (; startIndex < numCodecInfos; ++startIndex) {
+ const MediaCodecInfo &info = *mCodecInfos[startIndex];
if (info.isEncoder() != encoder) {
continue;
}
sp<MediaCodecInfo::Capabilities> capabilities = info.getCapabilitiesFor(type);
- if (capabilities == NULL) {
+ if (capabilities == nullptr) {
continue;
}
const sp<AMessage> &details = capabilities->getDetails();
@@ -913,223 +241,9 @@
return -ENOENT;
}
-static status_t limitFoundMissingAttr(const AString &name, const char *attr, bool found = true) {
- ALOGE("limit '%s' with %s'%s' attribute", name.c_str(),
- (found ? "" : "no "), attr);
- return -EINVAL;
-}
-
-static status_t limitError(const AString &name, const char *msg) {
- ALOGE("limit '%s' %s", name.c_str(), msg);
- return -EINVAL;
-}
-
-static status_t limitInvalidAttr(const AString &name, const char *attr, const AString &value) {
- ALOGE("limit '%s' with invalid '%s' attribute (%s)", name.c_str(),
- attr, value.c_str());
- return -EINVAL;
-}
-
-status_t MediaCodecList::addLimit(const char **attrs) {
- sp<AMessage> msg = new AMessage();
-
- size_t i = 0;
- while (attrs[i] != NULL) {
- if (attrs[i + 1] == NULL) {
- return -EINVAL;
- }
-
- // attributes with values
- if (!strcmp(attrs[i], "name")
- || !strcmp(attrs[i], "default")
- || !strcmp(attrs[i], "in")
- || !strcmp(attrs[i], "max")
- || !strcmp(attrs[i], "min")
- || !strcmp(attrs[i], "range")
- || !strcmp(attrs[i], "ranges")
- || !strcmp(attrs[i], "scale")
- || !strcmp(attrs[i], "value")) {
- msg->setString(attrs[i], attrs[i + 1]);
- ++i;
- } else {
- return -EINVAL;
- }
- ++i;
- }
-
- AString name;
- if (!msg->findString("name", &name)) {
- ALOGE("limit with no 'name' attribute");
- return -EINVAL;
- }
-
- // size, blocks, bitrate, frame-rate, blocks-per-second, aspect-ratio,
- // measured-frame-rate, measured-blocks-per-second: range
- // quality: range + default + [scale]
- // complexity: range + default
- bool found;
-
- if (name == "aspect-ratio" || name == "bitrate" || name == "block-count"
- || name == "blocks-per-second" || name == "complexity"
- || name == "frame-rate" || name == "quality" || name == "size"
- || name == "measured-blocks-per-second" || name.startsWith("measured-frame-rate-")) {
- AString min, max;
- if (msg->findString("min", &min) && msg->findString("max", &max)) {
- min.append("-");
- min.append(max);
- if (msg->contains("range") || msg->contains("value")) {
- return limitError(name, "has 'min' and 'max' as well as 'range' or "
- "'value' attributes");
- }
- msg->setString("range", min);
- } else if (msg->contains("min") || msg->contains("max")) {
- return limitError(name, "has only 'min' or 'max' attribute");
- } else if (msg->findString("value", &max)) {
- min = max;
- min.append("-");
- min.append(max);
- if (msg->contains("range")) {
- return limitError(name, "has both 'range' and 'value' attributes");
- }
- msg->setString("range", min);
- }
-
- AString range, scale = "linear", def, in_;
- if (!msg->findString("range", &range)) {
- return limitError(name, "with no 'range', 'value' or 'min'/'max' attributes");
- }
-
- if ((name == "quality" || name == "complexity") ^
- (found = msg->findString("default", &def))) {
- return limitFoundMissingAttr(name, "default", found);
- }
- if (name != "quality" && msg->findString("scale", &scale)) {
- return limitFoundMissingAttr(name, "scale");
- }
- if ((name == "aspect-ratio") ^ (found = msg->findString("in", &in_))) {
- return limitFoundMissingAttr(name, "in", found);
- }
-
- if (name == "aspect-ratio") {
- if (!(in_ == "pixels") && !(in_ == "blocks")) {
- return limitInvalidAttr(name, "in", in_);
- }
- in_.erase(5, 1); // (pixel|block)-aspect-ratio
- in_.append("-");
- in_.append(name);
- name = in_;
- }
- if (name == "quality") {
- mCurrentInfo->addDetail("quality-scale", scale);
- }
- if (name == "quality" || name == "complexity") {
- AString tag = name;
- tag.append("-default");
- mCurrentInfo->addDetail(tag, def);
- }
- AString tag = name;
- tag.append("-range");
- mCurrentInfo->addDetail(tag, range);
- } else {
- AString max, value, ranges;
- if (msg->contains("default")) {
- return limitFoundMissingAttr(name, "default");
- } else if (msg->contains("in")) {
- return limitFoundMissingAttr(name, "in");
- } else if ((name == "channel-count" || name == "concurrent-instances") ^
- (found = msg->findString("max", &max))) {
- return limitFoundMissingAttr(name, "max", found);
- } else if (msg->contains("min")) {
- return limitFoundMissingAttr(name, "min");
- } else if (msg->contains("range")) {
- return limitFoundMissingAttr(name, "range");
- } else if ((name == "sample-rate") ^
- (found = msg->findString("ranges", &ranges))) {
- return limitFoundMissingAttr(name, "ranges", found);
- } else if (msg->contains("scale")) {
- return limitFoundMissingAttr(name, "scale");
- } else if ((name == "alignment" || name == "block-size") ^
- (found = msg->findString("value", &value))) {
- return limitFoundMissingAttr(name, "value", found);
- }
-
- if (max.size()) {
- AString tag = "max-";
- tag.append(name);
- mCurrentInfo->addDetail(tag, max);
- } else if (value.size()) {
- mCurrentInfo->addDetail(name, value);
- } else if (ranges.size()) {
- AString tag = name;
- tag.append("-ranges");
- mCurrentInfo->addDetail(tag, ranges);
- } else {
- ALOGW("Ignoring unrecognized limit '%s'", name.c_str());
- }
- }
- return OK;
-}
-
-status_t MediaCodecList::addFeature(const char **attrs) {
- size_t i = 0;
- const char *name = NULL;
- int32_t optional = -1;
- int32_t required = -1;
- const char *value = NULL;
-
- while (attrs[i] != NULL) {
- if (attrs[i + 1] == NULL) {
- return -EINVAL;
- }
-
- // attributes with values
- if (!strcmp(attrs[i], "name")) {
- name = attrs[i + 1];
- ++i;
- } else if (!strcmp(attrs[i], "optional") || !strcmp(attrs[i], "required")) {
- int value = (int)parseBoolean(attrs[i + 1]);
- if (!strcmp(attrs[i], "optional")) {
- optional = value;
- } else {
- required = value;
- }
- ++i;
- } else if (!strcmp(attrs[i], "value")) {
- value = attrs[i + 1];
- ++i;
- } else {
- return -EINVAL;
- }
- ++i;
- }
- if (name == NULL) {
- ALOGE("feature with no 'name' attribute");
- return -EINVAL;
- }
-
- if (optional == required && optional != -1) {
- ALOGE("feature '%s' is both/neither optional and required", name);
- return -EINVAL;
- }
-
- if ((optional != -1 || required != -1) && (value != NULL)) {
- ALOGE("feature '%s' has both a value and optional/required attribute", name);
- return -EINVAL;
- }
-
- if (value != NULL) {
- mCurrentInfo->addFeature(name, value);
- } else {
- mCurrentInfo->addFeature(name, (required == 1) || (optional == 0));
- }
- return OK;
-}
-
ssize_t MediaCodecList::findCodecByName(const char *name) const {
for (size_t i = 0; i < mCodecInfos.size(); ++i) {
- const MediaCodecInfo &info = *mCodecInfos.itemAt(i).get();
-
- if (info.mName == name) {
+ if (strcmp(mCodecInfos[i]->getCodecName(), name) == 0) {
return i;
}
}
@@ -1167,11 +281,15 @@
//static
void MediaCodecList::findMatchingCodecs(
- const char *mime, bool encoder, uint32_t flags, Vector<AString> *matches) {
+ const char *mime, bool encoder, uint32_t flags,
+ Vector<AString> *matches, Vector<AString> *owners) {
matches->clear();
+ if (owners != nullptr) {
+ owners->clear();
+ }
const sp<IMediaCodecList> list = getInstance();
- if (list == NULL) {
+ if (list == nullptr) {
return;
}
@@ -1187,45 +305,27 @@
index = matchIndex + 1;
const sp<MediaCodecInfo> info = list->getCodecInfo(matchIndex);
- CHECK(info != NULL);
+ CHECK(info != nullptr);
AString componentName = info->getCodecName();
if ((flags & kHardwareCodecsOnly) && isSoftwareCodec(componentName)) {
ALOGV("skipping SW codec '%s'", componentName.c_str());
} else {
matches->push(componentName);
+ if (owners != nullptr) {
+ owners->push(AString(info->getOwnerName()));
+ }
ALOGV("matching '%s'", componentName.c_str());
}
}
- if (flags & kPreferSoftwareCodecs || property_get_bool("debug.stagefright.swcodec", false)) {
+ if (flags & kPreferSoftwareCodecs ||
+ property_get_bool("debug.stagefright.swcodec", false)) {
matches->sort(compareSoftwareCodecsFirst);
}
}
-// static
-uint32_t MediaCodecList::getQuirksFor(const char *componentName) {
- const sp<IMediaCodecList> list = getInstance();
- if (list == NULL) {
- return 0;
- }
-
- ssize_t ix = list->findCodecByName(componentName);
- if (ix < 0) {
- return 0;
- }
-
- const sp<MediaCodecInfo> info = list->getCodecInfo(ix);
-
- uint32_t quirks = 0;
- if (info->hasQuirk("requires-allocate-on-input-ports")) {
- quirks |= ACodec::kRequiresAllocateBufferOnInputPorts;
- }
- if (info->hasQuirk("requires-allocate-on-output-ports")) {
- quirks |= ACodec::kRequiresAllocateBufferOnOutputPorts;
- }
-
- return quirks;
+MediaCodecListBuilderBase::~MediaCodecListBuilderBase() {
}
} // namespace android
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index 095fc6a..6920e51 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -33,8 +33,6 @@
namespace android {
-const char *kProfilingResults = "/data/misc/media/media_codecs_profiling_results.xml";
-
AString getProfilingVersionString() {
char val[PROPERTY_VALUE_MAX];
if (property_get("ro.build.display.id", val, NULL) && (strlen(val) > 0)) {
@@ -205,24 +203,24 @@
return true;
}
-void profileCodecs(const Vector<sp<MediaCodecInfo>> &infos) {
+void profileCodecs(const std::vector<sp<MediaCodecInfo>> &infos,
+ const char* profilingResults) {
CodecSettings global_results;
KeyedVector<AString, CodecSettings> encoder_results;
KeyedVector<AString, CodecSettings> decoder_results;
profileCodecs(infos, &global_results, &encoder_results, &decoder_results);
- exportResultsToXML(kProfilingResults, global_results, encoder_results, decoder_results);
+ exportResultsToXML(profilingResults, global_results, encoder_results, decoder_results);
}
void profileCodecs(
- const Vector<sp<MediaCodecInfo>> &infos,
+ const std::vector<sp<MediaCodecInfo>> &infos,
CodecSettings *global_results,
KeyedVector<AString, CodecSettings> *encoder_results,
KeyedVector<AString, CodecSettings> *decoder_results,
bool forceToMeasure) {
KeyedVector<AString, sp<MediaCodecInfo::Capabilities>> codecsNeedMeasure;
AString supportMultipleSecureCodecs = "true";
- for (size_t i = 0; i < infos.size(); ++i) {
- const sp<MediaCodecInfo> info = infos[i];
+ for (const auto& info : infos) {
AString name = info->getCodecName();
if (name.startsWith("OMX.google.") ||
// TODO: reenable below codecs once fixed
diff --git a/media/libstagefright/MediaCodecListOverrides.h b/media/libstagefright/MediaCodecListOverrides.h
index d4bb225..4f8c2f5 100644
--- a/media/libstagefright/MediaCodecListOverrides.h
+++ b/media/libstagefright/MediaCodecListOverrides.h
@@ -23,12 +23,10 @@
#include <utils/StrongPointer.h>
#include <utils/KeyedVector.h>
+#include <vector>
namespace android {
-extern const char *kProfilingVersionString;
-extern const char *kProfilingResults;
-
struct MediaCodecInfo;
AString getProfilingVersionString();
@@ -36,11 +34,12 @@
bool splitString(const AString &s, const AString &delimiter, AString *s1, AString *s2);
// profile codecs and save the result to xml file named kProfilingResults.
-void profileCodecs(const Vector<sp<MediaCodecInfo>> &infos);
+void profileCodecs(const std::vector<sp<MediaCodecInfo>> &infos,
+ const char* profilingResults);
// profile codecs and save the result to global_results, encoder_results and decoder_results.
void profileCodecs(
- const Vector<sp<MediaCodecInfo>> &infos,
+ const std::vector<sp<MediaCodecInfo>> &infos,
CodecSettings *global_results,
KeyedVector<AString, CodecSettings> *encoder_results,
KeyedVector<AString, CodecSettings> *decoder_results,
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 51f1ba3..640cb82 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-//#define LOG_NDEBUG 0
+#define LOG_NDEBUG 0
#define LOG_TAG "NuMediaExtractor"
#include <utils/Log.h>
@@ -35,7 +35,6 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
-#include <android/media/ICas.h>
namespace android {
@@ -83,8 +82,8 @@
return ERROR_UNSUPPORTED;
}
- if (mCas != NULL) {
- mImpl->setMediaCas(mCas);
+ if (!mCasToken.empty()) {
+ mImpl->setMediaCas(mCasToken);
}
status_t err = updateDurationAndBitrate();
@@ -119,8 +118,8 @@
return ERROR_UNSUPPORTED;
}
- if (mCas != NULL) {
- mImpl->setMediaCas(mCas);
+ if (!mCasToken.empty()) {
+ mImpl->setMediaCas(mCasToken);
}
err = updateDurationAndBitrate();
@@ -149,8 +148,8 @@
return ERROR_UNSUPPORTED;
}
- if (mCas != NULL) {
- mImpl->setMediaCas(mCas);
+ if (!mCasToken.empty()) {
+ mImpl->setMediaCas(mCasToken);
}
err = updateDurationAndBitrate();
@@ -161,24 +160,36 @@
return err;
}
-status_t NuMediaExtractor::setMediaCas(const sp<ICas> &cas) {
- ALOGV("setMediaCas: cas=%p", cas.get());
+static String8 arrayToString(const std::vector<uint8_t> &array) {
+ String8 result;
+ for (size_t i = 0; i < array.size(); i++) {
+ result.appendFormat("%02x ", array[i]);
+ }
+ if (result.isEmpty()) {
+ result.append("(null)");
+ }
+ return result;
+}
+
+status_t NuMediaExtractor::setMediaCas(const HInterfaceToken &casToken) {
+ ALOGV("setMediaCas: casToken={%s}", arrayToString(casToken).c_str());
Mutex::Autolock autoLock(mLock);
- if (cas == NULL) {
+ if (casToken.empty()) {
return BAD_VALUE;
}
+ mCasToken = casToken;
+
if (mImpl != NULL) {
- mImpl->setMediaCas(cas);
+ mImpl->setMediaCas(casToken);
status_t err = updateDurationAndBitrate();
if (err != OK) {
return err;
}
}
- mCas = cas;
return OK;
}
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 5f9aa01..5f50e46 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -38,7 +38,7 @@
}
status_t OMXClient::connect() {
- return connect(nullptr);
+ return connect("default", nullptr);
}
status_t OMXClient::connect(bool* trebleFlag) {
@@ -54,6 +54,19 @@
return connectLegacy();
}
+status_t OMXClient::connect(const char* name, bool* trebleFlag) {
+ if (property_get_bool("persist.media.treble_omx", true)) {
+ if (trebleFlag != nullptr) {
+ *trebleFlag = true;
+ }
+ return connectTreble(name);
+ }
+ if (trebleFlag != nullptr) {
+ *trebleFlag = false;
+ }
+ return connectLegacy();
+}
+
status_t OMXClient::connectLegacy() {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> codecbinder = sm->getService(String16("media.codec"));
@@ -73,9 +86,12 @@
return OK;
}
-status_t OMXClient::connectTreble() {
+status_t OMXClient::connectTreble(const char* name) {
using namespace ::android::hardware::media::omx::V1_0;
- sp<IOmx> tOmx = IOmx::getService("default");
+ if (name == nullptr) {
+ name = "default";
+ }
+ sp<IOmx> tOmx = IOmx::getService(name);
if (tOmx.get() == nullptr) {
ALOGE("Cannot obtain Treble IOmx.");
return NO_INIT;
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
new file mode 100644
index 0000000..8717a79
--- /dev/null
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2017 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 "OmxInfoBuilder"
+
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
+#include <utils/Log.h>
+#include <cutils/properties.h>
+
+#include <binder/IServiceManager.h>
+#include <media/IMediaCodecService.h>
+#include <media/stagefright/OmxInfoBuilder.h>
+#include <media/stagefright/ACodec.h>
+
+#include <android/hardware/media/omx/1.0/IOmxStore.h>
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <media/stagefright/omx/OMXUtils.h>
+
+#include <media/IOMXStore.h>
+#include <media/IOMX.h>
+#include <media/MediaDefs.h>
+#include <media/omx/1.0/WOmx.h>
+
+#include <media/openmax/OMX_Index.h>
+#include <media/openmax/OMX_IndexExt.h>
+#include <media/openmax/OMX_Audio.h>
+#include <media/openmax/OMX_AudioExt.h>
+#include <media/openmax/OMX_Video.h>
+#include <media/openmax/OMX_VideoExt.h>
+
+namespace android {
+
+namespace /* unnamed */ {
+
+status_t queryCapabilities(
+ const IOMXStore::NodeInfo& node, const char* mime, bool isEncoder,
+ MediaCodecInfo::CapabilitiesWriter* caps) {
+ sp<ACodec> codec = new ACodec();
+ status_t err = codec->queryCapabilities(
+ node.owner.c_str(), node.name.c_str(), mime, isEncoder, caps);
+ if (err != OK) {
+ return err;
+ }
+ for (const auto& attribute : node.attributes) {
+ // All features have an int32 value except
+ // "feature-bitrate-modes", which has a string value.
+ if ((attribute.key.compare(0, 8, "feature-") == 0) &&
+ (attribute.key.compare(8, 15, "bitrate-modes")
+ != 0)) {
+ // If this attribute.key is a feature that is not a bitrate
+ // control, add an int32 value.
+ caps->addDetail(
+ attribute.key.c_str(),
+ attribute.value == "1" ? 1 : 0);
+ } else {
+ // Non-feature attributes
+ caps->addDetail(
+ attribute.key.c_str(), attribute.value.c_str());
+ }
+ }
+ return OK;
+}
+
+} // unnamed namespace
+
+OmxInfoBuilder::OmxInfoBuilder() {
+}
+
+status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
+ bool treble;
+ sp<IOMX> omx;
+ std::vector<IOMXStore::RoleInfo> roles;
+
+ treble = property_get_bool("persist.media.treble_omx", true);
+ if (treble) {
+ using namespace ::android::hardware::media::omx::V1_0;
+ using ::android::hardware::hidl_vec;
+ using ::android::hardware::hidl_string;
+
+ // Obtain IOmxStore
+ sp<IOmxStore> omxStore = IOmxStore::getService();
+ if (omxStore == nullptr) {
+ ALOGE("Cannot connect to an IOmxStore instance.");
+ return NO_INIT;
+ }
+
+ // List service attributes (global settings)
+ Status status;
+ hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
+ auto transStatus = omxStore->listServiceAttributes(
+ [&status, &serviceAttributes]
+ (Status inStatus, const hidl_vec<IOmxStore::ServiceAttribute>&
+ inAttributes) {
+ status = inStatus;
+ serviceAttributes = inAttributes;
+ });
+ if (!transStatus.isOk()) {
+ ALOGE("Fail to obtain global settings from IOmxStore.");
+ return NO_INIT;
+ }
+ if (status != Status::OK) {
+ ALOGE("IOmxStore reports parsing error.");
+ return NO_INIT;
+ }
+ for (const auto& p : serviceAttributes) {
+ writer->addGlobalSetting(
+ p.key.c_str(), p.value.c_str());
+ }
+
+ // List roles and convert to IOMXStore's format
+ transStatus = omxStore->listRoles(
+ [&roles]
+ (const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
+ roles.reserve(inRoleList.size());
+ for (const auto& inRole : inRoleList) {
+ IOMXStore::RoleInfo role;
+ role.role = inRole.role;
+ role.type = inRole.type;
+ role.isEncoder = inRole.isEncoder;
+ role.preferPlatformNodes = inRole.preferPlatformNodes;
+ std::vector<IOMXStore::NodeInfo>& nodes =
+ role.nodes;
+ nodes.reserve(inRole.nodes.size());
+ for (const auto& inNode : inRole.nodes) {
+ IOMXStore::NodeInfo node;
+ node.name = inNode.name;
+ node.owner = inNode.owner;
+ std::vector<IOMXStore::Attribute>& attributes =
+ node.attributes;
+ attributes.reserve(inNode.attributes.size());
+ for (const auto& inAttr : inNode.attributes) {
+ IOMXStore::Attribute attr;
+ attr.key = inAttr.key;
+ attr.value = inAttr.value;
+ attributes.push_back(std::move(attr));
+ }
+ nodes.push_back(std::move(node));
+ }
+ roles.push_back(std::move(role));
+ }
+ });
+ if (!transStatus.isOk()) {
+ ALOGE("Fail to obtain codec roles from IOmxStore.");
+ return NO_INIT;
+ }
+ } else {
+ // Obtain IOMXStore
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm == nullptr) {
+ ALOGE("Cannot obtain the default service manager.");
+ return NO_INIT;
+ }
+ sp<IBinder> codecBinder = sm->getService(String16("media.codec"));
+ if (codecBinder == nullptr) {
+ ALOGE("Cannot obtain the media codec service.");
+ return NO_INIT;
+ }
+ sp<IMediaCodecService> codecService =
+ interface_cast<IMediaCodecService>(codecBinder);
+ if (codecService == nullptr) {
+ ALOGE("Wrong type of media codec service obtained.");
+ return NO_INIT;
+ }
+ omx = codecService->getOMX();
+ if (omx == nullptr) {
+ ALOGE("Cannot connect to an IOMX instance.");
+ }
+ sp<IOMXStore> omxStore = codecService->getOMXStore();
+ if (omxStore == nullptr) {
+ ALOGE("Cannot connect to an IOMXStore instance.");
+ return NO_INIT;
+ }
+
+ // List service attributes (global settings)
+ std::vector<IOMXStore::Attribute> serviceAttributes;
+ status_t status = omxStore->listServiceAttributes(&serviceAttributes);
+ if (status != OK) {
+ ALOGE("Fail to obtain global settings from IOMXStore.");
+ return NO_INIT;
+ }
+ for (const auto& p : serviceAttributes) {
+ writer->addGlobalSetting(
+ p.key.c_str(), p.value.c_str());
+ }
+
+ // List roles
+ status = omxStore->listRoles(&roles);
+ if (status != OK) {
+ ALOGE("Fail to obtain codec roles from IOMXStore.");
+ return NO_INIT;
+ }
+ }
+
+ // Convert roles to lists of codecs
+
+ // codec name -> index into swCodecs
+ std::map<std::string, std::unique_ptr<MediaCodecInfoWriter> >
+ swCodecName2Info;
+ // codec name -> index into hwCodecs
+ std::map<std::string, std::unique_ptr<MediaCodecInfoWriter> >
+ hwCodecName2Info;
+ // owner name -> MediaCodecInfo
+ // This map will be used to obtain the correct IOmx service(s) needed for
+ // creating IOmxNode instances and querying capabilities.
+ std::map<std::string, std::vector<sp<MediaCodecInfo> > >
+ owner2CodecInfo;
+
+ for (const auto& role : roles) {
+ const auto& typeName = role.type;
+ bool isEncoder = role.isEncoder;
+ bool preferPlatformNodes = role.preferPlatformNodes;
+ // If preferPlatformNodes is true, hardware nodes must be added after
+ // platform (software) nodes. hwCodecs is used to hold hardware nodes
+ // that need to be added after software nodes for the same role.
+ std::vector<const IOMXStore::NodeInfo*> hwCodecs;
+ for (const auto& node : role.nodes) {
+ const auto& nodeName = node.name;
+ bool isSoftware = nodeName.compare(0, 10, "OMX.google") == 0;
+ MediaCodecInfoWriter* info;
+ if (isSoftware) {
+ auto c2i = swCodecName2Info.find(nodeName);
+ if (c2i == swCodecName2Info.end()) {
+ // Create a new MediaCodecInfo for a new node.
+ c2i = swCodecName2Info.insert(std::make_pair(
+ nodeName, writer->addMediaCodecInfo())).first;
+ info = c2i->second.get();
+ info->setName(nodeName.c_str());
+ info->setOwner(node.owner.c_str());
+ info->setEncoder(isEncoder);
+ } else {
+ // The node has been seen before. Simply retrieve the
+ // existing MediaCodecInfoWriter.
+ info = c2i->second.get();
+ }
+ } else {
+ auto c2i = hwCodecName2Info.find(nodeName);
+ if (c2i == hwCodecName2Info.end()) {
+ // Create a new MediaCodecInfo for a new node.
+ if (!preferPlatformNodes) {
+ c2i = hwCodecName2Info.insert(std::make_pair(
+ nodeName, writer->addMediaCodecInfo())).first;
+ info = c2i->second.get();
+ info->setName(nodeName.c_str());
+ info->setOwner(node.owner.c_str());
+ info->setEncoder(isEncoder);
+ } else {
+ // If preferPlatformNodes is true, this node must be
+ // added after all software nodes.
+ hwCodecs.push_back(&node);
+ continue;
+ }
+ } else {
+ // The node has been seen before. Simply retrieve the
+ // existing MediaCodecInfoWriter.
+ info = c2i->second.get();
+ }
+ }
+ std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
+ info->addMime(typeName.c_str());
+ if (queryCapabilities(
+ node, typeName.c_str(), isEncoder, caps.get()) != OK) {
+ ALOGW("Fail to add mime %s to codec %s",
+ typeName.c_str(), nodeName.c_str());
+ info->removeMime(typeName.c_str());
+ }
+ }
+
+ // If preferPlatformNodes is true, hardware nodes will not have been
+ // added in the loop above, but rather saved in hwCodecs. They are
+ // going to be added here.
+ if (preferPlatformNodes) {
+ for (const auto& node : hwCodecs) {
+ MediaCodecInfoWriter* info;
+ const auto& nodeName = node->name;
+ auto c2i = hwCodecName2Info.find(nodeName);
+ if (c2i == hwCodecName2Info.end()) {
+ // Create a new MediaCodecInfo for a new node.
+ c2i = hwCodecName2Info.insert(std::make_pair(
+ nodeName, writer->addMediaCodecInfo())).first;
+ info = c2i->second.get();
+ info->setName(nodeName.c_str());
+ info->setOwner(node->owner.c_str());
+ info->setEncoder(isEncoder);
+ } else {
+ // The node has been seen before. Simply retrieve the
+ // existing MediaCodecInfoWriter.
+ info = c2i->second.get();
+ }
+ std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
+ info->addMime(typeName.c_str());
+ if (queryCapabilities(
+ *node, typeName.c_str(), isEncoder, caps.get()) != OK) {
+ ALOGW("Fail to add mime %s to codec %s "
+ "after software codecs",
+ typeName.c_str(), nodeName.c_str());
+ info->removeMime(typeName.c_str());
+ }
+ }
+ }
+ }
+ return OK;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index f0c27ac..4ff2bfe 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -85,7 +85,8 @@
status_t status;
if (fd < 0) {
// couldn't open it locally, maybe the media server can?
- status = mRetriever->setDataSource(NULL /* httpService */, path);
+ sp<IMediaHTTPService> nullService;
+ status = mRetriever->setDataSource(nullService, path);
} else {
status = mRetriever->setDataSource(fd, 0, 0x7ffffffffffffffL);
close(fd);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 03dc9df..e8c3dd3 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -60,6 +60,12 @@
StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
ALOGV("~StagefrightMetadataRetriever()");
clearMetadata();
+ // Explicitly release extractor before continuing with the destructor,
+ // some extractors might need to callback to close off the DataSource
+ // and we need to make sure it's still there.
+ if (mExtractor != NULL) {
+ mExtractor->release();
+ }
if (mSource != NULL) {
mSource->close();
}
@@ -121,12 +127,12 @@
}
status_t StagefrightMetadataRetriever::setDataSource(
- const sp<DataSource>& source) {
+ const sp<DataSource>& source, const char *mime) {
ALOGV("setDataSource(DataSource)");
clearMetadata();
mSource = source;
- mExtractor = MediaExtractor::Create(mSource);
+ mExtractor = MediaExtractor::Create(mSource, mime);
if (mExtractor == NULL) {
ALOGE("Failed to instantiate a MediaExtractor.");
@@ -137,17 +143,170 @@
return OK;
}
+static VideoFrame *allocVideoFrame(
+ const sp<MetaData> &trackMeta, int32_t width, int32_t height, int32_t bpp, bool metaOnly) {
+ int32_t rotationAngle;
+ if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
+ rotationAngle = 0; // By default, no rotation
+ }
+
+ uint32_t type;
+ const void *iccData;
+ size_t iccSize;
+ if (!trackMeta->findData(kKeyIccProfile, &type, &iccData, &iccSize)){
+ iccData = NULL;
+ iccSize = 0;
+ }
+
+ int32_t sarWidth, sarHeight;
+ int32_t displayWidth, displayHeight;
+ if (trackMeta->findInt32(kKeySARWidth, &sarWidth)
+ && trackMeta->findInt32(kKeySARHeight, &sarHeight)
+ && sarHeight != 0) {
+ displayWidth = (width * sarWidth) / sarHeight;
+ displayHeight = height;
+ } else if (trackMeta->findInt32(kKeyDisplayWidth, &displayWidth)
+ && trackMeta->findInt32(kKeyDisplayHeight, &displayHeight)
+ && displayWidth > 0 && displayHeight > 0
+ && width > 0 && height > 0) {
+ ALOGV("found display size %dx%d", displayWidth, displayHeight);
+ } else {
+ displayWidth = width;
+ displayHeight = height;
+ }
+
+ return new VideoFrame(width, height, displayWidth, displayHeight,
+ rotationAngle, bpp, !metaOnly, iccData, iccSize);
+}
+
+static bool getDstColorFormat(android_pixel_format_t colorFormat,
+ OMX_COLOR_FORMATTYPE *omxColorFormat, int32_t *bpp) {
+ switch (colorFormat) {
+ case HAL_PIXEL_FORMAT_RGB_565:
+ {
+ *omxColorFormat = OMX_COLOR_Format16bitRGB565;
+ *bpp = 2;
+ return true;
+ }
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ {
+ *omxColorFormat = OMX_COLOR_Format32BitRGBA8888;
+ *bpp = 4;
+ return true;
+ }
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ {
+ *omxColorFormat = OMX_COLOR_Format32bitBGRA8888;
+ *bpp = 4;
+ return true;
+ }
+ default:
+ {
+ ALOGE("Unsupported color format: %d", colorFormat);
+ break;
+ }
+ }
+ return false;
+}
+
static VideoFrame *extractVideoFrame(
const AString &componentName,
const sp<MetaData> &trackMeta,
const sp<IMediaSource> &source,
int64_t frameTimeUs,
- int seekMode) {
-
+ int seekMode,
+ int colorFormat,
+ bool metaOnly) {
sp<MetaData> format = source->getFormat();
+ MediaSource::ReadOptions::SeekMode mode =
+ static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
+ if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
+ seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) {
+ ALOGE("Unknown seek mode: %d", seekMode);
+ return NULL;
+ }
+
+ int32_t dstBpp;
+ OMX_COLOR_FORMATTYPE dstFormat;
+ if (!getDstColorFormat(
+ (android_pixel_format_t)colorFormat, &dstFormat, &dstBpp)) {
+ return NULL;
+ }
+
+ if (metaOnly) {
+ int32_t width, height;
+ CHECK(trackMeta->findInt32(kKeyWidth, &width));
+ CHECK(trackMeta->findInt32(kKeyHeight, &height));
+ return allocVideoFrame(trackMeta, width, height, dstBpp, true);
+ }
+
+ MediaSource::ReadOptions options;
+ sp<MetaData> overrideMeta;
+ if (frameTimeUs < 0) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ int64_t thumbNailTime;
+ int32_t thumbnailWidth, thumbnailHeight;
+
+ // if we have a stand-alone thumbnail, set up the override meta,
+ // and set seekTo time to -1.
+ if (trackMeta->findInt32(kKeyThumbnailWidth, &thumbnailWidth)
+ && trackMeta->findInt32(kKeyThumbnailHeight, &thumbnailHeight)
+ && trackMeta->findData(kKeyThumbnailHVCC, &type, &data, &size)){
+ overrideMeta = new MetaData(*trackMeta);
+ overrideMeta->remove(kKeyDisplayWidth);
+ overrideMeta->remove(kKeyDisplayHeight);
+ overrideMeta->setInt32(kKeyWidth, thumbnailWidth);
+ overrideMeta->setInt32(kKeyHeight, thumbnailHeight);
+ overrideMeta->setData(kKeyHVCC, type, data, size);
+ thumbNailTime = -1ll;
+ ALOGV("thumbnail: %dx%d", thumbnailWidth, thumbnailHeight);
+ } else if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)
+ || thumbNailTime < 0) {
+ thumbNailTime = 0;
+ }
+
+ options.setSeekTo(thumbNailTime, mode);
+ } else {
+ options.setSeekTo(frameTimeUs, mode);
+ }
+
+ int32_t gridRows = 1, gridCols = 1;
+ if (overrideMeta == NULL) {
+ // check if we're dealing with a tiled heif
+ int32_t gridWidth, gridHeight, tmpRows, tmpCols;
+ if (trackMeta->findInt32(kKeyGridWidth, &gridWidth) && gridWidth > 0
+ && trackMeta->findInt32(kKeyGridHeight, &gridHeight) && gridHeight > 0
+ && trackMeta->findInt32(kKeyGridRows, &tmpRows) && tmpRows > 0
+ && trackMeta->findInt32(kKeyGridCols, &tmpCols) && tmpCols > 0) {
+ int32_t width, height;
+ CHECK(trackMeta->findInt32(kKeyWidth, &width));
+ CHECK(trackMeta->findInt32(kKeyHeight, &height));
+
+ if (width <= gridWidth * tmpCols && height <= gridHeight * tmpRows) {
+ ALOGV("grid: %dx%d, size: %dx%d, picture size: %dx%d",
+ tmpCols, tmpRows, gridWidth, gridHeight, width, height);
+
+ overrideMeta = new MetaData(*trackMeta);
+ overrideMeta->setInt32(kKeyWidth, gridWidth);
+ overrideMeta->setInt32(kKeyHeight, gridHeight);
+ gridCols = tmpCols;
+ gridRows = tmpRows;
+ } else {
+ ALOGE("bad grid: %dx%d, size: %dx%d, picture size: %dx%d",
+ tmpCols, tmpRows, gridWidth, gridHeight, width, height);
+ }
+ }
+ if (overrideMeta == NULL) {
+ overrideMeta = trackMeta;
+ }
+ }
+ int32_t numTiles = gridRows * gridCols;
+
sp<AMessage> videoFormat;
- if (convertMetaDataToMessage(trackMeta, &videoFormat) != OK) {
+ if (convertMetaDataToMessage(overrideMeta, &videoFormat) != OK) {
ALOGE("b/23680780");
ALOGW("Failed to convert meta data to message");
return NULL;
@@ -160,7 +319,8 @@
// input and output ports, if seeking to a sync frame. NOTE: This request may
// fail if component requires more than that for decoding.
bool isSeekingClosest = (seekMode == MediaSource::ReadOptions::SEEK_CLOSEST);
- if (!isSeekingClosest) {
+ bool decodeSingleFrame = !isSeekingClosest && (numTiles == 1);
+ if (decodeSingleFrame) {
videoFormat->setInt32("android._num-input-buffers", 1);
videoFormat->setInt32("android._num-output-buffers", 1);
}
@@ -190,30 +350,6 @@
return NULL;
}
- MediaSource::ReadOptions options;
- if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
- seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) {
-
- ALOGE("Unknown seek mode: %d", seekMode);
- decoder->release();
- return NULL;
- }
-
- MediaSource::ReadOptions::SeekMode mode =
- static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
-
- int64_t thumbNailTime;
- if (frameTimeUs < 0) {
- if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)
- || thumbNailTime < 0) {
- thumbNailTime = 0;
- }
- options.setSeekTo(thumbNailTime, mode);
- } else {
- thumbNailTime = -1;
- options.setSeekTo(frameTimeUs, mode);
- }
-
err = source->start();
if (err != OK) {
ALOGW("source failed to start: %d (%s)", err, asString(err));
@@ -258,6 +394,9 @@
bool firstSample = true;
int64_t targetTimeUs = -1ll;
+ VideoFrame *frame = NULL;
+ int32_t tilesDecoded = 0;
+
do {
size_t inputIndex = -1;
int64_t ptsUs = 0ll;
@@ -282,6 +421,9 @@
if (err != OK) {
ALOGW("Input Error or EOS");
haveMoreInputs = false;
+ if (err == ERROR_END_OF_STREAM) {
+ err = OK;
+ }
break;
}
if (firstSample && isSeekingClosest) {
@@ -293,6 +435,7 @@
if (mediaBuffer->range_length() > codecBuffer->capacity()) {
ALOGE("buffer size (%zu) too large for codec input size (%zu)",
mediaBuffer->range_length(), codecBuffer->capacity());
+ haveMoreInputs = false;
err = BAD_VALUE;
} else {
codecBuffer->setRange(0, mediaBuffer->range_length());
@@ -301,19 +444,20 @@
memcpy(codecBuffer->data(),
(const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
mediaBuffer->range_length());
- if (isAvcOrHevc && IsIDR(codecBuffer) && !isSeekingClosest) {
- // Only need to decode one IDR frame, unless we're seeking with CLOSEST
- // option, in which case we need to actually decode to targetTimeUs.
- haveMoreInputs = false;
- flags |= MediaCodec::BUFFER_FLAG_EOS;
- }
}
mediaBuffer->release();
break;
}
- if (err == OK && inputIndex < inputBuffers.size()) {
+ if (haveMoreInputs && inputIndex < inputBuffers.size()) {
+ if (isAvcOrHevc && IsIDR(codecBuffer) && decodeSingleFrame) {
+ // Only need to decode one IDR frame, unless we're seeking with CLOSEST
+ // option, in which case we need to actually decode to targetTimeUs.
+ haveMoreInputs = false;
+ flags |= MediaCodec::BUFFER_FLAG_EOS;
+ }
+
ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x",
codecBuffer->size(), ptsUs, flags);
err = decoder->queueInputBuffer(
@@ -350,13 +494,80 @@
ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
err = OK;
} else if (err == OK) {
+ if (outputFormat == NULL) {
+ decoder->releaseOutputBuffer(index);
+ err = ERROR_MALFORMED;
+ break;
+ }
+
// If we're seeking with CLOSEST option and obtained a valid targetTimeUs
// from the extractor, decode to the specified frame. Otherwise we're done.
- done = (targetTimeUs < 0ll) || (timeUs >= targetTimeUs);
ALOGV("Received an output buffer, timeUs=%lld", (long long)timeUs);
- if (!done) {
- err = decoder->releaseOutputBuffer(index);
+ sp<MediaCodecBuffer> videoFrameBuffer = outputBuffers.itemAt(index);
+
+ int32_t width, height;
+ CHECK(outputFormat->findInt32("width", &width));
+ CHECK(outputFormat->findInt32("height", &height));
+
+ int32_t crop_left, crop_top, crop_right, crop_bottom;
+ if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
+ crop_left = crop_top = 0;
+ crop_right = width - 1;
+ crop_bottom = height - 1;
}
+
+ if (frame == NULL) {
+ frame = allocVideoFrame(
+ trackMeta,
+ (crop_right - crop_left + 1) * gridCols,
+ (crop_bottom - crop_top + 1) * gridRows,
+ dstBpp,
+ false /*metaOnly*/);
+ }
+
+ int32_t srcFormat;
+ CHECK(outputFormat->findInt32("color-format", &srcFormat));
+
+ ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat);
+
+ int32_t dstLeft, dstTop, dstRight, dstBottom;
+ if (numTiles == 1) {
+ dstLeft = crop_left;
+ dstTop = crop_top;
+ dstRight = crop_right;
+ dstBottom = crop_bottom;
+ } else {
+ dstLeft = tilesDecoded % gridCols * width;
+ dstTop = tilesDecoded / gridCols * height;
+ dstRight = dstLeft + width - 1;
+ dstBottom = dstTop + height - 1;
+ }
+
+ done = (targetTimeUs < 0ll) || (timeUs >= targetTimeUs);
+
+ if (done) {
+ if (converter.isValid()) {
+ err = converter.convert(
+ (const uint8_t *)videoFrameBuffer->data(),
+ width, height,
+ crop_left, crop_top, crop_right, crop_bottom,
+ frame->mData,
+ frame->mWidth,
+ frame->mHeight,
+ dstLeft, dstTop, dstRight, dstBottom);
+ } else {
+ ALOGE("Unable to convert from format 0x%08x to 0x%08x",
+ srcFormat, dstFormat);
+
+ err = ERROR_UNSUPPORTED;
+ }
+ if (numTiles > 1) {
+ tilesDecoded++;
+ done &= (tilesDecoded >= numTiles);
+ }
+ }
+
+ decoder->releaseOutputBuffer(index);
} else {
ALOGW("Received error %d (%s) instead of output", err, asString(err));
done = true;
@@ -366,102 +577,11 @@
}
} while (err == OK && !done);
- if (err != OK || size <= 0 || outputFormat == NULL) {
- ALOGE("Failed to decode thumbnail frame");
- source->stop();
- decoder->release();
- return NULL;
- }
-
- ALOGV("successfully decoded video frame.");
- sp<MediaCodecBuffer> videoFrameBuffer = outputBuffers.itemAt(index);
-
- if (thumbNailTime >= 0) {
- if (timeUs != thumbNailTime) {
- AString mime;
- CHECK(outputFormat->findString("mime", &mime));
-
- ALOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s",
- (long long)thumbNailTime, (long long)timeUs, mime.c_str());
- }
- }
-
- int32_t width, height;
- CHECK(outputFormat->findInt32("width", &width));
- CHECK(outputFormat->findInt32("height", &height));
-
- int32_t crop_left, crop_top, crop_right, crop_bottom;
- if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
- crop_left = crop_top = 0;
- crop_right = width - 1;
- crop_bottom = height - 1;
- }
-
- int32_t rotationAngle;
- if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
- rotationAngle = 0; // By default, no rotation
- }
-
- VideoFrame *frame = new VideoFrame;
- frame->mWidth = crop_right - crop_left + 1;
- frame->mHeight = crop_bottom - crop_top + 1;
- frame->mDisplayWidth = frame->mWidth;
- frame->mDisplayHeight = frame->mHeight;
- frame->mSize = frame->mWidth * frame->mHeight * 2;
- frame->mData = new uint8_t[frame->mSize];
- frame->mRotationAngle = rotationAngle;
-
- int32_t sarWidth, sarHeight;
- if (trackMeta->findInt32(kKeySARWidth, &sarWidth)
- && trackMeta->findInt32(kKeySARHeight, &sarHeight)
- && sarHeight != 0) {
- frame->mDisplayWidth = (frame->mDisplayWidth * sarWidth) / sarHeight;
- } else {
- int32_t width, height;
- if (trackMeta->findInt32(kKeyDisplayWidth, &width)
- && trackMeta->findInt32(kKeyDisplayHeight, &height)
- && frame->mDisplayWidth > 0 && frame->mDisplayHeight > 0
- && width > 0 && height > 0) {
- if (frame->mDisplayHeight * (int64_t)width / height > (int64_t)frame->mDisplayWidth) {
- frame->mDisplayHeight =
- (int32_t)(height * (int64_t)frame->mDisplayWidth / width);
- } else {
- frame->mDisplayWidth =
- (int32_t)(frame->mDisplayHeight * (int64_t)width / height);
- }
- ALOGV("thumbNail width and height are overridden to %d x %d",
- frame->mDisplayWidth, frame->mDisplayHeight);
- }
- }
-
- int32_t srcFormat;
- CHECK(outputFormat->findInt32("color-format", &srcFormat));
-
- ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
-
- if (converter.isValid()) {
- err = converter.convert(
- (const uint8_t *)videoFrameBuffer->data(),
- width, height,
- crop_left, crop_top, crop_right, crop_bottom,
- frame->mData,
- frame->mWidth,
- frame->mHeight,
- 0, 0, frame->mWidth - 1, frame->mHeight - 1);
- } else {
- ALOGE("Unable to convert from format 0x%08x to RGB565", srcFormat);
-
- err = ERROR_UNSUPPORTED;
- }
-
- videoFrameBuffer.clear();
source->stop();
- decoder->releaseOutputBuffer(index);
decoder->release();
if (err != OK) {
- ALOGE("Colorconverter failed to convert frame.");
-
+ ALOGE("failed to get video frame (err %d)", err);
delete frame;
frame = NULL;
}
@@ -470,9 +590,10 @@
}
VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
- int64_t timeUs, int option) {
+ int64_t timeUs, int option, int colorFormat, bool metaOnly) {
- ALOGV("getFrameAtTime: %" PRId64 " us option: %d", timeUs, option);
+ ALOGV("getFrameAtTime: %" PRId64 " us option: %d colorFormat: %d, metaOnly: %d",
+ timeUs, option, colorFormat, metaOnly);
if (mExtractor.get() == NULL) {
ALOGV("no extractor.");
@@ -540,8 +661,8 @@
for (size_t i = 0; i < matchingCodecs.size(); ++i) {
const AString &componentName = matchingCodecs[i];
- VideoFrame *frame =
- extractVideoFrame(componentName, trackMeta, source, timeUs, option);
+ VideoFrame *frame = extractVideoFrame(
+ componentName, trackMeta, source, timeUs, option, colorFormat, metaOnly);
if (frame != NULL) {
return frame;
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 0aea8e1..3ef8f2a 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -237,6 +237,11 @@
OMX_VIDEO_AVCPROFILETYPE codecProfile;
OMX_VIDEO_AVCLEVELTYPE codecLevel;
if (profiles.map(profile, &codecProfile)) {
+ if (profile == 66 && (constraints & 0x40)) {
+ codecProfile = (OMX_VIDEO_AVCPROFILETYPE)OMX_VIDEO_AVCProfileConstrainedBaseline;
+ } else if (profile == 100 && (constraints & 0x0C) == 0x0C) {
+ codecProfile = (OMX_VIDEO_AVCPROFILETYPE)OMX_VIDEO_AVCProfileConstrainedHigh;
+ }
format->setInt32("profile", codecProfile);
if (levels.map(level, &codecLevel)) {
// for 9 && 11 decide level based on profile and constraint_set3 flag
@@ -1874,5 +1879,13 @@
return result;
}
+void MakeFourCCString(uint32_t x, char *s) {
+ s[0] = x >> 24;
+ s[1] = (x >> 16) & 0xff;
+ s[2] = (x >> 8) & 0xff;
+ s[3] = x & 0xff;
+ s[4] = '\0';
+}
+
} // namespace android
diff --git a/media/libstagefright/codecs/aacdec/Android.bp b/media/libstagefright/codecs/aacdec/Android.bp
index 6e04c1e..21c00a1 100644
--- a/media/libstagefright/codecs/aacdec/Android.bp
+++ b/media/libstagefright/codecs/aacdec/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_soft_aacdec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: [
"SoftAAC2.cpp",
@@ -33,4 +37,5 @@
"libcutils",
"liblog",
],
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 9fbdb72..e0c0c32 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -218,6 +218,30 @@
OMX_ERRORTYPE SoftAAC2::internalGetParameter(
OMX_INDEXTYPE index, OMX_PTR params) {
switch ((OMX_U32) index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding =
+ (formatParams->nPortIndex == 0)
+ ? OMX_AUDIO_CodingAAC : OMX_AUDIO_CodingPCM;
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioAac:
{
OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
@@ -342,6 +366,29 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if ((formatParams->nPortIndex == 0
+ && formatParams->eEncoding != OMX_AUDIO_CodingAAC)
+ || (formatParams->nPortIndex == 1
+ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioAac:
{
const OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index a1cf285..73a3965 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -17,7 +17,7 @@
#ifndef SOFT_AAC_2_H_
#define SOFT_AAC_2_H_
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
#include "aacdecoder_lib.h"
#include "DrcPresModeWrap.h"
diff --git a/media/libstagefright/codecs/aacenc/Android.bp b/media/libstagefright/codecs/aacenc/Android.bp
index 1a7ffca..fb368c2 100644
--- a/media/libstagefright/codecs/aacenc/Android.bp
+++ b/media/libstagefright/codecs/aacenc/Android.bp
@@ -1,5 +1,6 @@
cc_library_static {
name: "libstagefright_aacenc",
+ vendor_available: true,
srcs: [
"basic_op/basicop2.c",
@@ -111,6 +112,10 @@
cc_library_shared {
name: "libstagefright_soft_aacenc",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["SoftAACEncoder2.cpp"],
@@ -140,6 +145,7 @@
"libutils",
"liblog",
],
+ compile_multilib: "32",
}
cc_library_shared {
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
index 981cbbb..e64c1b7 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
@@ -18,7 +18,7 @@
#define SOFT_AAC_ENCODER_H_
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
struct VO_AUDIO_CODECAPI;
struct VO_MEM_OPERATOR;
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
index 123fd25..681dcf2 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
@@ -18,7 +18,7 @@
#define SOFT_AAC_ENCODER_2_H_
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
#include "aacenc_lib.h"
diff --git a/media/libstagefright/codecs/amrnb/common/Android.bp b/media/libstagefright/codecs/amrnb/common/Android.bp
index c5ac558..5177593 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.bp
+++ b/media/libstagefright/codecs/amrnb/common/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_amrnb_common",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: [
"src/add.cpp",
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.bp b/media/libstagefright/codecs/amrnb/dec/Android.bp
index 996183b..d266dc2 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.bp
+++ b/media/libstagefright/codecs/amrnb/dec/Android.bp
@@ -1,5 +1,6 @@
cc_library_static {
name: "libstagefright_amrnbdec",
+ vendor_available: true,
srcs: [
"src/a_refl.cpp",
@@ -55,13 +56,20 @@
// ],
//},
- shared_libs: ["libstagefright_amrnb_common"],
+ shared_libs: [
+ "libstagefright_amrnb_common",
+ "liblog",
+ ],
}
//###############################################################################
cc_library_shared {
name: "libstagefright_soft_amrdec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["SoftAMR.cpp"],
@@ -96,6 +104,7 @@
"liblog",
"libstagefright_amrnb_common",
],
+ compile_multilib: "32",
}
//###############################################################################
diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
index 7553153..b7e84ec 100644
--- a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
@@ -143,6 +143,30 @@
OMX_ERRORTYPE SoftAMR::internalGetParameter(
OMX_INDEXTYPE index, OMX_PTR params) {
switch (index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding =
+ (formatParams->nPortIndex == 0)
+ ? OMX_AUDIO_CodingAMR : OMX_AUDIO_CodingPCM;
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioAmr:
{
OMX_AUDIO_PARAM_AMRTYPE *amrParams =
@@ -236,6 +260,29 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if ((formatParams->nPortIndex == 0
+ && formatParams->eEncoding != OMX_AUDIO_CodingAMR)
+ || (formatParams->nPortIndex == 1
+ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioAmr:
{
const OMX_AUDIO_PARAM_AMRTYPE *aacParams =
diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.h b/media/libstagefright/codecs/amrnb/dec/SoftAMR.h
index 758d6ac..869b81d 100644
--- a/media/libstagefright/codecs/amrnb/dec/SoftAMR.h
+++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.h
@@ -18,7 +18,7 @@
#define SOFT_AMR_H_
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
namespace android {
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.bp b/media/libstagefright/codecs/amrnb/enc/Android.bp
index af0f8c2..6dc2dc1 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.bp
+++ b/media/libstagefright/codecs/amrnb/enc/Android.bp
@@ -1,5 +1,6 @@
cc_library_static {
name: "libstagefright_amrnbenc",
+ vendor_available: true,
srcs: [
"src/amrencode.cpp",
@@ -83,6 +84,10 @@
cc_library_shared {
name: "libstagefright_soft_amrnbenc",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["SoftAMRNBEncoder.cpp"],
@@ -110,6 +115,7 @@
"liblog",
"libstagefright_amrnb_common",
],
+ compile_multilib: "32",
}
//###############################################################################
diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h
index 50178c4..c73e4dd 100644
--- a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h
+++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h
@@ -18,7 +18,7 @@
#define SOFT_AMRNB_ENCODER_H_
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
namespace android {
diff --git a/media/libstagefright/codecs/amrwb/Android.bp b/media/libstagefright/codecs/amrwb/Android.bp
index e261c04..b932ccc 100644
--- a/media/libstagefright/codecs/amrwb/Android.bp
+++ b/media/libstagefright/codecs/amrwb/Android.bp
@@ -1,5 +1,6 @@
cc_library_static {
name: "libstagefright_amrwbdec",
+ vendor_available: true,
srcs: [
"src/agc2_amr_wb.cpp",
diff --git a/media/libstagefright/codecs/amrwbenc/Android.bp b/media/libstagefright/codecs/amrwbenc/Android.bp
index 5c5a122..6ded9ff 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.bp
+++ b/media/libstagefright/codecs/amrwbenc/Android.bp
@@ -1,5 +1,6 @@
cc_library_static {
name: "libstagefright_amrwbenc",
+ vendor_available: true,
srcs: [
"src/autocorr.c",
@@ -128,6 +129,7 @@
shared_libs: [
"libstagefright_enc_common",
+ "liblog",
],
cflags: ["-Werror"],
@@ -144,6 +146,10 @@
cc_library_shared {
name: "libstagefright_soft_amrwbenc",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["SoftAMRWBEncoder.cpp"],
@@ -173,6 +179,7 @@
"liblog",
"libstagefright_enc_common",
],
+ compile_multilib: "32",
}
//###############################################################################
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
index d52fed3..79a5d67 100644
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
+++ b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
@@ -12,6 +12,7 @@
shared_libs: [
"libdl",
+ "liblog",
],
static_libs: [
diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h
index d0c1dab..8950a8c 100644
--- a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h
+++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h
@@ -18,7 +18,7 @@
#define SOFT_AMRWB_ENCODER_H_
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
#include "voAMRWB.h"
diff --git a/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c b/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
index 8cebb09..f2e28c4 100644
--- a/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
+++ b/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
@@ -47,6 +47,10 @@
#include "q_pulse.h"
+#undef LOG_TAG
+#define LOG_TAG "amrwbenc"
+#include "log/log.h"
+
static Word16 tipos[36] = {
0, 1, 2, 3, /* starting point &ipos[0], 1st iter */
1, 2, 3, 0, /* starting point &ipos[4], 2nd iter */
@@ -745,11 +749,16 @@
i = (Word16)((vo_L_mult(track, NPMAXPT) >> 1));
- while (ind[i] >= 0)
+ while (i < NPMAXPT * NB_TRACK && ind[i] >= 0)
{
i += 1;
}
- ind[i] = index;
+ if (i < NPMAXPT * NB_TRACK) {
+ ind[i] = index;
+ } else {
+ ALOGE("b/132647222, OOB access in ind array track=%d i=%d", track, i);
+ android_errorWriteLog(0x534e4554, "132647222");
+ }
}
k = 0;
diff --git a/media/libstagefright/codecs/avcdec/Android.bp b/media/libstagefright/codecs/avcdec/Android.bp
index 6b996a7..1f43803 100644
--- a/media/libstagefright/codecs/avcdec/Android.bp
+++ b/media/libstagefright/codecs/avcdec/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_soft_avcdec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
static_libs: ["libavcdec"],
srcs: ["SoftAVCDec.cpp"],
@@ -12,7 +16,7 @@
],
shared_libs: [
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libstagefright_foundation",
"libutils",
@@ -30,4 +34,5 @@
},
ldflags: ["-Wl,-Bsymbolic"],
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
index 5486a6d..dae6e79 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -48,10 +48,14 @@
(IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
static const CodecProfileLevel kProfileLevels[] = {
+ { OMX_VIDEO_AVCProfileConstrainedBaseline, OMX_VIDEO_AVCLevel52 },
+
{ OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel52 },
{ OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel52 },
+ { OMX_VIDEO_AVCProfileConstrainedHigh, OMX_VIDEO_AVCLevel52 },
+
{ OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel52 },
};
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.h b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
index 18b7556..679ed3e 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.h
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
@@ -18,7 +18,7 @@
#define SOFT_H264_DEC_H_
-#include "SoftVideoDecoderOMXComponent.h"
+#include <media/stagefright/omx/SoftVideoDecoderOMXComponent.h>
#include <sys/time.h>
namespace android {
diff --git a/media/libstagefright/codecs/avcenc/Android.bp b/media/libstagefright/codecs/avcenc/Android.bp
index 49021a9..66507a7 100644
--- a/media/libstagefright/codecs/avcenc/Android.bp
+++ b/media/libstagefright/codecs/avcenc/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_soft_avcenc",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
static_libs: ["libavcenc"],
srcs: ["SoftAVCEnc.cpp"],
@@ -13,7 +17,7 @@
],
shared_libs: [
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libutils",
"liblog",
@@ -30,4 +34,5 @@
},
ldflags: ["-Wl,-Bsymbolic"],
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
index 30960b5..32fdbd3 100644
--- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
+++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
@@ -27,7 +27,6 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
#include <OMX_IndexExt.h>
#include <OMX_VideoExt.h>
@@ -75,33 +74,11 @@
};
static const CodecProfileLevel kProfileLevels[] = {
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel2 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel21 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel22 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel3 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel31 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel32 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel4 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel1 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel1b },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel11 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel12 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel13 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel2 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel21 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel22 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel3 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel31 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel32 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel4 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel41 },
+ { OMX_VIDEO_AVCProfileConstrainedBaseline, OMX_VIDEO_AVCLevel41 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 },
+
+ { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel41 },
};
static size_t GetCPUCoreCount() {
@@ -629,8 +606,10 @@
level = 30;
} else if (displaySizeY > (352 * 288)) {
level = 21;
- } else {
+ } else if (displaySizeY > (176 * 144)) {
level = 20;
+ } else {
+ level = 10;
}
mAVCEncLevel = MAX(level, mAVCEncLevel);
@@ -963,7 +942,8 @@
return OMX_ErrorUndefined;
}
- avcParams->eProfile = OMX_VIDEO_AVCProfileBaseline;
+ // TODO: maintain profile
+ avcParams->eProfile = (OMX_VIDEO_AVCPROFILETYPE)OMX_VIDEO_AVCProfileConstrainedBaseline;
avcParams->eLevel = omxLevel;
avcParams->nRefFrames = 1;
avcParams->bUseHadamard = OMX_TRUE;
diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.h b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h
index 818e4a1..a43cdf1 100644
--- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.h
+++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h
@@ -21,7 +21,7 @@
#include <media/stagefright/foundation/ABase.h>
#include <utils/Vector.h>
-#include "SoftVideoEncoderOMXComponent.h"
+#include <media/stagefright/omx/SoftVideoEncoderOMXComponent.h>
namespace android {
diff --git a/media/libstagefright/codecs/common/Android.bp b/media/libstagefright/codecs/common/Android.bp
index 021e6af..3726922 100644
--- a/media/libstagefright/codecs/common/Android.bp
+++ b/media/libstagefright/codecs/common/Android.bp
@@ -1,5 +1,9 @@
cc_library {
name: "libstagefright_enc_common",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["cmnMemory.c"],
diff --git a/media/libstagefright/codecs/flac/dec/Android.bp b/media/libstagefright/codecs/flac/dec/Android.bp
index 6ac264d..595cfdb 100644
--- a/media/libstagefright/codecs/flac/dec/Android.bp
+++ b/media/libstagefright/codecs/flac/dec/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_soft_flacdec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: [
"SoftFlacDecoder.cpp",
@@ -33,4 +37,5 @@
"libstagefright_foundation",
"libutils",
],
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
index cff4a33..4ab1ab2 100644
--- a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
@@ -126,6 +126,29 @@
OMX_INDEXTYPE index, OMX_PTR params) {
ALOGV("internalGetParameter: index(%x)", index);
switch ((OMX_U32)index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding =
+ (formatParams->nPortIndex == 0)
+ ? OMX_AUDIO_CodingFLAC : OMX_AUDIO_CodingPCM;
+
+ return OMX_ErrorNone;
+ }
case OMX_IndexParamAudioFlac:
{
OMX_AUDIO_PARAM_FLACTYPE *flacParams =
@@ -219,6 +242,29 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if ((formatParams->nPortIndex == 0
+ && formatParams->eEncoding != OMX_AUDIO_CodingFLAC)
+ || (formatParams->nPortIndex == 1
+ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioPcm:
{
const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
@@ -256,10 +302,27 @@
while (!inQueue.empty() && !outQueue.empty()) {
BufferInfo *inInfo = *inQueue.begin();
OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
uint8_t* inBuffer = inHeader->pBuffer + inHeader->nOffset;
uint32_t inBufferLength = inHeader->nFilledLen;
bool endOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0;
+ if (inHeader->nFilledLen == 0) {
+ if (endOfInput) {
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(outQueue.begin());
+ notifyFillBufferDone(outHeader);
+ } else {
+ ALOGE("onQueueFilled: emptyInputBuffer received");
+ }
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ notifyEmptyBufferDone(inHeader);
+ return;
+ }
if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
ALOGE("onQueueFilled: first buffer should have OMX_BUFFERFLAG_CODECCONFIG set");
inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
@@ -297,8 +360,6 @@
return;
}
- BufferInfo *outInfo = *outQueue.begin();
- OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
short *outBuffer =
reinterpret_cast<short *>(outHeader->pBuffer + outHeader->nOffset);
size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset;
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
index c09081d..4a21c34 100644
--- a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
@@ -18,7 +18,7 @@
#define SOFT_FLAC_DECODER_H
#include "FLACDecoder.h"
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
namespace android {
diff --git a/media/libstagefright/codecs/flac/enc/Android.bp b/media/libstagefright/codecs/flac/enc/Android.bp
index d1413f6..066917b 100644
--- a/media/libstagefright/codecs/flac/enc/Android.bp
+++ b/media/libstagefright/codecs/flac/enc/Android.bp
@@ -22,7 +22,7 @@
},
shared_libs: [
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libstagefright_foundation",
"libutils",
@@ -32,5 +32,10 @@
static_libs: ["libFLAC"],
name: "libstagefright_soft_flacenc",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
index caceda9..56d2d69 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
@@ -154,6 +154,30 @@
ALOGV("SoftFlacEncoder::internalGetParameter(index=0x%x)", index);
switch (index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding =
+ (formatParams->nPortIndex == 0)
+ ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingFLAC;
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioPcm:
{
OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
@@ -163,7 +187,7 @@
return OMX_ErrorBadParameter;
}
- if (pcmParams->nPortIndex > 1) {
+ if (pcmParams->nPortIndex != 0) {
return OMX_ErrorUndefined;
}
@@ -189,6 +213,10 @@
return OMX_ErrorBadParameter;
}
+ if (flacParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
flacParams->nCompressionLevel = mCompressionLevel;
flacParams->nChannels = mNumChannels;
flacParams->nSampleRate = mSampleRate;
@@ -203,6 +231,29 @@
OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter(
OMX_INDEXTYPE index, const OMX_PTR params) {
switch (index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if ((formatParams->nPortIndex == 0
+ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
+ || (formatParams->nPortIndex == 1
+ && formatParams->eEncoding != OMX_AUDIO_CodingFLAC)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioPcm:
{
ALOGV("SoftFlacEncoder::internalSetParameter(OMX_IndexParamAudioPcm)");
@@ -212,7 +263,7 @@
return OMX_ErrorBadParameter;
}
- if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) {
+ if (pcmParams->nPortIndex != 0) {
ALOGE("SoftFlacEncoder::internalSetParameter() Error #1");
return OMX_ErrorUndefined;
}
@@ -258,6 +309,10 @@
return OMX_ErrorBadParameter;
}
+ if (flacParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
mCompressionLevel = flacParams->nCompressionLevel; // range clamping done inside encoder
return OMX_ErrorNone;
}
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h
index 6027f76..f4f0655 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h
@@ -18,7 +18,7 @@
#define SOFT_FLAC_ENC_H_
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
#include "FLAC/stream_encoder.h"
diff --git a/media/libstagefright/codecs/g711/dec/Android.bp b/media/libstagefright/codecs/g711/dec/Android.bp
index b78b689..fff72a8 100644
--- a/media/libstagefright/codecs/g711/dec/Android.bp
+++ b/media/libstagefright/codecs/g711/dec/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_soft_g711dec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["SoftG711.cpp"],
@@ -9,7 +13,7 @@
],
shared_libs: [
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libutils",
"liblog",
@@ -27,4 +31,5 @@
cfi: true,
},
},
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
index f7c0429..7a4cca9 100644
--- a/media/libstagefright/codecs/g711/dec/SoftG711.cpp
+++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
@@ -105,6 +105,30 @@
OMX_ERRORTYPE SoftG711::internalGetParameter(
OMX_INDEXTYPE index, OMX_PTR params) {
switch (index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding =
+ (formatParams->nPortIndex == 0)
+ ? OMX_AUDIO_CodingG711 : OMX_AUDIO_CodingPCM;
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioPcm:
{
OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
@@ -173,6 +197,29 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if ((formatParams->nPortIndex == 0
+ && formatParams->eEncoding != OMX_AUDIO_CodingG711)
+ || (formatParams->nPortIndex == 1
+ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamStandardComponentRole:
{
const OMX_PARAM_COMPONENTROLETYPE *roleParams =
diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.h b/media/libstagefright/codecs/g711/dec/SoftG711.h
index 16b6340..3ece246 100644
--- a/media/libstagefright/codecs/g711/dec/SoftG711.h
+++ b/media/libstagefright/codecs/g711/dec/SoftG711.h
@@ -18,7 +18,7 @@
#define SOFT_G711_H_
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
namespace android {
diff --git a/media/libstagefright/codecs/gsm/dec/Android.bp b/media/libstagefright/codecs/gsm/dec/Android.bp
index 8e86ad6..753eeef 100644
--- a/media/libstagefright/codecs/gsm/dec/Android.bp
+++ b/media/libstagefright/codecs/gsm/dec/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_soft_gsmdec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["SoftGSM.cpp"],
@@ -23,11 +27,12 @@
},
shared_libs: [
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libutils",
"liblog",
],
static_libs: ["libgsm"],
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
index 11999b4..d777229 100644
--- a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
+++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
@@ -105,6 +105,30 @@
OMX_ERRORTYPE SoftGSM::internalGetParameter(
OMX_INDEXTYPE index, OMX_PTR params) {
switch (index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding =
+ (formatParams->nPortIndex == 0)
+ ? OMX_AUDIO_CodingGSMFR : OMX_AUDIO_CodingPCM;
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioPcm:
{
OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
@@ -164,6 +188,29 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if ((formatParams->nPortIndex == 0
+ && formatParams->eEncoding != OMX_AUDIO_CodingGSMFR)
+ || (formatParams->nPortIndex == 1
+ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamStandardComponentRole:
{
const OMX_PARAM_COMPONENTROLETYPE *roleParams =
diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.h b/media/libstagefright/codecs/gsm/dec/SoftGSM.h
index 0303dea..ef86915 100644
--- a/media/libstagefright/codecs/gsm/dec/SoftGSM.h
+++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.h
@@ -18,7 +18,7 @@
#define SOFT_GSM_H_
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
extern "C" {
#include "gsm.h"
diff --git a/media/libstagefright/codecs/hevcdec/Android.bp b/media/libstagefright/codecs/hevcdec/Android.bp
index cd75c97..7fa74d4 100644
--- a/media/libstagefright/codecs/hevcdec/Android.bp
+++ b/media/libstagefright/codecs/hevcdec/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_soft_hevcdec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
static_libs: ["libhevcdec"],
srcs: ["SoftHEVC.cpp"],
@@ -22,7 +26,7 @@
},
shared_libs: [
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libstagefright_foundation",
"libutils",
@@ -33,4 +37,5 @@
// requires unsupported dynamic reloc R_ARM_REL32; recompile with -fPIC
// Bug: 16853291
ldflags: ["-Wl,-Bsymbolic"],
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.h b/media/libstagefright/codecs/hevcdec/SoftHEVC.h
index e7c2127..5800490 100644
--- a/media/libstagefright/codecs/hevcdec/SoftHEVC.h
+++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.h
@@ -18,7 +18,7 @@
#define SOFT_HEVC_H_
-#include "SoftVideoDecoderOMXComponent.h"
+#include <media/stagefright/omx/SoftVideoDecoderOMXComponent.h>
#include <sys/time.h>
namespace android {
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.bp b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
index 04ea075..1216ae5 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
@@ -1,5 +1,7 @@
cc_library_static {
name: "libstagefright_m4vh263dec",
+ vendor_available: true,
+ shared_libs: ["liblog"],
srcs: [
"src/adaptive_smooth_no_mmx.cpp",
@@ -66,6 +68,10 @@
cc_library_shared {
name: "libstagefright_soft_mpeg4dec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["SoftMPEG4.cpp"],
@@ -87,7 +93,7 @@
static_libs: ["libstagefright_m4vh263dec"],
shared_libs: [
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libstagefright_foundation",
"libutils",
@@ -103,4 +109,5 @@
cfi: true,
},
},
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index 411a251..39b67ab 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -31,20 +31,12 @@
namespace android {
static const CodecProfileLevel kM4VProfileLevels[] = {
- { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 },
- { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b },
- { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 },
- { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 },
{ OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 },
};
static const CodecProfileLevel kH263ProfileLevels[] = {
- { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10 },
- { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level20 },
{ OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level30 },
{ OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 },
- { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level10 },
- { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level20 },
{ OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level30 },
{ OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level45 },
};
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h
index 4114e7d..e399ac9 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h
@@ -18,7 +18,7 @@
#define SOFT_MPEG4_H_
-#include "SoftVideoDecoderOMXComponent.h"
+#include <media/stagefright/omx/SoftVideoDecoderOMXComponent.h>
struct tagvideoDecControls;
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.bp b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
index da5b162..640718d 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
@@ -1,5 +1,6 @@
cc_library_static {
name: "libstagefright_m4vh263enc",
+ vendor_available: true,
srcs: [
"src/bitstream_io.cpp",
@@ -52,6 +53,10 @@
cc_library_shared {
name: "libstagefright_soft_mpeg4enc",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["SoftMPEG4Encoder.cpp"],
@@ -75,7 +80,7 @@
static_libs: ["libstagefright_m4vh263enc"],
shared_libs: [
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libutils",
"liblog",
@@ -90,6 +95,7 @@
cfi: true,
},
},
+ compile_multilib: "32",
}
//###############################################################################
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
index f15b154..f6a7b0e 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
@@ -29,7 +29,6 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
#include "SoftMPEG4Encoder.h"
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
index ae8cb6f..00f2dd3 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
@@ -19,7 +19,7 @@
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/foundation/ABase.h>
-#include "SoftVideoEncoderOMXComponent.h"
+#include <media/stagefright/omx/SoftVideoEncoderOMXComponent.h>
#include "mp4enc_api.h"
diff --git a/media/libstagefright/codecs/mp3dec/Android.bp b/media/libstagefright/codecs/mp3dec/Android.bp
index 0d0a2c6..273fa31 100644
--- a/media/libstagefright/codecs/mp3dec/Android.bp
+++ b/media/libstagefright/codecs/mp3dec/Android.bp
@@ -1,5 +1,6 @@
cc_library_static {
name: "libstagefright_mp3dec",
+ vendor_available: true,
srcs: [
"src/pvmp3_normalize.cpp",
@@ -77,6 +78,10 @@
cc_library_shared {
name: "libstagefright_soft_mp3dec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["SoftMP3.cpp"],
@@ -102,7 +107,7 @@
},
shared_libs: [
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libstagefright_foundation",
"libutils",
@@ -110,6 +115,7 @@
],
static_libs: ["libstagefright_mp3dec"],
+ compile_multilib: "32",
}
//###############################################################################
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 3def1f0..2364684 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -134,6 +134,30 @@
OMX_ERRORTYPE SoftMP3::internalGetParameter(
OMX_INDEXTYPE index, OMX_PTR params) {
switch (index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding =
+ (formatParams->nPortIndex == 0)
+ ? OMX_AUDIO_CodingMP3 : OMX_AUDIO_CodingPCM;
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioPcm:
{
OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
@@ -208,6 +232,29 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if ((formatParams->nPortIndex == 0
+ && formatParams->eEncoding != OMX_AUDIO_CodingMP3)
+ || (formatParams->nPortIndex == 1
+ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioPcm:
{
const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.h b/media/libstagefright/codecs/mp3dec/SoftMP3.h
index 3bfa6c7..976fd00 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.h
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.h
@@ -18,7 +18,7 @@
#define SOFT_MP3_H_
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
struct tPVMP3DecoderExternal;
diff --git a/media/libstagefright/codecs/mpeg2dec/Android.bp b/media/libstagefright/codecs/mpeg2dec/Android.bp
index 0144581..15fdde7 100644
--- a/media/libstagefright/codecs/mpeg2dec/Android.bp
+++ b/media/libstagefright/codecs/mpeg2dec/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_soft_mpeg2dec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
static_libs: ["libmpeg2dec"],
srcs: ["SoftMPEG2.cpp"],
@@ -12,7 +16,7 @@
],
shared_libs: [
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libstagefright_foundation",
"libutils",
@@ -30,4 +34,5 @@
cfi: true,
},
},
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
index 9a69226..9d5f342 100644
--- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
+++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
@@ -789,7 +789,7 @@
if (s_dec_op.u4_output_present) {
ssize_t timeStampIdx;
- outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
+ outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
timeStampIdx = getMinTimestampIdx(mTimeStamps, mTimeStampsValid);
if (timeStampIdx < 0) {
diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
index 6729a54..338fc30 100644
--- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
+++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
@@ -18,7 +18,7 @@
#define SOFT_MPEG2_H_
-#include "SoftVideoDecoderOMXComponent.h"
+#include <media/stagefright/omx/SoftVideoDecoderOMXComponent.h>
#include <sys/time.h>
namespace android {
diff --git a/media/libstagefright/codecs/on2/dec/Android.bp b/media/libstagefright/codecs/on2/dec/Android.bp
index c4242c2..59c1f5d 100644
--- a/media/libstagefright/codecs/on2/dec/Android.bp
+++ b/media/libstagefright/codecs/on2/dec/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_soft_vpxdec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["SoftVPX.cpp"],
@@ -11,7 +15,7 @@
static_libs: ["libvpx"],
shared_libs: [
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libstagefright_foundation",
"libutils",
@@ -30,4 +34,5 @@
cfi: true,
},
},
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.h b/media/libstagefright/codecs/on2/dec/SoftVPX.h
index 84cf79c..d6bb902 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.h
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.h
@@ -18,7 +18,7 @@
#define SOFT_VPX_H_
-#include "SoftVideoDecoderOMXComponent.h"
+#include <media/stagefright/omx/SoftVideoDecoderOMXComponent.h>
#include "vpx/vpx_decoder.h"
#include "vpx/vpx_codec.h"
diff --git a/media/libstagefright/codecs/on2/enc/Android.bp b/media/libstagefright/codecs/on2/enc/Android.bp
index 114c1be..741774c 100644
--- a/media/libstagefright/codecs/on2/enc/Android.bp
+++ b/media/libstagefright/codecs/on2/enc/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_soft_vpxenc",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: [
"SoftVPXEncoder.cpp",
@@ -26,10 +30,11 @@
static_libs: ["libvpx"],
shared_libs: [
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libstagefright_foundation",
"libutils",
"liblog",
],
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
index 86dfad7..dd86d36 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
@@ -18,7 +18,7 @@
#define SOFT_VPX_ENCODER_H_
-#include "SoftVideoEncoderOMXComponent.h"
+#include <media/stagefright/omx/SoftVideoEncoderOMXComponent.h>
#include <OMX_VideoExt.h>
#include <OMX_IndexExt.h>
diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.h b/media/libstagefright/codecs/on2/h264dec/SoftAVC.h
index b8c1807..fad988b 100644
--- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.h
+++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.h
@@ -18,7 +18,7 @@
#define SOFT_AVC_H_
-#include "SoftVideoDecoderOMXComponent.h"
+#include <media/stagefright/omx/SoftVideoDecoderOMXComponent.h>
#include <utils/KeyedVector.h>
#include "H264SwDecApi.h"
diff --git a/media/libstagefright/codecs/opus/dec/Android.bp b/media/libstagefright/codecs/opus/dec/Android.bp
index 5d9c4c8..88d6ec4 100644
--- a/media/libstagefright/codecs/opus/dec/Android.bp
+++ b/media/libstagefright/codecs/opus/dec/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_soft_opusdec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["SoftOpus.cpp"],
@@ -10,13 +14,15 @@
shared_libs: [
"libopus",
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libstagefright_foundation",
"libutils",
"liblog",
],
+ cflags: ["-Werror"],
+
sanitize: {
misc_undefined: [
"signed-integer-overflow",
@@ -27,4 +33,5 @@
cfi: true,
},
},
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
index 2ac6ce0..813004b 100644
--- a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
+++ b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
@@ -62,6 +62,7 @@
mSeekPreRoll(0),
mAnchorTimeUs(0),
mNumFramesOutput(0),
+ mHaveEOS(false),
mOutputPortSettingsChange(NONE) {
initPorts();
CHECK_EQ(initDecoder(), (status_t)OK);
@@ -129,6 +130,31 @@
OMX_ERRORTYPE SoftOpus::internalGetParameter(
OMX_INDEXTYPE index, OMX_PTR params) {
switch ((int)index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding =
+ (formatParams->nPortIndex == 0)
+ ? (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS :
+ OMX_AUDIO_CodingPCM;
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioAndroidOpus:
{
OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams =
@@ -212,6 +238,30 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if ((formatParams->nPortIndex == 0
+ && formatParams->eEncoding !=
+ (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS)
+ || (formatParams->nPortIndex == 1
+ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioAndroidOpus:
{
const OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams =
@@ -335,7 +385,31 @@
return static_cast<double>(ns) * kRate / 1000000000;
}
-void SoftOpus::onQueueFilled(OMX_U32 portIndex) {
+void SoftOpus::handleEOS() {
+ List<BufferInfo *> &inQueue = getPortQueue(0);
+ List<BufferInfo *> &outQueue = getPortQueue(1);
+ CHECK(!inQueue.empty() && !outQueue.empty());
+
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ mHaveEOS = true;
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ ++mInputBufferCount;
+}
+
+void SoftOpus::onQueueFilled(OMX_U32 /* portIndex */) {
List<BufferInfo *> &inQueue = getPortQueue(0);
List<BufferInfo *> &outQueue = getPortQueue(1);
@@ -343,104 +417,108 @@
return;
}
- if (portIndex == 0 && mInputBufferCount < 3) {
- BufferInfo *info = *inQueue.begin();
- OMX_BUFFERHEADERTYPE *header = info->mHeader;
-
- const uint8_t *data = header->pBuffer + header->nOffset;
- size_t size = header->nFilledLen;
-
- if (mInputBufferCount == 0) {
- CHECK(mHeader == NULL);
- mHeader = new OpusHeader();
- memset(mHeader, 0, sizeof(*mHeader));
- if (!ParseOpusHeader(data, size, mHeader)) {
- ALOGV("Parsing Opus Header failed.");
- notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- return;
- }
-
- uint8_t channel_mapping[kMaxChannels] = {0};
- if (mHeader->channels <= kMaxChannelsWithDefaultLayout) {
- memcpy(&channel_mapping,
- kDefaultOpusChannelLayout,
- kMaxChannelsWithDefaultLayout);
- } else {
- memcpy(&channel_mapping,
- mHeader->stream_map,
- mHeader->channels);
- }
-
- int status = OPUS_INVALID_STATE;
- mDecoder = opus_multistream_decoder_create(kRate,
- mHeader->channels,
- mHeader->num_streams,
- mHeader->num_coupled,
- channel_mapping,
- &status);
- if (!mDecoder || status != OPUS_OK) {
- ALOGV("opus_multistream_decoder_create failed status=%s",
- opus_strerror(status));
- notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- return;
- }
- status =
- opus_multistream_decoder_ctl(mDecoder,
- OPUS_SET_GAIN(mHeader->gain_db));
- if (status != OPUS_OK) {
- ALOGV("Failed to set OPUS header gain; status=%s",
- opus_strerror(status));
- notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- return;
- }
- } else if (mInputBufferCount == 1) {
- mCodecDelay = ns_to_samples(
- *(reinterpret_cast<int64_t*>(header->pBuffer +
- header->nOffset)),
- kRate);
- mSamplesToDiscard = mCodecDelay;
- } else {
- mSeekPreRoll = ns_to_samples(
- *(reinterpret_cast<int64_t*>(header->pBuffer +
- header->nOffset)),
- kRate);
- notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
- mOutputPortSettingsChange = AWAITING_DISABLED;
- }
-
- inQueue.erase(inQueue.begin());
- info->mOwnedByUs = false;
- notifyEmptyBufferDone(header);
- ++mInputBufferCount;
- return;
- }
-
- while (!inQueue.empty() && !outQueue.empty()) {
+ while (!mHaveEOS && !inQueue.empty() && !outQueue.empty()) {
BufferInfo *inInfo = *inQueue.begin();
OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
- // Ignore CSD re-submissions.
- if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+ if (mInputBufferCount < 3) {
+ const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
+ size_t size = inHeader->nFilledLen;
+
+ if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && size == 0) {
+ handleEOS();
+ return;
+ }
+
+ if (mInputBufferCount == 0) {
+ CHECK(mHeader == NULL);
+ mHeader = new OpusHeader();
+ memset(mHeader, 0, sizeof(*mHeader));
+ if (!ParseOpusHeader(data, size, mHeader)) {
+ ALOGV("Parsing Opus Header failed.");
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ return;
+ }
+
+ uint8_t channel_mapping[kMaxChannels] = {0};
+ if (mHeader->channels <= kMaxChannelsWithDefaultLayout) {
+ memcpy(&channel_mapping,
+ kDefaultOpusChannelLayout,
+ kMaxChannelsWithDefaultLayout);
+ } else {
+ memcpy(&channel_mapping,
+ mHeader->stream_map,
+ mHeader->channels);
+ }
+
+ int status = OPUS_INVALID_STATE;
+ mDecoder = opus_multistream_decoder_create(kRate,
+ mHeader->channels,
+ mHeader->num_streams,
+ mHeader->num_coupled,
+ channel_mapping,
+ &status);
+ if (!mDecoder || status != OPUS_OK) {
+ ALOGV("opus_multistream_decoder_create failed status=%s",
+ opus_strerror(status));
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ return;
+ }
+ status =
+ opus_multistream_decoder_ctl(mDecoder,
+ OPUS_SET_GAIN(mHeader->gain_db));
+ if (status != OPUS_OK) {
+ ALOGV("Failed to set OPUS header gain; status=%s",
+ opus_strerror(status));
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ return;
+ }
+ } else if (mInputBufferCount == 1) {
+ mCodecDelay = ns_to_samples(
+ *(reinterpret_cast<int64_t*>(inHeader->pBuffer +
+ inHeader->nOffset)),
+ kRate);
+ mSamplesToDiscard = mCodecDelay;
+ } else {
+ mSeekPreRoll = ns_to_samples(
+ *(reinterpret_cast<int64_t*>(inHeader->pBuffer +
+ inHeader->nOffset)),
+ kRate);
+ notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+ mOutputPortSettingsChange = AWAITING_DISABLED;
+ }
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ handleEOS();
+ return;
+ }
+
inQueue.erase(inQueue.begin());
inInfo->mOwnedByUs = false;
notifyEmptyBufferDone(inHeader);
- return;
+ ++mInputBufferCount;
+
+ continue;
+ }
+
+ // Ignore CSD re-submissions.
+ if (mInputBufferCount >= 3 && (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ handleEOS();
+ return;
+ }
+
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+ continue;
}
BufferInfo *outInfo = *outQueue.begin();
OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) {
- inQueue.erase(inQueue.begin());
- inInfo->mOwnedByUs = false;
- notifyEmptyBufferDone(inHeader);
-
- outHeader->nFilledLen = 0;
- outHeader->nFlags = OMX_BUFFERFLAG_EOS;
-
- outQueue.erase(outQueue.begin());
- outInfo->mOwnedByUs = false;
- notifyFillBufferDone(outHeader);
+ handleEOS();
return;
}
@@ -490,7 +568,6 @@
}
outHeader->nFilledLen = numFrames * sizeof(int16_t) * mHeader->channels;
- outHeader->nFlags = 0;
outHeader->nTimeStamp = mAnchorTimeUs +
(mNumFramesOutput * 1000000ll) /
@@ -499,22 +576,20 @@
mNumFramesOutput += numFrames;
if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
- inHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ mHaveEOS = true;
} else {
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
+ outHeader->nFlags = 0;
}
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ notifyEmptyBufferDone(inHeader);
+ ++mInputBufferCount;
+
outInfo->mOwnedByUs = false;
outQueue.erase(outQueue.begin());
- outInfo = NULL;
notifyFillBufferDone(outHeader);
- outHeader = NULL;
-
- ++mInputBufferCount;
}
}
@@ -526,6 +601,7 @@
opus_multistream_decoder_ctl(mDecoder, OPUS_RESET_STATE);
mAnchorTimeUs = 0;
mSamplesToDiscard = mSeekPreRoll;
+ mHaveEOS = false;
}
}
@@ -542,6 +618,7 @@
}
mOutputPortSettingsChange = NONE;
+ mHaveEOS = false;
}
void SoftOpus::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.h b/media/libstagefright/codecs/opus/dec/SoftOpus.h
index 97f6561..91cafa1 100644
--- a/media/libstagefright/codecs/opus/dec/SoftOpus.h
+++ b/media/libstagefright/codecs/opus/dec/SoftOpus.h
@@ -23,7 +23,7 @@
#define SOFT_OPUS_H_
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
struct OpusMSDecoder;
@@ -75,6 +75,7 @@
int64_t mSamplesToDiscard;
int64_t mAnchorTimeUs;
int64_t mNumFramesOutput;
+ bool mHaveEOS;
enum {
NONE,
@@ -85,6 +86,7 @@
void initPorts();
status_t initDecoder();
bool isConfigured() const;
+ void handleEOS();
DISALLOW_EVIL_CONSTRUCTORS(SoftOpus);
};
diff --git a/media/libstagefright/codecs/raw/Android.bp b/media/libstagefright/codecs/raw/Android.bp
index c64027b..f21d46f 100644
--- a/media/libstagefright/codecs/raw/Android.bp
+++ b/media/libstagefright/codecs/raw/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_soft_rawdec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["SoftRaw.cpp"],
@@ -27,4 +31,5 @@
"libutils",
"liblog",
],
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/raw/SoftRaw.cpp b/media/libstagefright/codecs/raw/SoftRaw.cpp
index acb2b37..1a527b3 100644
--- a/media/libstagefright/codecs/raw/SoftRaw.cpp
+++ b/media/libstagefright/codecs/raw/SoftRaw.cpp
@@ -60,7 +60,7 @@
def.eDir = OMX_DirInput;
def.nBufferCountMin = kNumBuffers;
def.nBufferCountActual = def.nBufferCountMin;
- def.nBufferSize = 32 * 1024;
+ def.nBufferSize = 64 * 1024;
def.bEnabled = OMX_TRUE;
def.bPopulated = OMX_FALSE;
def.eDomain = OMX_PortDomainAudio;
@@ -78,7 +78,7 @@
def.eDir = OMX_DirOutput;
def.nBufferCountMin = kNumBuffers;
def.nBufferCountActual = def.nBufferCountMin;
- def.nBufferSize = 32 * 1024;
+ def.nBufferSize = 64 * 1024;
def.bEnabled = OMX_TRUE;
def.bPopulated = OMX_FALSE;
def.eDomain = OMX_PortDomainAudio;
@@ -100,6 +100,28 @@
OMX_ERRORTYPE SoftRaw::internalGetParameter(
OMX_INDEXTYPE index, OMX_PTR params) {
switch (index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding = OMX_AUDIO_CodingPCM;
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioPcm:
{
OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
@@ -153,6 +175,26 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->eEncoding != OMX_AUDIO_CodingPCM) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioPcm:
{
const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
diff --git a/media/libstagefright/codecs/raw/SoftRaw.h b/media/libstagefright/codecs/raw/SoftRaw.h
index 80906b4..ebc2741 100644
--- a/media/libstagefright/codecs/raw/SoftRaw.h
+++ b/media/libstagefright/codecs/raw/SoftRaw.h
@@ -18,7 +18,7 @@
#define SOFT_RAW_H_
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
struct tPVMP4AudioDecoderExternal;
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.bp b/media/libstagefright/codecs/vorbis/dec/Android.bp
index 1a4de60..628b36c 100644
--- a/media/libstagefright/codecs/vorbis/dec/Android.bp
+++ b/media/libstagefright/codecs/vorbis/dec/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_soft_vorbisdec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["SoftVorbis.cpp"],
@@ -10,7 +14,7 @@
shared_libs: [
"libvorbisidec",
- "libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libstagefright_foundation",
"libutils",
@@ -25,4 +29,5 @@
"unsigned-integer-overflow",
],
},
+ compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index 14dd250..8912f8a 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -129,6 +129,30 @@
OMX_ERRORTYPE SoftVorbis::internalGetParameter(
OMX_INDEXTYPE index, OMX_PTR params) {
switch (index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding =
+ (formatParams->nPortIndex == 0)
+ ? OMX_AUDIO_CodingVORBIS : OMX_AUDIO_CodingPCM;
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioVorbis:
{
OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams =
@@ -221,6 +245,29 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if ((formatParams->nPortIndex == 0
+ && formatParams->eEncoding != OMX_AUDIO_CodingVORBIS)
+ || (formatParams->nPortIndex == 1
+ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioVorbis:
{
const OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams =
@@ -262,7 +309,33 @@
oggpack_readinit(bits, ref);
}
-void SoftVorbis::onQueueFilled(OMX_U32 portIndex) {
+void SoftVorbis::handleEOS() {
+ List<BufferInfo *> &inQueue = getPortQueue(0);
+ List<BufferInfo *> &outQueue = getPortQueue(1);
+
+ CHECK(!inQueue.empty() && !outQueue.empty());
+
+ mSawInputEos = true;
+
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+ mSignalledOutputEos = true;
+
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+ ++mInputBufferCount;
+}
+
+void SoftVorbis::onQueueFilled(OMX_U32 /* portIndex */) {
List<BufferInfo *> &inQueue = getPortQueue(0);
List<BufferInfo *> &outQueue = getPortQueue(1);
@@ -270,69 +343,7 @@
return;
}
- if (portIndex == 0 && mInputBufferCount < 2) {
- BufferInfo *info = *inQueue.begin();
- OMX_BUFFERHEADERTYPE *header = info->mHeader;
-
- const uint8_t *data = header->pBuffer + header->nOffset;
- size_t size = header->nFilledLen;
- if (size < 7) {
- ALOGE("Too small input buffer: %zu bytes", size);
- android_errorWriteLog(0x534e4554, "27833616");
- notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- mSignalledError = true;
- return;
- }
-
- ogg_buffer buf;
- ogg_reference ref;
- oggpack_buffer bits;
-
- makeBitReader(
- (const uint8_t *)data + 7, size - 7,
- &buf, &ref, &bits);
-
- if (mInputBufferCount == 0) {
- CHECK(mVi == NULL);
- mVi = new vorbis_info;
- vorbis_info_init(mVi);
-
- int ret = _vorbis_unpack_info(mVi, &bits);
- if (ret != 0) {
- notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
- mSignalledError = true;
- return;
- }
- } else {
- int ret = _vorbis_unpack_books(mVi, &bits);
- if (ret != 0) {
- notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
- mSignalledError = true;
- return;
- }
-
- CHECK(mState == NULL);
- mState = new vorbis_dsp_state;
- CHECK_EQ(0, vorbis_dsp_init(mState, mVi));
-
- if (mVi->rate != kDefaultSamplingRate ||
- mVi->channels != kDefaultChannelCount) {
- ALOGV("vorbis: rate/channels changed: %ld/%d", mVi->rate, mVi->channels);
- notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
- mOutputPortSettingsChange = AWAITING_DISABLED;
- }
- }
-
- inQueue.erase(inQueue.begin());
- info->mOwnedByUs = false;
- notifyEmptyBufferDone(header);
-
- ++mInputBufferCount;
-
- return;
- }
-
- while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
+ while (!mSignalledOutputEos && (!inQueue.empty() || mSawInputEos) && !outQueue.empty()) {
BufferInfo *inInfo = NULL;
OMX_BUFFERHEADERTYPE *inHeader = NULL;
if (!inQueue.empty()) {
@@ -346,6 +357,73 @@
int32_t numPageSamples = 0;
if (inHeader) {
+ if (mInputBufferCount < 2) {
+ const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
+ size_t size = inHeader->nFilledLen;
+
+ if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && size == 0) {
+ handleEOS();
+ return;
+ }
+
+ if (size < 7) {
+ ALOGE("Too small input buffer: %zu bytes", size);
+ android_errorWriteLog(0x534e4554, "27833616");
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
+
+ ogg_buffer buf;
+ ogg_reference ref;
+ oggpack_buffer bits;
+
+ makeBitReader((const uint8_t *)data + 7, size - 7, &buf, &ref, &bits);
+
+ if (mInputBufferCount == 0) {
+ CHECK(mVi == NULL);
+ mVi = new vorbis_info;
+ vorbis_info_init(mVi);
+
+ int ret = _vorbis_unpack_info(mVi, &bits);
+ if (ret != 0) {
+ notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
+ mSignalledError = true;
+ return;
+ }
+ } else {
+ int ret = _vorbis_unpack_books(mVi, &bits);
+ if (ret != 0) {
+ notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
+ mSignalledError = true;
+ return;
+ }
+
+ CHECK(mState == NULL);
+ mState = new vorbis_dsp_state;
+ CHECK_EQ(0, vorbis_dsp_init(mState, mVi));
+
+ if (mVi->rate != kDefaultSamplingRate ||
+ mVi->channels != kDefaultChannelCount) {
+ ALOGV("vorbis: rate/channels changed: %ld/%d", mVi->rate, mVi->channels);
+ notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+ mOutputPortSettingsChange = AWAITING_DISABLED;
+ }
+ }
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ handleEOS();
+ return;
+ }
+
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+ ++mInputBufferCount;
+
+ continue;
+ }
+
if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
mSawInputEos = true;
}
@@ -359,8 +437,7 @@
return;
}
memcpy(&numPageSamples,
- inHeader->pBuffer
- + inHeader->nOffset + inHeader->nFilledLen - 4,
+ inHeader->pBuffer + inHeader->nOffset + inHeader->nFilledLen - 4,
sizeof(numPageSamples));
if (inHeader->nOffset == 0) {
@@ -399,6 +476,14 @@
int numFrames = 0;
outHeader->nFlags = 0;
+
+ if (mState == nullptr || mVi == nullptr) {
+ notify(OMX_EventError, OMX_ErrorStreamCorrupt, 0, NULL);
+ mSignalledError = true;
+ ALOGE("onQueueFilled, input does not have CSD");
+ return;
+ }
+
int err = vorbis_dsp_synthesis(mState, &pack, 1);
if (err != 0) {
// FIXME temporary workaround for log spam
@@ -448,18 +533,13 @@
if (inHeader) {
inInfo->mOwnedByUs = false;
inQueue.erase(inQueue.begin());
- inInfo = NULL;
notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
+ ++mInputBufferCount;
}
outInfo->mOwnedByUs = false;
outQueue.erase(outQueue.begin());
- outInfo = NULL;
notifyFillBufferDone(outHeader);
- outHeader = NULL;
-
- ++mInputBufferCount;
}
}
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
index 30d137b..5ff8ea4 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
@@ -18,7 +18,7 @@
#define SOFT_VORBIS_H_
-#include "SimpleSoftOMXComponent.h"
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
struct vorbis_dsp_state;
struct vorbis_info;
@@ -72,6 +72,7 @@
void initPorts();
status_t initDecoder();
bool isConfigured() const;
+ void handleEOS();
DISALLOW_EVIL_CONSTRUCTORS(SoftVorbis);
};
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 3ca7cc0..0982006 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -23,6 +23,7 @@
#include <media/stagefright/MediaErrors.h>
#include "libyuv/convert_from.h"
+#include "libyuv/video_common.h"
#define USE_LIBYUV
@@ -41,17 +42,17 @@
}
bool ColorConverter::isValid() const {
- if (mDstFormat != OMX_COLOR_Format16bitRGB565) {
- return false;
- }
-
switch (mSrcFormat) {
case OMX_COLOR_FormatYUV420Planar:
+ return mDstFormat == OMX_COLOR_Format16bitRGB565
+ || mDstFormat == OMX_COLOR_Format32BitRGBA8888
+ || mDstFormat == OMX_COLOR_Format32bitBGRA8888;
+
case OMX_COLOR_FormatCbYCrY:
case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
case OMX_COLOR_FormatYUV420SemiPlanar:
case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
- return true;
+ return mDstFormat == OMX_COLOR_Format16bitRGB565;
default:
return false;
@@ -62,14 +63,43 @@
void *bits,
size_t width, size_t height,
size_t cropLeft, size_t cropTop,
- size_t cropRight, size_t cropBottom)
+ size_t cropRight, size_t cropBottom,
+ OMX_COLOR_FORMATTYPE colorFromat)
: mBits(bits),
+ mColorFormat(colorFromat),
mWidth(width),
mHeight(height),
mCropLeft(cropLeft),
mCropTop(cropTop),
mCropRight(cropRight),
mCropBottom(cropBottom) {
+ switch(mColorFormat) {
+ case OMX_COLOR_Format16bitRGB565:
+ mBpp = 2;
+ mStride = 2 * mWidth;
+ break;
+
+ case OMX_COLOR_Format32bitBGRA8888:
+ case OMX_COLOR_Format32BitRGBA8888:
+ mBpp = 4;
+ mStride = 4 * mWidth;
+ break;
+
+ case OMX_COLOR_FormatYUV420Planar:
+ case OMX_COLOR_FormatCbYCrY:
+ case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
+ case OMX_COLOR_FormatYUV420SemiPlanar:
+ case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
+ mBpp = 1;
+ mStride = mWidth;
+ break;
+
+ default:
+ ALOGE("Unsupported color format %d", mColorFormat);
+ mBpp = 1;
+ mStride = mWidth;
+ break;
+ }
}
size_t ColorConverter::BitmapParams::cropWidth() const {
@@ -89,19 +119,15 @@
size_t dstWidth, size_t dstHeight,
size_t dstCropLeft, size_t dstCropTop,
size_t dstCropRight, size_t dstCropBottom) {
- if (mDstFormat != OMX_COLOR_Format16bitRGB565) {
- return ERROR_UNSUPPORTED;
- }
-
BitmapParams src(
const_cast<void *>(srcBits),
srcWidth, srcHeight,
- srcCropLeft, srcCropTop, srcCropRight, srcCropBottom);
+ srcCropLeft, srcCropTop, srcCropRight, srcCropBottom, mSrcFormat);
BitmapParams dst(
dstBits,
dstWidth, dstHeight,
- dstCropLeft, dstCropTop, dstCropRight, dstCropBottom);
+ dstCropLeft, dstCropTop, dstCropRight, dstCropBottom, mDstFormat);
status_t err;
@@ -212,26 +238,104 @@
return ERROR_UNSUPPORTED;
}
- uint16_t *dst_ptr = (uint16_t *)dst.mBits
- + dst.mCropTop * dst.mWidth + dst.mCropLeft;
+ uint8_t *dst_ptr = (uint8_t *)dst.mBits
+ + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
const uint8_t *src_y =
- (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
+ (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft;
const uint8_t *src_u =
- (const uint8_t *)src_y + src.mWidth * src.mHeight
- + src.mCropTop * (src.mWidth / 2) + src.mCropLeft / 2;
+ (const uint8_t *)src.mBits + src.mStride * src.mHeight
+ + (src.mCropTop / 2) * (src.mStride / 2) + (src.mCropLeft / 2);
const uint8_t *src_v =
- src_u + (src.mWidth / 2) * (src.mHeight / 2);
+ src_u + (src.mStride / 2) * (src.mHeight / 2);
+ switch (mDstFormat) {
+ case OMX_COLOR_Format16bitRGB565:
+ libyuv::I420ToRGB565(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
+ (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
+ break;
- libyuv::I420ToRGB565(src_y, src.mWidth, src_u, src.mWidth / 2, src_v, src.mWidth / 2,
- (uint8 *)dst_ptr, dst.mWidth * 2, dst.mWidth, dst.mHeight);
+ case OMX_COLOR_Format32BitRGBA8888:
+ libyuv::ConvertFromI420(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
+ (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight(), libyuv::FOURCC_ABGR);
+ break;
+
+ case OMX_COLOR_Format32bitBGRA8888:
+ libyuv::ConvertFromI420(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
+ (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight(), libyuv::FOURCC_ARGB);
+ break;
+
+ default:
+ return ERROR_UNSUPPORTED;
+ }
return OK;
}
+void ColorConverter::writeToDst(
+ void *dst_ptr, uint8_t *kAdjustedClip, bool uncropped,
+ signed r1, signed g1, signed b1,
+ signed r2, signed g2, signed b2) {
+ switch (mDstFormat) {
+ case OMX_COLOR_Format16bitRGB565:
+ {
+ uint32_t rgb1 =
+ ((kAdjustedClip[r1] >> 3) << 11)
+ | ((kAdjustedClip[g1] >> 2) << 5)
+ | (kAdjustedClip[b1] >> 3);
+
+ if (uncropped) {
+ uint32_t rgb2 =
+ ((kAdjustedClip[r2] >> 3) << 11)
+ | ((kAdjustedClip[g2] >> 2) << 5)
+ | (kAdjustedClip[b2] >> 3);
+
+ *(uint32_t *)dst_ptr = (rgb2 << 16) | rgb1;
+ } else {
+ *(uint16_t *)dst_ptr = rgb1;
+ }
+ break;
+ }
+ case OMX_COLOR_Format32BitRGBA8888:
+ {
+ ((uint32_t *)dst_ptr)[0] =
+ (kAdjustedClip[r1])
+ | (kAdjustedClip[g1] << 8)
+ | (kAdjustedClip[b1] << 16)
+ | (0xFF << 24);
+
+ if (uncropped) {
+ ((uint32_t *)dst_ptr)[1] =
+ (kAdjustedClip[r2])
+ | (kAdjustedClip[g2] << 8)
+ | (kAdjustedClip[b2] << 16)
+ | (0xFF << 24);
+ }
+ break;
+ }
+ case OMX_COLOR_Format32bitBGRA8888:
+ {
+ ((uint32_t *)dst_ptr)[0] =
+ (kAdjustedClip[b1])
+ | (kAdjustedClip[g1] << 8)
+ | (kAdjustedClip[r1] << 16)
+ | (0xFF << 24);
+
+ if (uncropped) {
+ ((uint32_t *)dst_ptr)[1] =
+ (kAdjustedClip[b2])
+ | (kAdjustedClip[g2] << 8)
+ | (kAdjustedClip[r2] << 16)
+ | (0xFF << 24);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
status_t ColorConverter::convertYUV420Planar(
const BitmapParams &src, const BitmapParams &dst) {
if (!((src.mCropLeft & 1) == 0
@@ -242,18 +346,18 @@
uint8_t *kAdjustedClip = initClip();
- uint16_t *dst_ptr = (uint16_t *)dst.mBits
- + dst.mCropTop * dst.mWidth + dst.mCropLeft;
+ uint8_t *dst_ptr = (uint8_t *)dst.mBits
+ + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
const uint8_t *src_y =
- (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
+ (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft;
const uint8_t *src_u =
- (const uint8_t *)src_y + src.mWidth * src.mHeight
- + src.mCropTop * (src.mWidth / 2) + src.mCropLeft / 2;
+ (const uint8_t *)src.mBits + src.mStride * src.mHeight
+ + (src.mCropTop / 2) * (src.mStride / 2) + src.mCropLeft / 2;
const uint8_t *src_v =
- src_u + (src.mWidth / 2) * (src.mHeight / 2);
+ src_u + (src.mStride / 2) * (src.mHeight / 2);
for (size_t y = 0; y < src.cropHeight(); ++y) {
for (size_t x = 0; x < src.cropWidth(); x += 2) {
@@ -296,31 +400,19 @@
signed g2 = (tmp2 + v_g + u_g) / 256;
signed r2 = (tmp2 + v_r) / 256;
- uint32_t rgb1 =
- ((kAdjustedClip[r1] >> 3) << 11)
- | ((kAdjustedClip[g1] >> 2) << 5)
- | (kAdjustedClip[b1] >> 3);
-
- uint32_t rgb2 =
- ((kAdjustedClip[r2] >> 3) << 11)
- | ((kAdjustedClip[g2] >> 2) << 5)
- | (kAdjustedClip[b2] >> 3);
-
- if (x + 1 < src.cropWidth()) {
- *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
- } else {
- dst_ptr[x] = rgb1;
- }
+ bool uncropped = x + 1 < src.cropWidth();
+ (void)writeToDst(dst_ptr + x * dst.mBpp,
+ kAdjustedClip, uncropped, r1, g1, b1, r2, g2, b2);
}
- src_y += src.mWidth;
+ src_y += src.mStride;
if (y & 1) {
- src_u += src.mWidth / 2;
- src_v += src.mWidth / 2;
+ src_u += src.mStride / 2;
+ src_v += src.mStride / 2;
}
- dst_ptr += dst.mWidth;
+ dst_ptr += dst.mStride;
}
return OK;
diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml
index ce164a2..829f403 100644
--- a/media/libstagefright/data/media_codecs_google_video.xml
+++ b/media/libstagefright/data/media_codecs_google_video.xml
@@ -34,20 +34,21 @@
<Feature name="adaptive-playback" />
</MediaCodec>
<MediaCodec name="OMX.google.h264.decoder" type="video/avc">
- <!-- profiles and levels: ProfileHigh : Level41 -->
- <Limit name="size" min="16x16" max="1920x1088" />
+ <!-- profiles and levels: ProfileHigh : Level52 -->
+ <Limit name="size" min="2x2" max="4080x4080" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
- <Limit name="blocks-per-second" range="1-244800" />
- <Limit name="bitrate" range="1-12000000" />
+ <Limit name="block-count" range="1-32768" /> <!-- max 4096x2048 equivalent -->
+ <Limit name="blocks-per-second" range="1-1966080" />
+ <Limit name="bitrate" range="1-48000000" />
<Feature name="adaptive-playback" />
</MediaCodec>
<MediaCodec name="OMX.google.hevc.decoder" type="video/hevc">
<!-- profiles and levels: ProfileMain : MainTierLevel51 -->
- <Limit name="size" min="2x2" max="2048x2048" />
+ <Limit name="size" min="2x2" max="4096x4096" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="8x8" />
- <Limit name="block-count" range="1-139264" />
+ <Limit name="block-count" range="1-196608" /> <!-- max 4096x3072 -->
<Limit name="blocks-per-second" range="1-2000000" />
<Limit name="bitrate" range="1-10000000" />
<Feature name="adaptive-playback" />
@@ -56,6 +57,7 @@
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
+ <Limit name="block-count" range="1-16384" />
<Limit name="blocks-per-second" range="1-1000000" />
<Limit name="bitrate" range="1-40000000" />
<Feature name="adaptive-playback" />
@@ -64,6 +66,7 @@
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
+ <Limit name="block-count" range="1-16384" />
<Limit name="blocks-per-second" range="1-500000" />
<Limit name="bitrate" range="1-40000000" />
<Feature name="adaptive-playback" />
@@ -79,10 +82,11 @@
</MediaCodec>
<MediaCodec name="OMX.google.h264.encoder" type="video/avc">
<!-- profiles and levels: ProfileBaseline : Level41 -->
- <Limit name="size" min="16x16" max="1920x1088" />
+ <Limit name="size" min="16x16" max="2048x2048" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
- <Limit name="blocks-per-second" range="1-244800" />
+ <Limit name="block-count" range="1-8192" /> <!-- max 2048x1024 -->
+ <Limit name="blocks-per-second" range="1-245760" />
<Limit name="bitrate" range="1-12000000" />
<Feature name="intra-refresh" />
</MediaCodec>
@@ -98,6 +102,9 @@
<!-- profiles and levels: ProfileMain : Level_Version0-3 -->
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
+ <Limit name="block-size" value="16x16" />
+ <!-- 2016 devices can encode at about 10fps at this block count -->
+ <Limit name="block-count" range="1-16384" />
<Limit name="bitrate" range="1-40000000" />
<Feature name="bitrate-modes" value="VBR,CBR" />
</MediaCodec>
@@ -105,6 +112,9 @@
<!-- profiles and levels: ProfileMain : Level_Version0-3 -->
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
+ <Limit name="block-size" value="16x16" />
+ <!-- 2016 devices can encode at about 8fps at this block count -->
+ <Limit name="block-count" range="1-3600" /> <!-- max 1280x720 -->
<Limit name="bitrate" range="1-40000000" />
<Feature name="bitrate-modes" value="VBR,CBR" />
</MediaCodec>
diff --git a/media/libstagefright/data/media_codecs_google_video_le.xml b/media/libstagefright/data/media_codecs_google_video_le.xml
index 034a038..d7c6570 100644
--- a/media/libstagefright/data/media_codecs_google_video_le.xml
+++ b/media/libstagefright/data/media_codecs_google_video_le.xml
@@ -34,22 +34,22 @@
<Feature name="adaptive-playback" />
</MediaCodec>
<MediaCodec name="OMX.google.h264.decoder" type="video/avc">
- <!-- profiles and levels: ProfileBaseline : Level51 -->
+ <!-- profiles and levels: ProfileHigh : Level51 -->
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
- <Limit name="block-count" range="1-8160" />
- <Limit name="blocks-per-second" range="1-489600" />
+ <Limit name="block-count" range="1-16384" />
+ <Limit name="blocks-per-second" range="1-491520" />
<Limit name="bitrate" range="1-40000000" />
<Feature name="adaptive-playback" />
</MediaCodec>
<MediaCodec name="OMX.google.hevc.decoder" type="video/hevc">
<!-- profiles and levels: ProfileMain : MainTierLevel51 -->
- <Limit name="size" min="2x2" max="1280x1280" />
+ <Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="8x8" />
- <Limit name="block-count" range="1-139264" />
- <Limit name="blocks-per-second" range="1-432000" />
+ <Limit name="block-count" range="1-65536" />
+ <Limit name="blocks-per-second" range="1-491520" />
<Limit name="bitrate" range="1-5000000" />
<Feature name="adaptive-playback" />
</MediaCodec>
@@ -57,7 +57,7 @@
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
- <Limit name="block-count" range="1-8160" />
+ <Limit name="block-count" range="1-8192" /> <!-- max 2048x1024 -->
<Limit name="blocks-per-second" range="1-500000" />
<Limit name="bitrate" range="1-40000000" />
<Feature name="adaptive-playback" />
@@ -66,7 +66,7 @@
<Limit name="size" min="2x2" max="1280x1280" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
- <Limit name="block-count" range="1-3600" />
+ <Limit name="block-count" range="1-3600" /> <!-- max 1280x720 -->
<Limit name="blocks-per-second" range="1-108000" />
<Limit name="bitrate" range="1-5000000" />
<Feature name="adaptive-playback" />
@@ -81,12 +81,14 @@
<Limit name="bitrate" range="1-128000" />
</MediaCodec>
<MediaCodec name="OMX.google.h264.encoder" type="video/avc">
- <!-- profiles and levels: ProfileBaseline : Level2 -->
- <Limit name="size" min="16x16" max="896x896" />
- <Limit name="alignment" value="16x16" />
+ <!-- profiles and levels: ProfileBaseline : Level3 -->
+ <Limit name="size" min="16x16" max="1808x1808" />
+ <Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
- <Limit name="blocks-per-second" range="1-11880" />
+ <Limit name="block-count" range="1-1620" />
+ <Limit name="blocks-per-second" range="1-40500" />
<Limit name="bitrate" range="1-2000000" />
+ <Feature name="intra-refresh" />
</MediaCodec>
<MediaCodec name="OMX.google.mpeg4.encoder" type="video/mp4v-es">
<!-- profiles and levels: ProfileCore : Level2 -->
@@ -100,7 +102,8 @@
<!-- profiles and levels: ProfileMain : Level_Version0-3 -->
<Limit name="size" min="2x2" max="1280x1280" />
<Limit name="alignment" value="2x2" />
- <Limit name="block-count" range="1-3600" />
+ <Limit name="block-size" value="16x16" />
+ <Limit name="block-count" range="1-3600" /> <!-- max 1280x720 -->
<Limit name="bitrate" range="1-20000000" />
<Feature name="bitrate-modes" value="VBR,CBR" />
</MediaCodec>
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index 284c25f..1b9fe0f 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -1,5 +1,9 @@
cc_library_shared {
name: "libstagefright_flacdec",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: [
"FLACDecoder.cpp",
@@ -31,4 +35,5 @@
"libstagefright_foundation",
"libutils",
],
+ header_libs: ["libmedia_headers"],
}
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 91462c8..221af1d 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -1,7 +1,15 @@
+cc_library_headers {
+ name: "libstagefright_foundation_headers",
+ export_include_dirs: ["include"],
+ vendor_available: true,
+}
+
cc_library_shared {
name: "libstagefright_foundation",
vendor_available: true,
-
+ vndk: {
+ enabled: true,
+ },
include_dirs: [
"frameworks/av/include",
"frameworks/native/include",
@@ -11,12 +19,13 @@
"include/media/stagefright/foundation",
],
- export_include_dirs: [
- "include",
- ],
-
header_libs: [
"libhardware_headers",
+ "libstagefright_foundation_headers",
+ ],
+
+ export_header_lib_headers: [
+ "libstagefright_foundation_headers",
],
export_shared_lib_headers: [
diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
index cc89064..8f32582 100644
--- a/media/libstagefright/foundation/base64.cpp
+++ b/media/libstagefright/foundation/base64.cpp
@@ -23,6 +23,7 @@
sp<ABuffer> decodeBase64(const AString &s) {
size_t n = s.size();
+
if ((n % 4) != 0) {
return NULL;
}
@@ -45,7 +46,6 @@
size_t outLen = (n / 4) * 3 - padding;
sp<ABuffer> buffer = new ABuffer(outLen);
-
uint8_t *out = buffer->data();
if (out == NULL || buffer->size() < outLen) {
return NULL;
@@ -61,9 +61,9 @@
value = 26 + c - 'a';
} else if (c >= '0' && c <= '9') {
value = 52 + c - '0';
- } else if (c == '+') {
+ } else if (c == '+' || c == '-') {
value = 62;
- } else if (c == '/') {
+ } else if (c == '/' || c == '_') {
value = 63;
} else if (c != '=') {
return NULL;
@@ -144,4 +144,26 @@
}
}
+void encodeBase64Url(
+ const void *_data, size_t size, AString *out) {
+ encodeBase64(_data, size, out);
+
+ if ((-1 != out->find("+")) || (-1 != out->find("/"))) {
+ size_t outLen = out->size();
+ char *base64url = new char[outLen];
+ for (size_t i = 0; i < outLen; ++i) {
+ if (out->c_str()[i] == '+')
+ base64url[i] = '-';
+ else if (out->c_str()[i] == '/')
+ base64url[i] = '_';
+ else
+ base64url[i] = out->c_str()[i];
+ }
+
+ out->setTo(base64url, outLen);
+ delete[] base64url;
+ }
+}
+
+
} // namespace android
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
index e340b89..abc95e0 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
@@ -28,6 +28,8 @@
sp<ABuffer> decodeBase64(const AString &s);
void encodeBase64(const void *data, size_t size, AString *out);
+void encodeBase64Url(const void *data, size_t size, AString *out);
+
} // namespace android
#endif // BASE_64_H_
diff --git a/media/libstagefright/foundation/tests/Android.mk b/media/libstagefright/foundation/tests/Android.mk
index d741c6f..a9e3c76 100644
--- a/media/libstagefright/foundation/tests/Android.mk
+++ b/media/libstagefright/foundation/tests/Android.mk
@@ -9,11 +9,13 @@
LOCAL_SRC_FILES := \
AData_test.cpp \
+ Base64_test.cpp \
Flagged_test.cpp \
TypeTraits_test.cpp \
Utils_test.cpp \
LOCAL_SHARED_LIBRARIES := \
+ liblog \
libstagefright_foundation \
libutils \
diff --git a/media/libstagefright/foundation/tests/Base64_test.cpp b/media/libstagefright/foundation/tests/Base64_test.cpp
new file mode 100644
index 0000000..7a4289e
--- /dev/null
+++ b/media/libstagefright/foundation/tests/Base64_test.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <utils/Log.h>
+
+#include "gtest/gtest.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/AStringUtils.h>
+#include <media/stagefright/foundation/base64.h>
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+namespace {
+const android::String8 kBase64Padding("=");
+};
+
+namespace android {
+
+class Base64Test : public ::testing::Test {
+};
+
+void verifyDecode(const AString* expected, const AString* in) {
+ size_t numTests = 0;
+ while (!expected[numTests].empty())
+ ++numTests;
+
+ for (size_t i = 0; i < numTests; ++i) {
+ // Since android::decodeBase64() requires padding characters,
+ // add them so length of encoded text is exactly a multiple of 4.
+ int remainder = in[i].size() % 4;
+ String8 paddedText(in[i].c_str());
+ if (remainder > 0) {
+ for (int i = 0; i < 4 - remainder; ++i) {
+ paddedText.append(kBase64Padding);
+ }
+ }
+ sp<ABuffer> result = decodeBase64(AString(paddedText.string()));
+
+ ASSERT_EQ(AStringUtils::Compare(expected[i].c_str(),
+ reinterpret_cast<char*>(result->data()),
+ expected[i].size(), false), 0);
+ }
+}
+
+void verifyEncode(const AString* expected, const AString* in) {
+ size_t numTests = 0;
+ while (!expected[numTests].empty())
+ ++numTests;
+
+ AString out = AString("");
+ for (size_t i = 0; i < numTests; ++i) {
+ encodeBase64Url(in[i].c_str(), in[i].size(), &out);
+
+ ASSERT_EQ(AStringUtils::Compare(expected[i].c_str(), out.c_str(),
+ expected[i].size(), false), 0);
+ }
+}
+
+TEST_F(Base64Test, TestDecodeBase64) {
+ const AString base64[] = {
+ AString("SGVsbG8gRnJpZW5kIQ"),
+ AString("R29vZCBkYXkh"),
+ AString("") // string to signal end of array
+ };
+
+ const AString clearText[] = {
+ AString("Hello Friend!"),
+ AString("Good day!"),
+ AString("")
+ };
+
+ verifyDecode(clearText, base64);
+}
+
+TEST_F(Base64Test, TestDecodeBase64Url) {
+ const AString base64Url[] = {
+ AString("SGVsbG8gRnJpZW5kICE-Pw"),
+ AString("SGVsbG8gRnJpZW5kICE_"),
+ AString("SGVsbG8gPz4-IEZyaWVuZCA_Pg"),
+ AString("")
+ };
+
+ const AString clearText[] = {
+ AString("Hello Friend !>?"),
+ AString("Hello Friend !?"),
+ AString("Hello ?>> Friend ?>"),
+ AString("")
+ };
+
+ verifyDecode(clearText, base64Url);
+}
+
+TEST_F(Base64Test, TestDecodeMalformedBase64) {
+ const AString base64Url[] = {
+ AString("1?GawgguFyGrWKav7AX4VKUg"), // fail on parsing
+ AString("GawgguFyGrWKav7AX4V???"), // fail on length not multiple of 4
+ AString("GawgguFyGrWKav7AX4VKUg"), // ditto
+ };
+
+ for (size_t i = 0; i < 3; ++i) {
+ sp<ABuffer> result = decodeBase64(AString(base64Url[i]));
+ EXPECT_TRUE(result == nullptr);
+ }
+}
+
+TEST_F(Base64Test, TestEncodeBase64) {
+ const AString clearText[] = {
+ AString("Hello Friend!"),
+ AString("Good day!"),
+ AString("")
+ };
+
+ const AString base64[] = {
+ AString("SGVsbG8gRnJpZW5kIQ=="),
+ AString("R29vZCBkYXkh"),
+ AString("")
+ };
+
+ verifyEncode(base64, clearText);
+}
+
+TEST_F(Base64Test, TestEncodeBase64Url) {
+ const AString clearText[] = {
+ AString("Hello Friend !>?"),
+ AString("Hello Friend !?"),
+ AString("Hello ?>> Friend ?>"),
+ AString("")
+ };
+
+ const AString base64Url[] = {
+ AString("SGVsbG8gRnJpZW5kICE-Pw=="),
+ AString("SGVsbG8gRnJpZW5kICE_"),
+ AString("SGVsbG8gPz4-IEZyaWVuZCA_Pg"),
+ AString("")
+ };
+
+ verifyEncode(base64Url, clearText);
+}
+
+} // namespace android
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index 0da2e81..f253a52 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -30,6 +30,8 @@
namespace android {
+using hardware::hidl_memory;
+
/**
* BufferChannelBase implementation for ACodec.
*/
@@ -117,6 +119,7 @@
sp<MemoryDealer> mDealer;
sp<IMemory> mDecryptDestination;
int32_t mHeapSeqNum;
+ hidl_memory mHidlMemory;
// These should only be accessed via std::atomic_* functions.
//
diff --git a/media/libstagefright/include/ItemTable.h b/media/libstagefright/include/ItemTable.h
new file mode 100644
index 0000000..5a6af5e
--- /dev/null
+++ b/media/libstagefright/include/ItemTable.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 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 ITEM_TABLE_H_
+#define ITEM_TABLE_H_
+
+#include <set>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class DataSource;
+class MetaData;
+
+namespace heif {
+
+struct AssociationEntry;
+struct ImageItem;
+struct ItemLoc;
+struct ItemInfo;
+struct ItemProperty;
+struct ItemReference;
+
+/*
+ * ItemTable keeps track of all image items (including coded images, grids and
+ * tiles) inside a HEIF still image (ISO/IEC FDIS 23008-12.2:2017(E)).
+ */
+
+class ItemTable : public RefBase {
+public:
+ explicit ItemTable(const sp<DataSource> &source);
+
+ status_t parse(uint32_t type, off64_t offset, size_t size);
+
+ bool isValid() { return mImageItemsValid; }
+ sp<MetaData> getImageMeta();
+ uint32_t countImages() const;
+ status_t findPrimaryImage(uint32_t *imageIndex);
+ status_t findThumbnail(uint32_t *thumbnailIndex);
+ status_t getImageOffsetAndSize(
+ uint32_t *imageIndex, off64_t *offset, size_t *size);
+
+protected:
+ ~ItemTable();
+
+private:
+ sp<DataSource> mDataSource;
+
+ KeyedVector<uint32_t, ItemLoc> mItemLocs;
+ Vector<ItemInfo> mItemInfos;
+ Vector<AssociationEntry> mAssociations;
+ Vector<sp<ItemProperty> > mItemProperties;
+ Vector<sp<ItemReference> > mItemReferences;
+
+ uint32_t mPrimaryItemId;
+ off64_t mIdatOffset;
+ size_t mIdatSize;
+
+ std::set<uint32_t> mRequiredBoxes;
+ std::set<uint32_t> mBoxesSeen;
+
+ bool mImageItemsValid;
+ uint32_t mCurrentImageIndex;
+ KeyedVector<uint32_t, ImageItem> mItemIdToImageMap;
+
+ status_t parseIlocBox(off64_t offset, size_t size);
+ status_t parseIinfBox(off64_t offset, size_t size);
+ status_t parsePitmBox(off64_t offset, size_t size);
+ status_t parseIprpBox(off64_t offset, size_t size);
+ status_t parseIdatBox(off64_t offset, size_t size);
+ status_t parseIrefBox(off64_t offset, size_t size);
+
+ void attachProperty(const AssociationEntry &association);
+ status_t buildImageItemsIfPossible(uint32_t type);
+
+ DISALLOW_EVIL_CONSTRUCTORS(ItemTable);
+};
+
+} // namespace heif
+} // namespace android
+
+#endif // ITEM_TABLE_H_
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index 2a75298..ac93b5e 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -45,7 +45,7 @@
virtual sp<MetaData> getMetaData();
- virtual status_t setMediaCas(const sp<ICas> &cas) override;
+ virtual status_t setMediaCas(const HInterfaceToken &casToken) override;
virtual uint32_t flags() const;
virtual const char * name() { return "MPEG2TSExtractor"; }
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index f847119..c9d7dde 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -28,11 +28,14 @@
#include <utils/String8.h>
namespace android {
-
struct AMessage;
class DataSource;
class SampleTable;
class String8;
+namespace heif {
+class ItemTable;
+}
+using heif::ItemTable;
struct SidxEntry {
size_t mSize;
@@ -59,6 +62,7 @@
virtual sp<MetaData> getMetaData();
virtual uint32_t flags() const;
virtual const char * name() { return "MPEG4Extractor"; }
+ virtual void release();
// for DRM
virtual char* getDrmTrackInfo(size_t trackID, int *len);
@@ -97,6 +101,7 @@
status_t mInitCheck;
uint32_t mHeaderTimescale;
bool mIsQT;
+ bool mIsHEIF;
Track *mFirstTrack, *mLastTrack;
@@ -134,6 +139,8 @@
SINF *mFirstSINF;
bool mIsDrm;
+ sp<ItemTable> mItemTable;
+
status_t parseDrmSINF(off64_t *offset, off64_t data_offset);
status_t parseTrackHeader(off64_t data_offset, off64_t data_size);
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index b7ac718..277eb3e 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -38,9 +38,9 @@
const KeyedVector<String8, String8> *headers);
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
- virtual status_t setDataSource(const sp<DataSource>& source);
+ virtual status_t setDataSource(const sp<DataSource>& source, const char *mime);
- virtual VideoFrame *getFrameAtTime(int64_t timeUs, int option);
+ virtual VideoFrame *getFrameAtTime(int64_t timeUs, int option, int colorFormat, bool metaOnly);
virtual MediaAlbumArt *extractAlbumArt();
virtual const char *extractMetadata(int keyCode);
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index d049df5..424246d 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <android/native_window.h>
#include <media/hardware/MetadataBufferType.h>
+#include <media/MediaCodecInfo.h>
#include <media/IOMX.h>
#include <media/stagefright/foundation/AHierarchicalStateMachine.h>
#include <media/stagefright/CodecBase.h>
@@ -30,6 +31,8 @@
#include <OMX_Audio.h>
#include <hardware/gralloc.h>
#include <nativebase/nativebase.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
#define TRACK_BUFFER_TIMING 0
@@ -42,20 +45,6 @@
struct DescribeColorFormat2Params;
struct DataConverter;
-// Treble shared memory
-namespace hidl {
-namespace allocator {
-namespace V1_0 {
-struct IAllocator;
-} // V1_0
-} // allocator
-namespace memory {
-namespace V1_0 {
-struct IMemory;
-} // V1_0
-} // memory
-} // hidl
-
typedef hidl::allocator::V1_0::IAllocator TAllocator;
typedef hidl::memory::V1_0::IMemory TMemory;
@@ -72,9 +61,10 @@
virtual void initiateStart();
virtual void initiateShutdown(bool keepComponentAllocated = false);
- virtual status_t queryCapabilities(
- const AString &name, const AString &mime, bool isEncoder,
- sp<MediaCodecInfo::Capabilities> *caps);
+ status_t queryCapabilities(
+ const char* owner, const char* name,
+ const char* mime, bool isEncoder,
+ MediaCodecInfo::CapabilitiesWriter* caps);
virtual status_t setSurface(const sp<Surface> &surface);
@@ -94,7 +84,8 @@
// some OMX components as auto level, and by others as invalid level.
static int /* OMX_VIDEO_AVCLEVELTYPE */ getAVCLevelFor(
int width, int height, int rate, int bitrate,
- OMX_VIDEO_AVCPROFILETYPE profile = OMX_VIDEO_AVCProfileBaseline);
+ OMX_VIDEO_AVCPROFILEEXTTYPE profile =
+ (OMX_VIDEO_AVCPROFILEEXTTYPE)OMX_VIDEO_AVCProfileBaseline);
// Quirk still supported, even though deprecated
enum Quirks {
diff --git a/media/libstagefright/include/media/stagefright/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
index 2aaa884..d6149c0 100644
--- a/media/libstagefright/include/media/stagefright/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -29,7 +29,7 @@
#include <utils/List.h>
#include <utils/RefBase.h>
#include <utils/String16.h>
-#include <MetadataBufferType.h>
+#include <media/hardware/MetadataBufferType.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index 0dd77ba..9197f7b 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -24,27 +24,31 @@
#define STRINGIFY_ENUMS
-#include <media/ICrypto.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/hardware/HardwareAPI.h>
#include <media/IOMX.h>
#include <media/MediaCodecInfo.h>
-#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/foundation/AHandler.h>
#include <media/stagefright/foundation/ColorUtils.h>
-#include <media/hardware/HardwareAPI.h>
-
+#include <media/stagefright/MediaErrors.h>
+#include <system/graphics.h>
#include <utils/NativeHandle.h>
-#include <system/graphics.h>
-#include <android/media/IDescrambler.h>
-
namespace android {
-using namespace media;
class BufferChannelBase;
struct BufferProducerWrapper;
class MediaCodecBuffer;
struct PersistentSurface;
struct RenderedFrameInfo;
class Surface;
+struct ICrypto;
+namespace hardware {
+namespace cas {
+namespace native {
+namespace V1_0 {
+struct IDescrambler;
+}}}}
+using hardware::cas::native::V1_0::IDescrambler;
struct CodecBase : public AHandler, /* static */ ColorUtils {
/**
@@ -209,10 +213,6 @@
// require an explicit message handler
virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
- virtual status_t queryCapabilities(
- const AString& /*name*/, const AString& /*mime*/, bool /*isEncoder*/,
- sp<MediaCodecInfo::Capabilities>* /*caps*/ /* nonnull */) { return INVALID_OPERATION; }
-
virtual status_t setSurface(const sp<Surface>& /*surface*/) { return INVALID_OPERATION; }
virtual void signalFlush() = 0;
@@ -256,13 +256,9 @@
mCallback = std::move(callback);
}
- inline void setCrypto(const sp<ICrypto> &crypto) {
- mCrypto = crypto;
- }
+ void setCrypto(const sp<ICrypto> &crypto);
- inline void setDescrambler(const sp<IDescrambler> &descrambler) {
- mDescrambler = descrambler;
- }
+ void setDescrambler(const sp<IDescrambler> &descrambler);
/**
* Queue an input buffer into the buffer channel.
diff --git a/media/libstagefright/include/media/stagefright/ColorConverter.h b/media/libstagefright/include/media/stagefright/ColorConverter.h
index 270c809..7ac9b37 100644
--- a/media/libstagefright/include/media/stagefright/ColorConverter.h
+++ b/media/libstagefright/include/media/stagefright/ColorConverter.h
@@ -49,14 +49,17 @@
void *bits,
size_t width, size_t height,
size_t cropLeft, size_t cropTop,
- size_t cropRight, size_t cropBottom);
+ size_t cropRight, size_t cropBottom,
+ OMX_COLOR_FORMATTYPE colorFromat);
size_t cropWidth() const;
size_t cropHeight() const;
void *mBits;
+ OMX_COLOR_FORMATTYPE mColorFormat;
size_t mWidth, mHeight;
size_t mCropLeft, mCropTop, mCropRight, mCropBottom;
+ size_t mBpp, mStride;
};
OMX_COLOR_FORMATTYPE mSrcFormat, mDstFormat;
@@ -82,6 +85,10 @@
status_t convertTIYUV420PackedSemiPlanar(
const BitmapParams &src, const BitmapParams &dst);
+ void writeToDst(void *dst_ptr, uint8_t *kAdjustedClip, bool uncropped,
+ signed r1, signed g1, signed b1,
+ signed r2, signed g2, signed b2);
+
ColorConverter(const ColorConverter &);
ColorConverter &operator=(const ColorConverter &);
};
diff --git a/media/libstagefright/include/media/stagefright/DataSource.h b/media/libstagefright/include/media/stagefright/DataSource.h
index 63eccea..bd863ba 100644
--- a/media/libstagefright/include/media/stagefright/DataSource.h
+++ b/media/libstagefright/include/media/stagefright/DataSource.h
@@ -73,6 +73,11 @@
bool getUInt32(off64_t offset, uint32_t *x);
bool getUInt64(off64_t offset, uint64_t *x);
+ // 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);
+
// Reads in "count" entries of type T into vector *x.
// Returns true if "count" entries can be read.
// If fewer than "count" entries can be read, return false. In this case,
diff --git a/media/libstagefright/include/media/stagefright/FrameRenderTracker.h b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
index 044699c..c14755a 100644
--- a/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
+++ b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
@@ -23,6 +23,8 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
#include <list>
@@ -30,9 +32,6 @@
namespace android {
-class Fence;
-class GraphicBuffer;
-
// Tracks the render information about a frame. Frames go through several states while
// the render information is tracked:
//
diff --git a/media/libstagefright/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
index dd357cc..1c7b4a6 100644
--- a/media/libstagefright/include/media/stagefright/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -204,7 +204,10 @@
void lock();
void unlock();
- void initInternal(int fd);
+ // Init all the internal variables for each recording session. Some variables
+ // will only need to be set for the first recording session and they will stay
+ // the same across all the recording sessions.
+ void initInternal(int fd, bool isFirstSession);
// Acquire lock before calling these methods
off64_t addSample_l(MediaBuffer *buffer);
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 4140266..1030407 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -47,10 +47,13 @@
struct PersistentSurface;
class SoftwareRenderer;
class Surface;
-namespace media {
-class IDescrambler;
-};
-using namespace media;
+namespace hardware {
+namespace cas {
+namespace native {
+namespace V1_0 {
+struct IDescrambler;
+}}}}
+using hardware::cas::native::V1_0::IDescrambler;
struct MediaCodec : public AHandler {
enum ConfigureFlags {
@@ -84,11 +87,6 @@
static sp<PersistentSurface> CreatePersistentInputSurface();
- // utility method to query capabilities
- static status_t QueryCapabilities(
- const AString &name, const AString &mime, bool isEncoder,
- sp<MediaCodecInfo::Capabilities> *caps /* nonnull */);
-
status_t configure(
const sp<AMessage> &format,
const sp<Surface> &nativeWindow,
@@ -316,6 +314,8 @@
SoftwareRenderer *mSoftRenderer;
MediaAnalyticsItem *mAnalyticsItem;
+ void initAnalyticsItem();
+ void flushAnalyticsItem();
sp<AMessage> mOutputFormat;
sp<AMessage> mInputFormat;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecList.h b/media/libstagefright/include/media/stagefright/MediaCodecList.h
index 430bc16..f2bd496 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecList.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecList.h
@@ -21,7 +21,6 @@
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AString.h>
#include <media/IMediaCodecList.h>
-#include <media/IOMX.h>
#include <media/MediaCodecInfo.h>
#include <sys/types.h>
@@ -36,6 +35,8 @@
struct AMessage;
+struct MediaCodecListBuilderBase;
+
struct MediaCodecList : public BnMediaCodecList {
static sp<IMediaCodecList> getInstance();
@@ -51,7 +52,7 @@
ALOGE("b/24445127");
return NULL;
}
- return mCodecInfos.itemAt(index);
+ return mCodecInfos[index];
}
virtual const sp<AMessage> getGlobalSettings() const;
@@ -62,9 +63,6 @@
// only to be used by getLocalInstance
static void *profilerThreadWrapper(void * /*arg*/);
- // only to be used by MediaPlayerService
- void parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
-
enum Flags {
kPreferSoftwareCodecs = 1,
kHardwareCodecsOnly = 2,
@@ -74,13 +72,11 @@
const char *mime,
bool createEncoder,
uint32_t flags,
- Vector<AString> *matching);
-
- static uint32_t getQuirksFor(const char *mComponentName);
+ Vector<AString> *matchingCodecs,
+ Vector<AString> *owners = nullptr);
static bool isSoftwareCodec(const AString &componentName);
-
private:
class BinderDeathObserver : public IBinder::DeathRecipient {
void binderDied(const wp<IBinder> &the_late_who __unused);
@@ -88,64 +84,86 @@
static sp<BinderDeathObserver> sBinderDeathObserver;
- enum Section {
- SECTION_TOPLEVEL,
- SECTION_SETTINGS,
- SECTION_DECODERS,
- SECTION_DECODER,
- SECTION_DECODER_TYPE,
- SECTION_ENCODERS,
- SECTION_ENCODER,
- SECTION_ENCODER_TYPE,
- SECTION_INCLUDE,
- };
-
static sp<IMediaCodecList> sCodecList;
static sp<IMediaCodecList> sRemoteList;
status_t mInitCheck;
- Section mCurrentSection;
- bool mUpdate;
- Vector<Section> mPastSections;
- int32_t mDepth;
- AString mHrefBase;
sp<AMessage> mGlobalSettings;
- KeyedVector<AString, CodecSettings> mOverrides;
+ std::vector<sp<MediaCodecInfo> > mCodecInfos;
- Vector<sp<MediaCodecInfo> > mCodecInfos;
- sp<MediaCodecInfo> mCurrentInfo;
+ /**
+ * This constructor will call `buildMediaCodecList()` from the given
+ * `MediaCodecListBuilderBase` object.
+ */
+ MediaCodecList(MediaCodecListBuilderBase* builder);
- MediaCodecList();
~MediaCodecList();
status_t initCheck() const;
- void parseXMLFile(const char *path);
- static void StartElementHandlerWrapper(
- void *me, const char *name, const char **attrs);
+ MediaCodecList(const MediaCodecList&) = delete;
+ MediaCodecList& operator=(const MediaCodecList&) = delete;
- static void EndElementHandlerWrapper(void *me, const char *name);
+ friend MediaCodecListWriter;
+};
- void startElementHandler(const char *name, const char **attrs);
- void endElementHandler(const char *name);
+/**
+ * This class is to be used by a `MediaCodecListBuilderBase` instance to add
+ * information to the associated `MediaCodecList` object.
+ */
+struct MediaCodecListWriter {
+ /**
+ * Add a key-value pair to a `MediaCodecList`'s global settings.
+ *
+ * @param key Key.
+ * @param value Value.
+ */
+ void addGlobalSetting(const char* key, const char* value);
+ /**
+ * Create an add a new `MediaCodecInfo` object to a `MediaCodecList`, and
+ * return a `MediaCodecInfoWriter` object associated with the newly added
+ * `MediaCodecInfo`.
+ *
+ * @return The `MediaCodecInfoWriter` object associated with the newly
+ * added `MediaCodecInfo` object.
+ */
+ std::unique_ptr<MediaCodecInfoWriter> addMediaCodecInfo();
+private:
+ /**
+ * The associated `MediaCodecList` object.
+ */
+ MediaCodecList* mList;
- status_t includeXMLFile(const char **attrs);
- status_t addSettingFromAttributes(const char **attrs);
- status_t addMediaCodecFromAttributes(bool encoder, const char **attrs);
- void addMediaCodec(bool encoder, const char *name, const char *type = NULL);
+ /**
+ * Construct this writer object associated with the given `MediaCodecList`
+ * object.
+ *
+ * @param list The "base" `MediaCodecList` object.
+ */
+ MediaCodecListWriter(MediaCodecList* list);
- void setCurrentCodecInfo(bool encoder, const char *name, const char *type);
+ friend MediaCodecList;
+};
- status_t addQuirk(const char **attrs);
- status_t addTypeFromAttributes(const char **attrs);
- status_t addLimit(const char **attrs);
- status_t addFeature(const char **attrs);
- void addType(const char *name);
+/**
+ * This interface is to be used by `MediaCodecList` to fill its members with
+ * appropriate information. `buildMediaCodecList()` will be called from a
+ * `MediaCodecList` object during its construction.
+ */
+struct MediaCodecListBuilderBase {
+ /**
+ * Build the `MediaCodecList` via the given `MediaCodecListWriter` interface.
+ *
+ * @param writer The writer interface.
+ * @return The status of the construction. `NO_ERROR` means success.
+ */
+ virtual status_t buildMediaCodecList(MediaCodecListWriter* writer) = 0;
- status_t initializeCapabilities(const char *type);
-
- DISALLOW_EVIL_CONSTRUCTORS(MediaCodecList);
+ /**
+ * The default destructor does nothing.
+ */
+ virtual ~MediaCodecListBuilderBase();
};
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/MediaErrors.h b/media/libstagefright/include/media/stagefright/MediaErrors.h
index 2e663ec..6a5c6b6 100644
--- a/media/libstagefright/include/media/stagefright/MediaErrors.h
+++ b/media/libstagefright/include/media/stagefright/MediaErrors.h
@@ -79,6 +79,26 @@
HEARTBEAT_ERROR_BASE = -3000,
ERROR_HEARTBEAT_TERMINATE_REQUESTED = HEARTBEAT_ERROR_BASE,
+ // CAS-related error codes
+ CAS_ERROR_BASE = -4000,
+
+ ERROR_CAS_UNKNOWN = CAS_ERROR_BASE,
+ ERROR_CAS_NO_LICENSE = CAS_ERROR_BASE - 1,
+ ERROR_CAS_LICENSE_EXPIRED = CAS_ERROR_BASE - 2,
+ ERROR_CAS_SESSION_NOT_OPENED = CAS_ERROR_BASE - 3,
+ ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED = CAS_ERROR_BASE - 4,
+ ERROR_CAS_DECRYPT = CAS_ERROR_BASE - 5,
+ ERROR_CAS_CANNOT_HANDLE = CAS_ERROR_BASE - 6,
+ ERROR_CAS_TAMPER_DETECTED = CAS_ERROR_BASE - 7,
+ ERROR_CAS_NOT_PROVISIONED = CAS_ERROR_BASE - 8,
+ ERROR_CAS_DEVICE_REVOKED = CAS_ERROR_BASE - 9,
+ ERROR_CAS_RESOURCE_BUSY = CAS_ERROR_BASE - 10,
+ ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = CAS_ERROR_BASE - 11,
+ ERROR_CAS_LAST_USED_ERRORCODE = CAS_ERROR_BASE - 11,
+
+ ERROR_CAS_VENDOR_MAX = CAS_ERROR_BASE - 500,
+ ERROR_CAS_VENDOR_MIN = CAS_ERROR_BASE - 999,
+
// NDK Error codes
// frameworks/av/include/ndk/NdkMediaError.h
// from -10000 (0xFFFFD8F0 - 0xFFFFD8EC)
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractor.h b/media/libstagefright/include/media/stagefright/MediaExtractor.h
index a856b2b..6ec7eaf 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractor.h
@@ -23,10 +23,6 @@
#include <media/MediaAnalyticsItem.h>
namespace android {
-namespace media {
-class ICas;
-};
-using namespace media;
class DataSource;
struct MediaSource;
class MetaData;
@@ -70,12 +66,14 @@
}
virtual void setUID(uid_t /*uid*/) {
}
- virtual status_t setMediaCas(const sp<ICas>& /*cas*/) override {
+ virtual status_t setMediaCas(const HInterfaceToken &/*casToken*/) override {
return INVALID_OPERATION;
}
virtual const char * name() { return "<unspecified>"; }
+ virtual void release() {}
+
protected:
MediaExtractor();
virtual ~MediaExtractor();
diff --git a/media/libstagefright/include/media/stagefright/MetaData.h b/media/libstagefright/include/media/stagefright/MetaData.h
index 9676b97..f2113f4 100644
--- a/media/libstagefright/include/media/stagefright/MetaData.h
+++ b/media/libstagefright/include/media/stagefright/MetaData.h
@@ -38,6 +38,8 @@
kKeyDisplayHeight = 'dHgt', // int32_t, display/presentation
kKeySARWidth = 'sarW', // int32_t, sampleAspectRatio width
kKeySARHeight = 'sarH', // int32_t, sampleAspectRatio height
+ kKeyThumbnailWidth = 'thbW', // int32_t, thumbnail width
+ kKeyThumbnailHeight = 'thbH', // int32_t, thumbnail height
// a rectangle, if absent assumed to be (0, 0, width - 1, height - 1)
kKeyCropRect = 'crop',
@@ -58,6 +60,7 @@
kKeyAACProfile = 'aacp', // int32_t
kKeyAVCC = 'avcc', // raw data
kKeyHVCC = 'hvcc', // raw data
+ kKeyThumbnailHVCC = 'thvc', // raw data
kKeyD263 = 'd263', // raw data
kKeyVorbisInfo = 'vinf', // raw data
kKeyVorbisBooks = 'vboo', // raw data
@@ -209,6 +212,12 @@
// color Matrix, value defined by ColorAspects.MatrixCoeffs.
kKeyTemporalLayerId = 'iLyr', // int32_t, temporal layer-id. 0-based (0 => base layer)
kKeyTemporalLayerCount = 'cLyr', // int32_t, number of temporal layers encoded
+
+ kKeyGridWidth = 'grdW', // int32_t, HEIF grid width
+ kKeyGridHeight = 'grdH', // int32_t, HEIF grid height
+ kKeyGridRows = 'grdR', // int32_t, HEIF grid rows
+ kKeyGridCols = 'grdC', // int32_t, HEIF grid columns
+ kKeyIccProfile = 'prof', // raw data, ICC prifile data
};
enum {
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 3e3cc17..6a93bd5 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -28,10 +28,6 @@
#include <utils/Vector.h>
namespace android {
-namespace media {
-class ICas;
-}
-using namespace media;
struct ABuffer;
struct AMessage;
@@ -64,7 +60,7 @@
status_t setDataSource(const sp<DataSource> &datasource);
- status_t setMediaCas(const sp<ICas> &cas);
+ status_t setMediaCas(const HInterfaceToken &casToken);
size_t countTracks() const;
status_t getTrackFormat(size_t index, sp<AMessage> *format, uint32_t flags = 0) const;
@@ -115,7 +111,7 @@
sp<DataSource> mDataSource;
sp<IMediaExtractor> mImpl;
- sp<ICas> mCas;
+ HInterfaceToken mCasToken;
Vector<TrackInfo> mSelectedTracks;
int64_t mTotalBitrate; // in bits/sec
diff --git a/media/libstagefright/include/media/stagefright/OMXClient.h b/media/libstagefright/include/media/stagefright/OMXClient.h
index 203a181..2f159b0 100644
--- a/media/libstagefright/include/media/stagefright/OMXClient.h
+++ b/media/libstagefright/include/media/stagefright/OMXClient.h
@@ -28,9 +28,10 @@
status_t connect();
status_t connect(bool* trebleFlag);
+ status_t connect(const char* name, bool* trebleFlag = nullptr);
status_t connectLegacy();
- status_t connectTreble();
+ status_t connectTreble(const char* name = "default");
void disconnect();
sp<IOMX> interface() {
@@ -40,8 +41,8 @@
private:
sp<IOMX> mOMX;
- OMXClient(const OMXClient &);
- OMXClient &operator=(const OMXClient &);
+ OMXClient(const OMXClient &) = delete;
+ OMXClient &operator=(const OMXClient &) = delete;
};
} // namespace android
diff --git a/drm/libmediadrm/aidl/android/media/IDescrambler.aidl b/media/libstagefright/include/media/stagefright/OmxInfoBuilder.h
similarity index 62%
rename from drm/libmediadrm/aidl/android/media/IDescrambler.aidl
rename to media/libstagefright/include/media/stagefright/OmxInfoBuilder.h
index fdf99eb..1b4d873 100644
--- a/drm/libmediadrm/aidl/android/media/IDescrambler.aidl
+++ b/media/libstagefright/include/media/stagefright/OmxInfoBuilder.h
@@ -14,14 +14,20 @@
* limitations under the License.
*/
-package android.media;
+#ifndef OMX_INFO_BUILDER_H_
+#define OMX_INFO_BUILDER_H_
-import android.media.MediaDescrambler;
+#include <media/stagefright/MediaCodecList.h>
+#include <utils/Errors.h>
-/** @hide */
-interface IDescrambler {
- void setMediaCasSession(in byte[] sessionId);
- boolean requiresSecureDecoderComponent(String mime);
- int descramble(in MediaDescrambler.DescrambleInfo descrambleInfo);
- void release();
-}
\ No newline at end of file
+namespace android {
+
+class OmxInfoBuilder : public MediaCodecListBuilderBase {
+public:
+ OmxInfoBuilder();
+ status_t buildMediaCodecList(MediaCodecListWriter* writer) override;
+};
+
+} // namespace android
+
+#endif // OMX_INFO_BUILDER_H_
diff --git a/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
index d38c337..d1677fa 100644
--- a/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
@@ -25,7 +25,7 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>
-#include <MetadataBufferType.h>
+#include <media/hardware/MetadataBufferType.h>
#include "foundation/ABase.h"
diff --git a/media/libstagefright/include/media/stagefright/Utils.h b/media/libstagefright/include/media/stagefright/Utils.h
index 88a416a..77cbd4c 100644
--- a/media/libstagefright/include/media/stagefright/Utils.h
+++ b/media/libstagefright/include/media/stagefright/Utils.h
@@ -95,7 +95,7 @@
void readFromAMessage(const sp<AMessage> &msg, BufferingSettings *buffering /* nonnull */);
AString nameForFd(int fd);
-
+void MakeFourCCString(uint32_t x, char *s);
} // namespace android
#endif // UTILS_H_
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 31edb21..a256a4d 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -23,8 +23,8 @@
#include "ESQueue.h"
#include "include/avc_utils.h"
-#include <android/media/IDescrambler.h>
-#include <binder/MemoryDealer.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <cutils/native_handle.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -41,8 +41,12 @@
#include <inttypes.h>
namespace android {
-using binder::Status;
-using MediaDescrambler::DescrambleInfo;
+using hardware::hidl_handle;
+using hardware::hidl_memory;
+using hardware::hidl_string;
+using hardware::hidl_vec;
+using namespace hardware::cas::V1_0;
+using namespace hardware::cas::native::V1_0;
// I want the expression "y" evaluated even if verbose logging is off.
#define MY_LOGV(x, y) \
@@ -203,6 +207,7 @@
sp<AMessage> mSampleAesKeyItem;
sp<IMemory> mMem;
sp<MemoryDealer> mDealer;
+ hardware::cas::native::V1_0::SharedBuffer mDescramblerSrcBuffer;
sp<ABuffer> mDescrambledBuffer;
List<SubSampleInfo> mSubSamples;
sp<IDescrambler> mDescrambler;
@@ -235,7 +240,7 @@
// Ensure internal buffers can hold specified size, and will re-allocate
// as needed.
- void ensureBufferCapacity(size_t size);
+ bool ensureBufferCapacity(size_t size);
DISALLOW_EVIL_CONSTRUCTORS(Stream);
};
@@ -807,9 +812,9 @@
mQueue = NULL;
}
-void ATSParser::Stream::ensureBufferCapacity(size_t neededSize) {
+bool ATSParser::Stream::ensureBufferCapacity(size_t neededSize) {
if (mBuffer != NULL && mBuffer->capacity() >= neededSize) {
- return;
+ return true;
}
ALOGV("ensureBufferCapacity: current size %zu, new size %zu, scrambled %d",
@@ -837,6 +842,26 @@
mMem = newMem;
mDealer = newDealer;
mDescrambledBuffer = newScrambledBuffer;
+
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = newMem->getMemory(&offset, &size);
+ if (heap == NULL) {
+ return false;
+ }
+ native_handle_t* nativeHandle = native_handle_create(1, 0);
+ if (!nativeHandle) {
+ ALOGE("[stream %d] failed to create native handle", mElementaryPID);
+ return false;
+ }
+ nativeHandle->data[0] = heap->getHeapID();
+ mDescramblerSrcBuffer.heapBase = hidl_memory("ashmem",
+ hidl_handle(nativeHandle), heap->getSize());
+ mDescramblerSrcBuffer.offset = (uint64_t) offset;
+ mDescramblerSrcBuffer.size = (uint64_t) size;
+
+ ALOGD("[stream %d] created shared buffer for descrambling, offset %zd, size %zu",
+ mElementaryPID, offset, size);
} else {
// Align to multiples of 64K.
neededSize = (neededSize + 65535) & ~65535;
@@ -850,6 +875,7 @@
newBuffer->setRange(0, 0);
}
mBuffer = newBuffer;
+ return true;
}
status_t ATSParser::Stream::parse(
@@ -923,7 +949,9 @@
}
size_t neededSize = mBuffer->size() + payloadSizeBits / 8;
- ensureBufferCapacity(neededSize);
+ if (!ensureBufferCapacity(neededSize)) {
+ return NO_MEMORY;
+ }
memcpy(mBuffer->data() + mBuffer->size(), br->data(), payloadSizeBits / 8);
mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8);
@@ -1365,47 +1393,59 @@
memcpy(mDescrambledBuffer->data(), mBuffer->data(), descrambleBytes);
mDescrambledBuffer->setRange(0, descrambleBytes);
- sp<ABuffer> subSamples = new ABuffer(
- sizeof(DescramblerPlugin::SubSample) * descrambleSubSamples);
-
- DescrambleInfo info;
- info.dstType = DescrambleInfo::kDestinationTypeVmPointer;
- info.scramblingControl = (DescramblerPlugin::ScramblingControl)sctrl;
- info.numSubSamples = descrambleSubSamples;
- info.subSamples = (DescramblerPlugin::SubSample *)subSamples->data();
- info.srcMem = mMem;
- info.srcOffset = 0;
- info.dstPtr = NULL; // in-place descrambling into srcMem
- info.dstOffset = 0;
+ hidl_vec<SubSample> subSamples;
+ subSamples.resize(descrambleSubSamples);
int32_t i = 0;
for (auto it = mSubSamples.begin();
it != mSubSamples.end() && i < descrambleSubSamples; it++, i++) {
if (it->transport_scrambling_mode != 0 || pesScramblingControl != 0) {
- info.subSamples[i].mNumBytesOfClearData = 0;
- info.subSamples[i].mNumBytesOfEncryptedData = it->subSampleSize;
+ subSamples[i].numBytesOfClearData = 0;
+ subSamples[i].numBytesOfEncryptedData = it->subSampleSize;
} else {
- info.subSamples[i].mNumBytesOfClearData = it->subSampleSize;
- info.subSamples[i].mNumBytesOfEncryptedData = 0;
+ subSamples[i].numBytesOfClearData = it->subSampleSize;
+ subSamples[i].numBytesOfEncryptedData = 0;
}
}
+
+ uint64_t srcOffset = 0, dstOffset = 0;
// If scrambled at PES-level, PES header should be skipped
if (pesScramblingControl != 0) {
- info.srcOffset = info.dstOffset = pesOffset;
- info.subSamples[0].mNumBytesOfEncryptedData -= pesOffset;
+ srcOffset = dstOffset = pesOffset;
+ subSamples[0].numBytesOfEncryptedData -= pesOffset;
}
- int32_t result;
- Status status = mDescrambler->descramble(info, &result);
+ Status status = Status::OK;
+ uint32_t bytesWritten = 0;
+ hidl_string detailedError;
- if (!status.isOk()) {
- ALOGE("[stream %d] descramble failed, exceptionCode=%d",
- mElementaryPID, status.exceptionCode());
+ DestinationBuffer dstBuffer;
+ dstBuffer.type = BufferType::SHARED_MEMORY;
+ dstBuffer.nonsecureMemory = mDescramblerSrcBuffer;
+
+ auto returnVoid = mDescrambler->descramble(
+ (ScramblingControl) sctrl,
+ subSamples,
+ mDescramblerSrcBuffer,
+ srcOffset,
+ dstBuffer,
+ dstOffset,
+ [&status, &bytesWritten, &detailedError] (
+ Status _status, uint32_t _bytesWritten,
+ const hidl_string& _detailedError) {
+ status = _status;
+ bytesWritten = _bytesWritten;
+ detailedError = _detailedError;
+ });
+
+ if (!returnVoid.isOk()) {
+ ALOGE("[stream %d] descramble failed, trans=%s",
+ mElementaryPID, returnVoid.description().c_str());
return UNKNOWN_ERROR;
}
ALOGV("[stream %d] descramble succeeded, %d bytes",
- mElementaryPID, result);
+ mElementaryPID, bytesWritten);
memcpy(mBuffer->data(), mDescrambledBuffer->data(), descrambleBytes);
}
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 374e011..41c19cd 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -29,11 +29,13 @@
#include <vector>
namespace android {
-namespace media {
-class ICas;
-class IDescrambler;
-};
-using namespace media;
+namespace hardware {
+namespace cas {
+namespace V1_0 {
+struct ICas;
+}}}
+using hardware::cas::V1_0::ICas;
+
class ABitReader;
struct ABuffer;
struct AnotherPacketSource;
diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp
index 96eb5bf..21259c4 100644
--- a/media/libstagefright/mpeg2ts/Android.bp
+++ b/media/libstagefright/mpeg2ts/Android.bp
@@ -35,5 +35,8 @@
shared_libs: [
"libcrypto",
"libmedia",
+ "libhidlmemory",
+ "android.hardware.cas.native@1.0",
+ "android.hidl.memory@1.0",
],
}
diff --git a/media/libstagefright/mpeg2ts/CasManager.cpp b/media/libstagefright/mpeg2ts/CasManager.cpp
index 047b1b3..9ff4521 100644
--- a/media/libstagefright/mpeg2ts/CasManager.cpp
+++ b/media/libstagefright/mpeg2ts/CasManager.cpp
@@ -18,15 +18,19 @@
#define LOG_TAG "CasManager"
#include "CasManager.h"
-#include <android/media/ICas.h>
-#include <android/media/IDescrambler.h>
-#include <android/media/IMediaCasService.h>
-#include <binder/IServiceManager.h>
+#include <android/hardware/cas/1.0/ICas.h>
+#include <android/hardware/cas/1.0/IMediaCasService.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <hidl/HidlSupport.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <utils/Log.h>
namespace android {
-using binder::Status;
+
+using hardware::hidl_vec;
+using hardware::Return;
+using namespace hardware::cas::V1_0;
+using namespace hardware::cas::native::V1_0;
struct ATSParser::CasManager::ProgramCasManager : public RefBase {
ProgramCasManager(unsigned programNumber, const CADescriptor &descriptor);
@@ -125,45 +129,60 @@
const sp<ICas>& cas,
PidToSessionMap &sessionMap,
CasSession *session) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> casServiceBinder = sm->getService(String16("media.cas"));
- sp<IMediaCasService> casService =
- interface_cast<IMediaCasService>(casServiceBinder);
-
+ sp<IMediaCasService> casService = IMediaCasService::getService("default");
if (casService == NULL) {
ALOGE("Cannot obtain IMediaCasService");
return NO_INIT;
}
+ Status status;
sp<IDescrambler> descrambler;
+ sp<IDescramblerBase> descramblerBase;
+ Return<Status> returnStatus(Status::OK);
+ Return<sp<IDescramblerBase> > returnDescrambler(NULL);
std::vector<uint8_t> sessionId;
const CADescriptor &descriptor = session->mCADescriptor;
- Status status = cas->openSession(&sessionId);
- if (!status.isOk()) {
- ALOGE("Failed to open session: exception=%d, error=%d",
- status.exceptionCode(), status.serviceSpecificErrorCode());
+ auto returnVoid = cas->openSession(
+ [&status, &sessionId] (Status _status, const hidl_vec<uint8_t>& _sessionId) {
+ status = _status;
+ sessionId = _sessionId;
+ });
+ if (!returnVoid.isOk() || status != Status::OK) {
+ ALOGE("Failed to open session: trans=%s, status=%d",
+ returnVoid.description().c_str(), status);
goto l_fail;
}
- cas->setSessionPrivateData(sessionId, descriptor.mPrivateData);
- if (!status.isOk()) {
- ALOGE("Failed to set private data: exception=%d, error=%d",
- status.exceptionCode(), status.serviceSpecificErrorCode());
+ returnStatus = cas->setSessionPrivateData(sessionId, descriptor.mPrivateData);
+ if (!returnStatus.isOk() || returnStatus != Status::OK) {
+ ALOGE("Failed to set private data: trans=%s, status=%d",
+ returnStatus.description().c_str(), (Status)returnStatus);
goto l_fail;
}
- status = casService->createDescrambler(descriptor.mSystemID, &descrambler);
- if (!status.isOk() || descrambler == NULL) {
- ALOGE("Failed to create descrambler: : exception=%d, error=%d",
- status.exceptionCode(), status.serviceSpecificErrorCode());
+ returnDescrambler = casService->createDescrambler(descriptor.mSystemID);
+ if (!returnDescrambler.isOk()) {
+ ALOGE("Failed to create descrambler: trans=%s",
+ returnDescrambler.description().c_str());
+ goto l_fail;
+ }
+ descramblerBase = (sp<IDescramblerBase>) returnDescrambler;
+ if (descramblerBase == NULL) {
+ ALOGE("Failed to create descrambler: null ptr");
goto l_fail;
}
- status = descrambler->setMediaCasSession(sessionId);
- if (!status.isOk()) {
- ALOGE("Failed to init descrambler: : exception=%d, error=%d",
- status.exceptionCode(), status.serviceSpecificErrorCode());
+ returnStatus = descramblerBase->setMediaCasSession(sessionId);
+ if (!returnStatus.isOk() || (Status) returnStatus != Status::OK) {
+ ALOGE("Failed to init descrambler: : trans=%s, status=%d",
+ returnStatus.description().c_str(), (Status) returnStatus);
+ goto l_fail;
+ }
+
+ descrambler = IDescrambler::castFrom(descramblerBase);
+ if (descrambler == NULL) {
+ ALOGE("Failed to cast from IDescramblerBase to IDescrambler");
goto l_fail;
}
@@ -177,8 +196,8 @@
if (!sessionId.empty()) {
cas->closeSession(sessionId);
}
- if (descrambler != NULL) {
- descrambler->release();
+ if (descramblerBase != NULL) {
+ descramblerBase->release();
}
return NO_INIT;
}
@@ -316,11 +335,12 @@
if (index < 0) {
return false;
}
- MediaCas::ParcelableCasData ecm(br->data(), br->numBitsLeft() / 8);
- Status status = mICas->processEcm(mCAPidToSessionIdMap[index], ecm);
- if (!status.isOk()) {
- ALOGE("Failed to process ECM: exception=%d, error=%d",
- status.exceptionCode(), status.serviceSpecificErrorCode());
+ hidl_vec<uint8_t> ecm;
+ ecm.setToExternal((uint8_t*)br->data(), br->numBitsLeft() / 8);
+ auto returnStatus = mICas->processEcm(mCAPidToSessionIdMap[index], ecm);
+ if (!returnStatus.isOk() || (Status) returnStatus != Status::OK) {
+ ALOGE("Failed to process ECM: trans=%s, status=%d",
+ returnStatus.description().c_str(), (Status) returnStatus);
}
return true; // handled
}
diff --git a/media/libstagefright/mpeg2ts/CasManager.h b/media/libstagefright/mpeg2ts/CasManager.h
index 8088dec..81f6546 100644
--- a/media/libstagefright/mpeg2ts/CasManager.h
+++ b/media/libstagefright/mpeg2ts/CasManager.h
@@ -21,10 +21,13 @@
#include <set>
namespace android {
-namespace media {
-class ICas;
-class IDescrambler;
-}
+namespace hardware {
+namespace cas {
+namespace native {
+namespace V1_0 {
+struct IDescrambler;
+}}}}
+using hardware::cas::native::V1_0::IDescrambler;
struct ATSParser::CasManager : public RefBase {
CasManager();
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index c3f1274..9d684e0 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -38,8 +38,13 @@
#include "AnotherPacketSource.h"
#include "ATSParser.h"
+#include <hidl/HybridInterface.h>
+#include <android/hardware/cas/1.0/ICas.h>
+
namespace android {
+using hardware::cas::V1_0::ICas;
+
static const size_t kTSPacketSize = 188;
static const int kMaxDurationReadSize = 250000LL;
static const int kMaxDurationRetry = 6;
@@ -156,7 +161,10 @@
|| !strcasecmp(MEDIA_MIMETYPE_AUDIO_SCRAMBLED, mime));
}
-status_t MPEG2TSExtractor::setMediaCas(const sp<ICas> &cas) {
+status_t MPEG2TSExtractor::setMediaCas(const HInterfaceToken &casToken) {
+ HalToken halToken;
+ halToken.setToExternal((uint8_t*)casToken.data(), casToken.size());
+ sp<ICas> cas = ICas::castFrom(retrieveHalInterface(halToken));
ALOGD("setMediaCas: %p", cas.get());
status_t err = mParser->setMediaCas(cas);
diff --git a/media/libstagefright/omx/1.0/Omx.cpp b/media/libstagefright/omx/1.0/Omx.cpp
index 789379a..fe50656 100644
--- a/media/libstagefright/omx/1.0/Omx.cpp
+++ b/media/libstagefright/omx/1.0/Omx.cpp
@@ -19,20 +19,19 @@
#include <android-base/logging.h>
#include <gui/IGraphicBufferProducer.h>
-#include <OMX_Core.h>
-#include <OMX_AsString.h>
+#include <media/openmax/OMX_Core.h>
+#include <media/openmax/OMX_AsString.h>
-#include "../OMXUtils.h"
-#include "../OMXMaster.h"
-#include "../GraphicBufferSource.h"
+#include <media/stagefright/omx/OMXUtils.h>
+#include <media/stagefright/omx/OMXMaster.h>
+#include <media/stagefright/omx/GraphicBufferSource.h>
-#include "WOmxNode.h"
-#include "WOmxObserver.h"
-#include "WGraphicBufferProducer.h"
-#include "WGraphicBufferSource.h"
-#include "Conversion.h"
-
-#include "Omx.h"
+#include <media/stagefright/omx/1.0/WOmxNode.h>
+#include <media/stagefright/omx/1.0/WOmxObserver.h>
+#include <media/stagefright/omx/1.0/WGraphicBufferProducer.h>
+#include <media/stagefright/omx/1.0/WGraphicBufferSource.h>
+#include <media/stagefright/omx/1.0/Conversion.h>
+#include <media/stagefright/omx/1.0/Omx.h>
namespace android {
namespace hardware {
@@ -115,15 +114,23 @@
return Void();
}
instance->setHandle(handle);
- std::vector<AString> quirkVector;
- if (mParser.getQuirks(name.c_str(), &quirkVector) == OK) {
+
+ // Find quirks from mParser
+ const auto& codec = mParser.getCodecMap().find(name.c_str());
+ if (codec == mParser.getCodecMap().cend()) {
+ LOG(WARNING) << "Failed to obtain quirks for omx component "
+ "'" << name.c_str() << "' "
+ "from XML files";
+ } else {
uint32_t quirks = 0;
- for (const AString quirk : quirkVector) {
+ for (const auto& quirk : codec->second.quirkSet) {
if (quirk == "requires-allocate-on-input-ports") {
- quirks |= kRequiresAllocateBufferOnInputPorts;
+ quirks |= OMXNodeInstance::
+ kRequiresAllocateBufferOnInputPorts;
}
if (quirk == "requires-allocate-on-output-ports") {
- quirks |= kRequiresAllocateBufferOnOutputPorts;
+ quirks |= OMXNodeInstance::
+ kRequiresAllocateBufferOnOutputPorts;
}
}
instance->setQuirks(quirks);
diff --git a/media/libstagefright/omx/1.0/OmxStore.cpp b/media/libstagefright/omx/1.0/OmxStore.cpp
index 0e37af9..447af6f 100644
--- a/media/libstagefright/omx/1.0/OmxStore.cpp
+++ b/media/libstagefright/omx/1.0/OmxStore.cpp
@@ -19,8 +19,9 @@
#include <android-base/logging.h>
-#include "Conversion.h"
-#include "OmxStore.h"
+#include <media/stagefright/omx/1.0/Conversion.h>
+#include <media/stagefright/omx/1.0/OmxStore.h>
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
namespace android {
namespace hardware {
@@ -29,24 +30,87 @@
namespace V1_0 {
namespace implementation {
-OmxStore::OmxStore() {
+OmxStore::OmxStore(
+ const char* owner,
+ const char* const* searchDirs,
+ const char* mainXmlName,
+ const char* performanceXmlName,
+ const char* profilingResultsXmlPath) {
+ MediaCodecsXmlParser parser(searchDirs,
+ mainXmlName,
+ performanceXmlName,
+ profilingResultsXmlPath);
+ mParsingStatus = toStatus(parser.getParsingStatus());
+
+ const auto& serviceAttributeMap = parser.getServiceAttributeMap();
+ mServiceAttributeList.resize(serviceAttributeMap.size());
+ size_t i = 0;
+ for (const auto& attributePair : serviceAttributeMap) {
+ ServiceAttribute attribute;
+ attribute.key = attributePair.first;
+ attribute.value = attributePair.second;
+ mServiceAttributeList[i] = std::move(attribute);
+ ++i;
+ }
+
+ const auto& roleMap = parser.getRoleMap();
+ mRoleList.resize(roleMap.size());
+ i = 0;
+ for (const auto& rolePair : roleMap) {
+ RoleInfo role;
+ role.role = rolePair.first;
+ role.type = rolePair.second.type;
+ role.isEncoder = rolePair.second.isEncoder;
+ // TODO: Currently, preferPlatformNodes information is not available in
+ // the xml file. Once we have a way to provide this information, it
+ // should be parsed properly.
+ role.preferPlatformNodes = rolePair.first.compare(0, 5, "audio") == 0;
+ hidl_vec<NodeInfo>& nodeList = role.nodes;
+ nodeList.resize(rolePair.second.nodeList.size());
+ size_t j = 0;
+ for (const auto& nodePair : rolePair.second.nodeList) {
+ NodeInfo node;
+ node.name = nodePair.second.name;
+ node.owner = owner;
+ hidl_vec<NodeAttribute>& attributeList = node.attributes;
+ attributeList.resize(nodePair.second.attributeList.size());
+ size_t k = 0;
+ for (const auto& attributePair : nodePair.second.attributeList) {
+ NodeAttribute attribute;
+ attribute.key = attributePair.first;
+ attribute.value = attributePair.second;
+ attributeList[k] = std::move(attribute);
+ ++k;
+ }
+ nodeList[j] = std::move(node);
+ ++j;
+ }
+ mRoleList[i] = std::move(role);
+ ++i;
+ }
+
+ mPrefix = parser.getCommonPrefix();
}
OmxStore::~OmxStore() {
}
Return<void> OmxStore::listServiceAttributes(listServiceAttributes_cb _hidl_cb) {
- _hidl_cb(toStatus(NO_ERROR), hidl_vec<ServiceAttribute>());
+ if (mParsingStatus == Status::NO_ERROR) {
+ _hidl_cb(Status::NO_ERROR, mServiceAttributeList);
+ } else {
+ _hidl_cb(mParsingStatus, hidl_vec<ServiceAttribute>());
+ }
return Void();
}
Return<void> OmxStore::getNodePrefix(getNodePrefix_cb _hidl_cb) {
- _hidl_cb(hidl_string());
+ _hidl_cb(mPrefix);
return Void();
}
Return<void> OmxStore::listRoles(listRoles_cb _hidl_cb) {
- _hidl_cb(hidl_vec<RoleInfo>());
+ _hidl_cb(mRoleList);
return Void();
}
@@ -54,12 +118,6 @@
return IOmx::tryGetService(omxName);
}
-// Methods from ::android::hidl::base::V1_0::IBase follow.
-
-IOmxStore* HIDL_FETCH_IOmxStore(const char* /* name */) {
- return new OmxStore();
-}
-
} // namespace implementation
} // namespace V1_0
} // namespace omx
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp b/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
index 9327f03..639b35f 100644
--- a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
+++ b/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
@@ -18,9 +18,9 @@
#include <android-base/logging.h>
-#include "WGraphicBufferProducer.h"
-#include "WProducerListener.h"
-#include "Conversion.h"
+#include <media/stagefright/omx/1.0/WGraphicBufferProducer.h>
+#include <media/stagefright/omx/1.0/WProducerListener.h>
+#include <media/stagefright/omx/1.0/Conversion.h>
#include <system/window.h>
namespace android {
@@ -41,7 +41,9 @@
sp<GraphicBuffer> buf;
status_t status = mBase->requestBuffer(slot, &buf);
AnwBuffer anwBuffer{};
- wrapAs(&anwBuffer, *buf);
+ if (buf != nullptr) {
+ wrapAs(&anwBuffer, *buf);
+ }
_hidl_cb(static_cast<int32_t>(status), anwBuffer);
return Void();
}
@@ -64,10 +66,9 @@
sp<Fence> fence;
::android::FrameEventHistoryDelta outTimestamps;
status_t status = mBase->dequeueBuffer(
- &slot, &fence,
- width, height,
- static_cast<::android::PixelFormat>(format), usage,
- getFrameTimestamps ? &outTimestamps : nullptr);
+ &slot, &fence, width, height,
+ static_cast<::android::PixelFormat>(format), usage, nullptr,
+ getFrameTimestamps ? &outTimestamps : nullptr);
hidl_handle tFence{};
FrameEventHistoryDelta tOutTimestamps{};
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
index d8540f8..3201c32 100644
--- a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
@@ -17,15 +17,14 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "TWGraphicBufferSource"
+#include <media/stagefright/omx/1.0/WGraphicBufferSource.h>
+#include <media/stagefright/omx/1.0/WOmxNode.h>
+#include <media/stagefright/omx/1.0/Conversion.h>
+#include <media/stagefright/omx/OMXUtils.h>
#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
-#include <OMX_Component.h>
-#include <OMX_IndexExt.h>
-
-#include "omx/OMXUtils.h"
-#include "WGraphicBufferSource.h"
-#include "WOmxNode.h"
-#include "Conversion.h"
+#include <media/openmax/OMX_Component.h>
+#include <media/openmax/OMX_IndexExt.h>
namespace android {
namespace hardware {
@@ -68,7 +67,14 @@
tMsg.data.eventData.data1 = dataSpace;
tMsg.data.eventData.data2 = aspects;
tMsg.data.eventData.data3 = pixelFormat;
- mOmxNode->dispatchMessage(tMsg);
+ if (!mOmxNode->dispatchMessage(tMsg).isOk()) {
+ ALOGE("TWOmxNodeWrapper failed to dispatch message "
+ "OMX_EventDataSpaceChanged: "
+ "dataSpace = %ld, aspects = %ld, pixelFormat = %ld",
+ static_cast<long>(dataSpace),
+ static_cast<long>(aspects),
+ static_cast<long>(pixelFormat));
+ }
}
};
@@ -144,10 +150,13 @@
outParams.data() + outParams.size(),
params);
});
- omxNode->getParameter(
+ auto transStatus = omxNode->getParameter(
static_cast<uint32_t>(OMX_IndexParamConsumerUsageBits),
inHidlBytes(&consumerUsage, sizeof(consumerUsage)),
_hidl_cb);
+ if (!transStatus.isOk()) {
+ return toStatus(FAILED_TRANSACTION);
+ }
if (fnStatus != OK) {
consumerUsage = 0;
}
@@ -158,10 +167,13 @@
_params = &def;
params = static_cast<uint8_t*>(_params);
- omxNode->getParameter(
+ transStatus = omxNode->getParameter(
static_cast<uint32_t>(OMX_IndexParamPortDefinition),
inHidlBytes(&def, sizeof(def)),
_hidl_cb);
+ if (!transStatus.isOk()) {
+ return toStatus(FAILED_TRANSACTION);
+ }
if (fnStatus != NO_ERROR) {
ALOGE("Failed to get port definition: %d", fnStatus);
return toStatus(fnStatus);
diff --git a/media/libstagefright/omx/1.0/WOmxBufferSource.cpp b/media/libstagefright/omx/1.0/WOmxBufferSource.cpp
index 803283a..c8c963f 100644
--- a/media/libstagefright/omx/1.0/WOmxBufferSource.cpp
+++ b/media/libstagefright/omx/1.0/WOmxBufferSource.cpp
@@ -16,8 +16,8 @@
#include <utils/String8.h>
-#include "WOmxBufferSource.h"
-#include "Conversion.h"
+#include <media/stagefright/omx/1.0/WOmxBufferSource.h>
+#include <media/stagefright/omx/1.0/Conversion.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/1.0/WOmxNode.cpp b/media/libstagefright/omx/1.0/WOmxNode.cpp
index 6c0abc9..1dc7c7b 100644
--- a/media/libstagefright/omx/1.0/WOmxNode.cpp
+++ b/media/libstagefright/omx/1.0/WOmxNode.cpp
@@ -16,9 +16,9 @@
#include <algorithm>
-#include "WOmxNode.h"
-#include "WOmxBufferSource.h"
-#include "Conversion.h"
+#include <media/stagefright/omx/1.0/WOmxNode.h>
+#include <media/stagefright/omx/1.0/WOmxBufferSource.h>
+#include <media/stagefright/omx/1.0/Conversion.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/1.0/WOmxObserver.cpp b/media/libstagefright/omx/1.0/WOmxObserver.cpp
index 354db29..ccbe25c 100644
--- a/media/libstagefright/omx/1.0/WOmxObserver.cpp
+++ b/media/libstagefright/omx/1.0/WOmxObserver.cpp
@@ -16,14 +16,14 @@
#define LOG_TAG "WOmxObserver-impl"
-#include <vector>
-
#include <android-base/logging.h>
#include <cutils/native_handle.h>
#include <binder/Binder.h>
-#include "WOmxObserver.h"
-#include "Conversion.h"
+#include <media/stagefright/omx/1.0/WOmxObserver.h>
+#include <media/stagefright/omx/1.0/Conversion.h>
+
+#include <vector>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/1.0/WProducerListener.cpp b/media/libstagefright/omx/1.0/WProducerListener.cpp
index be0d4d5..bdc3aa1 100644
--- a/media/libstagefright/omx/1.0/WProducerListener.cpp
+++ b/media/libstagefright/omx/1.0/WProducerListener.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "WProducerListener.h"
+#include <media/stagefright/omx/1.0/WProducerListener.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 2d921f9..d4cdf69 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -1,12 +1,16 @@
cc_library_shared {
name: "libstagefright_omx",
vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: [
"FrameDropper.cpp",
"GraphicBufferSource.cpp",
"BWGraphicBufferSource.cpp",
"OMX.cpp",
+ "OMXStore.cpp",
"OMXMaster.cpp",
"OMXNodeInstance.cpp",
"OMXUtils.cpp",
@@ -25,14 +29,16 @@
"1.0/WOmxBufferSource.cpp",
],
- include_dirs: [
- "frameworks/av/include", // for media/vndk/xmlparser/1.0/MediaCodecsXmlParser.h
- "frameworks/av/include/media/",
- "frameworks/av/media/libstagefright",
- "frameworks/av/media/libstagefright/include",
- "frameworks/native/include", // for media/hardware/MetadataBufferType.h
- "frameworks/native/include/media/hardware",
- "frameworks/native/include/media/openmax",
+ export_include_dirs: [
+ "include",
+ ],
+
+ header_libs: [
+ "media_plugin_headers",
+ ],
+
+ export_header_lib_headers: [
+ "media_plugin_headers",
],
shared_libs: [
@@ -45,12 +51,12 @@
"libgui",
"libcutils",
"libstagefright_foundation",
+ "libstagefright_xmlparser",
"libdl",
"libhidlbase",
"libhidlmemory",
"libhidltransport",
"libnativewindow", // TODO(b/62923479): use header library
- "libstagefright_xmlparser@1.0",
"android.hidl.memory@1.0",
"android.hidl.token@1.0-utils",
"android.hardware.media@1.0",
@@ -59,7 +65,12 @@
"android.hardware.graphics.bufferqueue@1.0",
],
- export_shared_lib_headers: ["android.hidl.memory@1.0"],
+ export_shared_lib_headers: [
+ "android.hidl.memory@1.0",
+ "libmedia_omx",
+ "libstagefright_foundation",
+ "libstagefright_xmlparser",
+ ],
cflags: [
"-Werror",
@@ -80,15 +91,29 @@
},
}
-cc_library_static {
+cc_library_shared {
name: "libstagefright_omx_utils",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: ["OMXUtils.cpp"],
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/native/include/media/hardware",
- "frameworks/native/include/media/openmax",
+ export_include_dirs: [
+ "include",
],
- shared_libs: ["libmedia"],
+ header_libs: [
+ "media_plugin_headers",
+ ],
+ export_header_lib_headers: [
+ "media_plugin_headers",
+ ],
+ shared_libs: [
+ "libmedia_omx",
+ "liblog",
+ ],
+ export_shared_lib_headers: [
+ "libmedia_omx",
+ ],
sanitize: {
misc_undefined: [
"signed-integer-overflow",
diff --git a/media/libstagefright/omx/BWGraphicBufferSource.cpp b/media/libstagefright/omx/BWGraphicBufferSource.cpp
index 79f6d93..94ef598 100644
--- a/media/libstagefright/omx/BWGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/BWGraphicBufferSource.cpp
@@ -17,15 +17,13 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "BWGraphicBufferSource"
-#include <OMX_Component.h>
-#include <OMX_IndexExt.h>
-
+#include <media/stagefright/omx/BWGraphicBufferSource.h>
+#include <media/stagefright/omx/OMXUtils.h>
+#include <media/openmax/OMX_Component.h>
+#include <media/openmax/OMX_IndexExt.h>
#include <media/OMXBuffer.h>
#include <media/IOMX.h>
-#include "OMXUtils.h"
-#include "BWGraphicBufferSource.h"
-
namespace android {
static const OMX_U32 kPortIndexInput = 0;
diff --git a/media/libstagefright/omx/FrameDropper.cpp b/media/libstagefright/omx/FrameDropper.cpp
index 9a4952e..0c50c58 100644
--- a/media/libstagefright/omx/FrameDropper.cpp
+++ b/media/libstagefright/omx/FrameDropper.cpp
@@ -18,8 +18,7 @@
#define LOG_TAG "FrameDropper"
#include <utils/Log.h>
-#include "FrameDropper.h"
-
+#include <media/stagefright/omx/FrameDropper.h>
#include <media/stagefright/foundation/ADebug.h>
namespace android {
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index ef4d745..1917d2a 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -22,7 +22,9 @@
#define STRINGIFY_ENUMS // for asString in HardwareAPI.h/VideoAPI.h
-#include "GraphicBufferSource.h"
+#include <media/stagefright/omx/GraphicBufferSource.h>
+#include <media/stagefright/omx/FrameDropper.h>
+#include <media/stagefright/omx/OMXUtils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/ColorUtils.h>
@@ -31,14 +33,12 @@
#include <media/hardware/MetadataBufferType.h>
#include <ui/GraphicBuffer.h>
#include <gui/BufferItem.h>
-#include <HardwareAPI.h>
-#include "omx/OMXUtils.h"
-#include <OMX_Component.h>
-#include <OMX_IndexExt.h>
-#include "media/OMXBuffer.h"
+#include <media/hardware/HardwareAPI.h>
+#include <media/openmax/OMX_Component.h>
+#include <media/openmax/OMX_IndexExt.h>
+#include <media/OMXBuffer.h>
#include <inttypes.h>
-#include "FrameDropper.h"
#include <functional>
#include <memory>
@@ -733,7 +733,7 @@
} else {
// snap to nearest capture point
int64_t nFrames = std::llround(
- (timeUs - mPrevCaptureUs) * mCaptureFps);
+ (timeUs - mPrevCaptureUs) * mCaptureFps / 1000000);
if (nFrames <= 0) {
// skip this frame as it's too close to previous capture
ALOGV("skipping frame, timeUs %lld", static_cast<long long>(timeUs));
@@ -741,9 +741,9 @@
}
mFrameCount += nFrames;
mPrevCaptureUs = mBaseCaptureUs + std::llround(
- mFrameCount / mCaptureFps);
+ mFrameCount * 1000000 / mCaptureFps);
mPrevFrameUs = mBaseFrameUs + std::llround(
- mFrameCount / mFps);
+ mFrameCount * 1000000 / mFps);
}
ALOGV("timeUs %lld, captureUs %lld, frameUs %lld",
@@ -956,28 +956,40 @@
Mutex::Autolock lock(mMutex);
uint64_t slotMask;
- if (mConsumer->getReleasedBuffers(&slotMask) != NO_ERROR) {
- ALOGW("onBuffersReleased: unable to get released buffer set");
+ uint64_t releaseMask;
+ if (mConsumer->getReleasedBuffers(&releaseMask) != NO_ERROR) {
slotMask = 0xffffffffffffffffULL;
+ ALOGW("onBuffersReleased: unable to get released buffer set");
+ } else {
+ slotMask = releaseMask;
+ ALOGV("onBuffersReleased: 0x%016" PRIx64, slotMask);
}
- ALOGV("onBuffersReleased: 0x%016" PRIx64, slotMask);
-
+ AString unpopulated;
for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
if ((slotMask & 0x01) != 0) {
- discardBufferInSlot_l(i);
+ if (!discardBufferInSlot_l(i)) {
+ if (!unpopulated.empty()) {
+ unpopulated.append(", ");
+ }
+ unpopulated.append(i);
+ }
}
slotMask >>= 1;
}
+ if (!unpopulated.empty()) {
+ ALOGW("released unpopulated slots: [%s]", unpopulated.c_str());
+ }
}
-void GraphicBufferSource::discardBufferInSlot_l(GraphicBufferSource::slot_id i) {
+bool GraphicBufferSource::discardBufferInSlot_l(GraphicBufferSource::slot_id i) {
ssize_t bsi = mBufferSlots.indexOfKey(i);
if (bsi < 0) {
- ALOGW("releasing an unpopulated slot: %d", i);
+ return false;
} else {
discardBufferAtSlotIndex_l(bsi);
mBufferSlots.removeItemsAt(bsi);
+ return true;
}
}
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 8c1141d..09c4019 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -22,15 +22,12 @@
#include <dlfcn.h>
-#include "../include/OMX.h"
-
-#include "../include/OMXNodeInstance.h"
-
+#include <media/stagefright/omx/OMX.h>
+#include <media/stagefright/omx/OMXNodeInstance.h>
+#include <media/stagefright/omx/BWGraphicBufferSource.h>
+#include <media/stagefright/omx/OMXMaster.h>
+#include <media/stagefright/omx/OMXUtils.h>
#include <media/stagefright/foundation/ADebug.h>
-#include "BWGraphicBufferSource.h"
-
-#include "OMXMaster.h"
-#include "OMXUtils.h"
namespace android {
@@ -118,15 +115,22 @@
return StatusFromOMXError(err);
}
instance->setHandle(handle);
- std::vector<AString> quirkVector;
- if (mParser.getQuirks(name, &quirkVector) == OK) {
+
+ // Find quirks from mParser
+ const auto& codec = mParser.getCodecMap().find(name);
+ if (codec == mParser.getCodecMap().cend()) {
+ ALOGW("Failed to obtain quirks for omx component '%s' from XML files",
+ name);
+ } else {
uint32_t quirks = 0;
- for (const AString quirk : quirkVector) {
+ for (const auto& quirk : codec->second.quirkSet) {
if (quirk == "requires-allocate-on-input-ports") {
- quirks |= kRequiresAllocateBufferOnInputPorts;
+ quirks |= OMXNodeInstance::
+ kRequiresAllocateBufferOnInputPorts;
}
if (quirk == "requires-allocate-on-output-ports") {
- quirks |= kRequiresAllocateBufferOnOutputPorts;
+ quirks |= OMXNodeInstance::
+ kRequiresAllocateBufferOnOutputPorts;
}
}
instance->setQuirks(quirks);
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index ac9b0c3..fd97fdc 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -18,15 +18,13 @@
#define LOG_TAG "OMXMaster"
#include <utils/Log.h>
-#include "OMXMaster.h"
-
-#include "SoftOMXPlugin.h"
+#include <media/stagefright/omx/OMXMaster.h>
+#include <media/stagefright/omx/SoftOMXPlugin.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <dlfcn.h>
#include <fcntl.h>
-#include <media/stagefright/foundation/ADebug.h>
-
namespace android {
OMXMaster::OMXMaster()
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 035947e..2e7812f 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -20,20 +20,20 @@
#include <inttypes.h>
-#include "../include/OMXNodeInstance.h"
-#include "OMXMaster.h"
-#include "OMXUtils.h"
+#include <media/stagefright/omx/OMXNodeInstance.h>
+#include <media/stagefright/omx/OMXMaster.h>
+#include <media/stagefright/omx/OMXUtils.h>
#include <android/IOMXBufferSource.h>
-#include <OMX_Component.h>
-#include <OMX_IndexExt.h>
-#include <OMX_VideoExt.h>
-#include <OMX_AsString.h>
+#include <media/openmax/OMX_Component.h>
+#include <media/openmax/OMX_IndexExt.h>
+#include <media/openmax/OMX_VideoExt.h>
+#include <media/openmax/OMX_AsString.h>
#include <binder/IMemory.h>
#include <cutils/properties.h>
#include <gui/BufferQueue.h>
-#include <HardwareAPI.h>
+#include <media/hardware/HardwareAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ColorUtils.h>
@@ -41,7 +41,7 @@
#include <utils/misc.h>
#include <utils/NativeHandle.h>
#include <media/OMXBuffer.h>
-#include <media/vndk/xmlparser/1.0/MediaCodecsXmlParser.h>
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
#include <hidlmemory/mapping.h>
@@ -246,6 +246,15 @@
virtual ~CallbackDispatcher();
private:
+ enum {
+ // This is used for frame_rendered message batching, which will eventually end up in a
+ // single AMessage in MediaCodec when it is signaled to the app. AMessage can contain
+ // up-to 64 key-value pairs, and each frame_rendered message uses 2 keys, so the max
+ // value for this would be 32. Nonetheless, limit this to 12 to which gives at least 10
+ // mseconds of batching at 120Hz.
+ kMaxQueueSize = 12,
+ };
+
Mutex mLock;
sp<OMXNodeInstance> const mOwner;
@@ -290,7 +299,7 @@
Mutex::Autolock autoLock(mLock);
mQueue.push_back(msg);
- if (realTime) {
+ if (realTime || mQueue.size() >= kMaxQueueSize) {
mQueueChanged.signal();
}
}
@@ -670,6 +679,11 @@
return BAD_VALUE;
}
+ if (mSailed || mNumPortBuffers[portIndex] > 0) {
+ android_errorWriteLog(0x534e4554, "29422020");
+ return INVALID_OPERATION;
+ }
+
CLOG_CONFIG(setPortMode, "%s(%d), port %d", asString(mode), mode, portIndex);
status_t err = OK;
@@ -1105,7 +1119,6 @@
status_t OMXNodeInstance::useBuffer_l(
OMX_U32 portIndex, const sp<IMemory> ¶ms,
const sp<IHidlMemory> &hParams, IOMX::buffer_id *buffer) {
-
BufferMeta *buffer_meta;
OMX_BUFFERHEADERTYPE *header;
OMX_ERRORTYPE err = OMX_ErrorNone;
@@ -2236,8 +2249,8 @@
msg.fenceFd = -1;
msg.u.render_data.timestamp = renderData[i].nMediaTimeUs;
msg.u.render_data.nanoTime = renderData[i].nSystemTimeNs;
-
- instance->mDispatcher->post(msg, false /* realTime */);
+ bool realTime = msg.u.render_data.timestamp == INT64_MAX;
+ instance->mDispatcher->post(msg, realTime);
}
return OMX_ErrorNone;
}
diff --git a/media/libstagefright/omx/OMXStore.cpp b/media/libstagefright/omx/OMXStore.cpp
new file mode 100644
index 0000000..345336d
--- /dev/null
+++ b/media/libstagefright/omx/OMXStore.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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 "OMXStore"
+#include <utils/Log.h>
+
+#include <media/stagefright/omx/OMXUtils.h>
+#include <media/stagefright/omx/OMX.h>
+#include <media/stagefright/omx/OMXStore.h>
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
+
+#include <map>
+#include <string>
+
+namespace android {
+
+namespace {
+ struct RoleProperties {
+ std::string type;
+ bool isEncoder;
+ bool preferPlatformNodes;
+ std::multimap<size_t, IOMXStore::NodeInfo> nodeList;
+ };
+} // Unnamed namespace
+
+OMXStore::OMXStore(
+ const char* owner,
+ const char* const* searchDirs,
+ const char* mainXmlName,
+ const char* performanceXmlName,
+ const char* profilingResultsXmlPath) {
+ MediaCodecsXmlParser parser(
+ searchDirs,
+ mainXmlName,
+ performanceXmlName,
+ profilingResultsXmlPath);
+ mParsingStatus = parser.getParsingStatus();
+
+ const auto& serviceAttributeMap = parser.getServiceAttributeMap();
+ mServiceAttributeList.reserve(serviceAttributeMap.size());
+ for (const auto& attributePair : serviceAttributeMap) {
+ Attribute attribute;
+ attribute.key = attributePair.first;
+ attribute.value = attributePair.second;
+ mServiceAttributeList.push_back(std::move(attribute));
+ }
+
+ const auto& roleMap = parser.getRoleMap();
+ mRoleList.reserve(roleMap.size());
+ for (const auto& rolePair : roleMap) {
+ RoleInfo role;
+ role.role = rolePair.first;
+ role.type = rolePair.second.type;
+ role.isEncoder = rolePair.second.isEncoder;
+ // TODO: Currently, preferPlatformNodes information is not available in
+ // the xml file. Once we have a way to provide this information, it
+ // should be parsed properly.
+ role.preferPlatformNodes = rolePair.first.compare(0, 5, "audio") == 0;
+ std::vector<NodeInfo>& nodeList = role.nodes;
+ nodeList.reserve(rolePair.second.nodeList.size());
+ for (const auto& nodePair : rolePair.second.nodeList) {
+ NodeInfo node;
+ node.name = nodePair.second.name;
+ node.owner = owner;
+ std::vector<Attribute>& attributeList = node.attributes;
+ attributeList.reserve(nodePair.second.attributeList.size());
+ for (const auto& attributePair : nodePair.second.attributeList) {
+ Attribute attribute;
+ attribute.key = attributePair.first;
+ attribute.value = attributePair.second;
+ attributeList.push_back(std::move(attribute));
+ }
+ nodeList.push_back(std::move(node));
+ }
+ mRoleList.push_back(std::move(role));
+ }
+
+ mPrefix = parser.getCommonPrefix();
+}
+
+status_t OMXStore::listServiceAttributes(std::vector<Attribute>* attributes) {
+ *attributes = mServiceAttributeList;
+ return mParsingStatus;
+}
+
+status_t OMXStore::getNodePrefix(std::string* prefix) {
+ *prefix = mPrefix;
+ return mParsingStatus;
+}
+
+status_t OMXStore::listRoles(std::vector<RoleInfo>* roleList) {
+ *roleList = mRoleList;
+ return mParsingStatus;
+}
+
+status_t OMXStore::getOmx(const std::string& name, sp<IOMX>* omx) {
+ *omx = new OMX();
+ return NO_ERROR;
+}
+
+OMXStore::~OMXStore() {
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/omx/OMXUtils.cpp b/media/libstagefright/omx/OMXUtils.cpp
index a66d565..5894837 100644
--- a/media/libstagefright/omx/OMXUtils.cpp
+++ b/media/libstagefright/omx/OMXUtils.cpp
@@ -19,13 +19,13 @@
#include <string.h>
-#include <media/hardware/HardwareAPI.h>
+#include <media/stagefright/omx/OMXUtils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/hardware/HardwareAPI.h>
#include <media/MediaDefs.h>
#include <system/graphics-base.h>
-#include "OMXUtils.h"
namespace android {
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index d89cb99..87c2411 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -18,8 +18,7 @@
#define LOG_TAG "SimpleSoftOMXComponent"
#include <utils/Log.h>
-#include "include/SimpleSoftOMXComponent.h"
-
+#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
diff --git a/media/libstagefright/omx/SoftOMXComponent.cpp b/media/libstagefright/omx/SoftOMXComponent.cpp
index df978f8..ee269e1 100644
--- a/media/libstagefright/omx/SoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftOMXComponent.cpp
@@ -18,8 +18,7 @@
#define LOG_TAG "SoftOMXComponent"
#include <utils/Log.h>
-#include "include/SoftOMXComponent.h"
-
+#include <media/stagefright/omx/SoftOMXComponent.h>
#include <media/stagefright/foundation/ADebug.h>
namespace android {
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index fccb12b..4946ada 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "SoftOMXPlugin"
#include <utils/Log.h>
-#include "SoftOMXPlugin.h"
-#include "include/SoftOMXComponent.h"
+#include <media/stagefright/omx/SoftOMXPlugin.h>
+#include <media/stagefright/omx/SoftOMXComponent.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
@@ -85,7 +85,21 @@
libName.append(kComponents[i].mLibNameSuffix);
libName.append(".so");
- void *libHandle = dlopen(libName.c_str(), RTLD_NOW);
+ // RTLD_NODELETE means we keep the shared library around forever.
+ // this eliminates thrashing during sequences like loading soundpools.
+ // It also leaves the rest of the logic around the dlopen()/dlclose()
+ // calls in this file unchanged.
+ //
+ // Implications of the change:
+ // -- the codec process (where this happens) will have a slightly larger
+ // long-term memory footprint as it accumulates the loaded shared libraries.
+ // This is expected to be a small amount of memory.
+ // -- plugin codecs can no longer (and never should have) depend on a
+ // free reset of any static data as the library would have crossed
+ // a dlclose/dlopen cycle.
+ //
+
+ void *libHandle = dlopen(libName.c_str(), RTLD_NOW|RTLD_NODELETE);
if (libHandle == NULL) {
ALOGE("unable to dlopen %s: %s", libName.c_str(), dlerror());
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 920dd18..cb811a0 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -20,14 +20,14 @@
#define LOG_TAG "SoftVideoDecoderOMXComponent"
#include <utils/Log.h>
-#include "include/SoftVideoDecoderOMXComponent.h"
+#include <media/stagefright/omx/SoftVideoDecoderOMXComponent.h>
-#include <media/hardware/HardwareAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/MediaDefs.h>
+#include <media/hardware/HardwareAPI.h>
+#include <media/MediaDefs.h>
namespace android {
@@ -182,11 +182,11 @@
uint32_t SoftVideoDecoderOMXComponent::outputBufferWidth() {
- return mIsAdaptive ? mAdaptiveMaxWidth : mWidth;
+ return max(mIsAdaptive ? mAdaptiveMaxWidth : 0, mWidth);
}
uint32_t SoftVideoDecoderOMXComponent::outputBufferHeight() {
- return mIsAdaptive ? mAdaptiveMaxHeight : mHeight;
+ return max(mIsAdaptive ? mAdaptiveMaxHeight : 0, mHeight);
}
void SoftVideoDecoderOMXComponent::handlePortSettingsChange(
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index 41d634a..6e563b7 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -21,25 +21,22 @@
#include <utils/Log.h>
#include <utils/misc.h>
-#include "include/SoftVideoEncoderOMXComponent.h"
-
-#include <media/hardware/HardwareAPI.h>
+#include <media/stagefright/omx/SoftVideoEncoderOMXComponent.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/MediaDefs.h>
+#include <media/hardware/HardwareAPI.h>
+#include <media/openmax/OMX_IndexExt.h>
+#include <media/MediaDefs.h>
#include <ui/Fence.h>
#include <ui/GraphicBufferMapper.h>
#include <ui/Rect.h>
#include <hardware/gralloc.h>
-
#include <nativebase/nativebase.h>
-#include <OMX_IndexExt.h>
-
namespace android {
const static OMX_COLOR_FORMATTYPE kSupportedColorFormats[] = {
diff --git a/media/libstagefright/omx/1.0/Conversion.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
similarity index 99%
rename from media/libstagefright/omx/1.0/Conversion.h
rename to media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
index fd91574..8d8a2d9 100644
--- a/media/libstagefright/omx/1.0/Conversion.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
@@ -29,12 +29,12 @@
#include <binder/Binder.h>
#include <binder/Status.h>
#include <ui/FenceTime.h>
-#include <media/OMXFenceParcelable.h>
#include <cutils/native_handle.h>
#include <gui/IGraphicBufferProducer.h>
+#include <media/OMXFenceParcelable.h>
#include <media/OMXBuffer.h>
-#include <VideoAPI.h>
+#include <media/hardware/VideoAPI.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
@@ -2064,8 +2064,10 @@
int const* constFds = static_cast<int const*>(baseFds.get());
numFds = baseNumFds;
if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
- native_handle_close(nh);
- native_handle_delete(nh);
+ if (nh != nullptr) {
+ native_handle_close(nh);
+ native_handle_delete(nh);
+ }
return false;
}
diff --git a/media/libstagefright/omx/1.0/Omx.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
similarity index 95%
rename from media/libstagefright/omx/1.0/Omx.h
rename to media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
index 23784aa..a6a9d3e 100644
--- a/media/libstagefright/omx/1.0/Omx.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
@@ -20,10 +20,9 @@
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include "../../include/OMXNodeInstance.h"
-
+#include <media/stagefright/omx/OMXNodeInstance.h>
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
-#include <media/vndk/xmlparser/1.0/MediaCodecsXmlParser.h>
namespace android {
diff --git a/media/libstagefright/omx/1.0/OmxStore.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h
similarity index 71%
rename from media/libstagefright/omx/1.0/OmxStore.h
rename to media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h
index f377f5a..006d2d9 100644
--- a/media/libstagefright/omx/1.0/OmxStore.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h
@@ -21,6 +21,7 @@
#include <hidl/Status.h>
#include <android/hardware/media/omx/1.0/IOmxStore.h>
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
namespace android {
namespace hardware {
@@ -41,17 +42,31 @@
using ::android::wp;
struct OmxStore : public IOmxStore {
- OmxStore();
+ OmxStore(
+ const char* owner = "default",
+ const char* const* searchDirs
+ = MediaCodecsXmlParser::defaultSearchDirs,
+ const char* mainXmlName
+ = MediaCodecsXmlParser::defaultMainXmlName,
+ const char* performanceXmlName
+ = MediaCodecsXmlParser::defaultPerformanceXmlName,
+ const char* profilingResultsXmlPath
+ = MediaCodecsXmlParser::defaultProfilingResultsXmlPath);
+
virtual ~OmxStore();
- // Methods from IOmx
+ // Methods from IOmxStore
Return<void> listServiceAttributes(listServiceAttributes_cb) override;
Return<void> getNodePrefix(getNodePrefix_cb) override;
Return<void> listRoles(listRoles_cb) override;
Return<sp<IOmx>> getOmx(hidl_string const&) override;
-};
-extern "C" IOmxStore* HIDL_FETCH_IOmxStore(const char* name);
+protected:
+ Status mParsingStatus;
+ hidl_string mPrefix;
+ hidl_vec<ServiceAttribute> mServiceAttributeList;
+ hidl_vec<RoleInfo> mRoleList;
+};
} // namespace implementation
} // namespace V1_0
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferProducer.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferProducer.h
similarity index 100%
rename from media/libstagefright/omx/1.0/WGraphicBufferProducer.h
rename to media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferProducer.h
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h
similarity index 98%
rename from media/libstagefright/omx/1.0/WGraphicBufferSource.h
rename to media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h
index 4549c97..b9f22ab 100644
--- a/media/libstagefright/omx/1.0/WGraphicBufferSource.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h
@@ -28,7 +28,7 @@
#include <android/BnGraphicBufferSource.h>
-#include "../GraphicBufferSource.h"
+#include <media/stagefright/omx/GraphicBufferSource.h>
namespace android {
namespace hardware {
diff --git a/media/libstagefright/omx/1.0/WOmxBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WOmxBufferSource.h
similarity index 100%
rename from media/libstagefright/omx/1.0/WOmxBufferSource.h
rename to media/libstagefright/omx/include/media/stagefright/omx/1.0/WOmxBufferSource.h
diff --git a/media/libstagefright/omx/1.0/WOmxNode.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WOmxNode.h
similarity index 98%
rename from media/libstagefright/omx/1.0/WOmxNode.h
rename to media/libstagefright/omx/include/media/stagefright/omx/1.0/WOmxNode.h
index d715374..38d5885 100644
--- a/media/libstagefright/omx/1.0/WOmxNode.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WOmxNode.h
@@ -22,7 +22,7 @@
#include <utils/Errors.h>
-#include "../../include/OMXNodeInstance.h"
+#include <media/stagefright/omx/OMXNodeInstance.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <android/hardware/media/omx/1.0/IOmxObserver.h>
diff --git a/media/libstagefright/omx/1.0/WOmxObserver.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WOmxObserver.h
similarity index 100%
rename from media/libstagefright/omx/1.0/WOmxObserver.h
rename to media/libstagefright/omx/include/media/stagefright/omx/1.0/WOmxObserver.h
diff --git a/media/libstagefright/omx/1.0/WProducerListener.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WProducerListener.h
similarity index 100%
rename from media/libstagefright/omx/1.0/WProducerListener.h
rename to media/libstagefright/omx/include/media/stagefright/omx/1.0/WProducerListener.h
diff --git a/media/libstagefright/omx/BWGraphicBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/BWGraphicBufferSource.h
similarity index 100%
rename from media/libstagefright/omx/BWGraphicBufferSource.h
rename to media/libstagefright/omx/include/media/stagefright/omx/BWGraphicBufferSource.h
diff --git a/media/libstagefright/omx/FrameDropper.h b/media/libstagefright/omx/include/media/stagefright/omx/FrameDropper.h
similarity index 100%
rename from media/libstagefright/omx/FrameDropper.h
rename to media/libstagefright/omx/include/media/stagefright/omx/FrameDropper.h
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/GraphicBufferSource.h
similarity index 98%
rename from media/libstagefright/omx/GraphicBufferSource.h
rename to media/libstagefright/omx/include/media/stagefright/omx/GraphicBufferSource.h
index 29b51a8..84fee6f 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/GraphicBufferSource.h
@@ -22,7 +22,7 @@
#include <gui/BufferQueue.h>
#include <utils/RefBase.h>
-#include <VideoAPI.h>
+#include <media/hardware/VideoAPI.h>
#include <media/IOMX.h>
#include <media/OMXFenceParcelable.h>
#include <media/stagefright/foundation/ABase.h>
@@ -264,8 +264,8 @@
void onBufferAcquired_l(const VideoBuffer &buffer);
// marks the buffer at the slot no longer cached, and accounts for the outstanding
- // acquire count
- void discardBufferInSlot_l(slot_id i);
+ // acquire count. Returns true if the slot was populated; otherwise, false.
+ bool discardBufferInSlot_l(slot_id i);
// marks the buffer at the slot index no longer cached, and accounts for the outstanding
// acquire count
diff --git a/media/libstagefright/omx/IOmxNodeWrapper.h b/media/libstagefright/omx/include/media/stagefright/omx/IOmxNodeWrapper.h
similarity index 100%
rename from media/libstagefright/omx/IOmxNodeWrapper.h
rename to media/libstagefright/omx/include/media/stagefright/omx/IOmxNodeWrapper.h
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/omx/include/media/stagefright/omx/OMX.h
similarity index 96%
rename from media/libstagefright/include/OMX.h
rename to media/libstagefright/omx/include/media/stagefright/omx/OMX.h
index 4af3d39..594b4c0 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMX.h
@@ -20,7 +20,7 @@
#include <media/IOMX.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
-#include <media/vndk/xmlparser/1.0/MediaCodecsXmlParser.h>
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
#include "OmxNodeOwner.h"
namespace android {
diff --git a/media/libstagefright/omx/OMXMaster.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXMaster.h
similarity index 97%
rename from media/libstagefright/omx/OMXMaster.h
rename to media/libstagefright/omx/include/media/stagefright/omx/OMXMaster.h
index 3f9c0ca..897f287 100644
--- a/media/libstagefright/omx/OMXMaster.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMXMaster.h
@@ -18,7 +18,7 @@
#define OMX_MASTER_H_
-#include <OMXPluginBase.h>
+#include <media/hardware/OMXPluginBase.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
similarity index 96%
rename from media/libstagefright/include/OMXNodeInstance.h
rename to media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
index 00c37e1..1065ca5 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
@@ -92,6 +92,15 @@
status_t getExtensionIndex(
const char *parameterName, OMX_INDEXTYPE *index);
+ // Quirk still supported, even though deprecated
+ enum Quirks {
+ kRequiresAllocateBufferOnInputPorts = 1,
+ kRequiresAllocateBufferOnOutputPorts = 2,
+
+ kQuirksMask = kRequiresAllocateBufferOnInputPorts
+ | kRequiresAllocateBufferOnOutputPorts,
+ };
+
status_t setQuirks(OMX_U32 quirks);
bool isSecure() const {
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h
new file mode 100644
index 0000000..e00d713
--- /dev/null
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_OMXSTORE_H_
+#define ANDROID_OMXSTORE_H_
+
+#include <media/IOMXStore.h>
+#include <media/IOMX.h>
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
+
+#include <vector>
+#include <string>
+
+namespace android {
+
+class OMXStore : public BnOMXStore {
+public:
+ OMXStore(
+ const char* owner = "default",
+ const char* const* searchDirs
+ = MediaCodecsXmlParser::defaultSearchDirs,
+ const char* mainXmlName
+ = MediaCodecsXmlParser::defaultMainXmlName,
+ const char* performanceXmlName
+ = MediaCodecsXmlParser::defaultPerformanceXmlName,
+ const char* profilingResultsXmlPath
+ = MediaCodecsXmlParser::defaultProfilingResultsXmlPath);
+
+ status_t listServiceAttributes(
+ std::vector<Attribute>* attributes) override;
+
+ status_t getNodePrefix(std::string* prefix) override;
+
+ status_t listRoles(std::vector<RoleInfo>* roleList) override;
+
+ status_t getOmx(const std::string& name, sp<IOMX>* omx) override;
+
+ ~OMXStore() override;
+
+protected:
+ status_t mParsingStatus;
+ std::string mPrefix;
+ std::vector<Attribute> mServiceAttributeList;
+ std::vector<RoleInfo> mRoleList;
+};
+
+} // namespace android
+
+#endif // ANDROID_OMXSTORE_H_
diff --git a/media/libstagefright/omx/OMXUtils.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXUtils.h
similarity index 100%
rename from media/libstagefright/omx/OMXUtils.h
rename to media/libstagefright/omx/include/media/stagefright/omx/OMXUtils.h
diff --git a/media/libstagefright/include/SimpleSoftOMXComponent.h b/media/libstagefright/omx/include/media/stagefright/omx/SimpleSoftOMXComponent.h
similarity index 100%
rename from media/libstagefright/include/SimpleSoftOMXComponent.h
rename to media/libstagefright/omx/include/media/stagefright/omx/SimpleSoftOMXComponent.h
diff --git a/media/libstagefright/include/SoftOMXComponent.h b/media/libstagefright/omx/include/media/stagefright/omx/SoftOMXComponent.h
similarity index 100%
rename from media/libstagefright/include/SoftOMXComponent.h
rename to media/libstagefright/omx/include/media/stagefright/omx/SoftOMXComponent.h
diff --git a/media/libstagefright/omx/SoftOMXPlugin.h b/media/libstagefright/omx/include/media/stagefright/omx/SoftOMXPlugin.h
similarity index 96%
rename from media/libstagefright/omx/SoftOMXPlugin.h
rename to media/libstagefright/omx/include/media/stagefright/omx/SoftOMXPlugin.h
index c89cd87..8ec717e 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/SoftOMXPlugin.h
@@ -19,7 +19,7 @@
#define SOFT_OMX_PLUGIN_H_
#include <media/stagefright/foundation/ABase.h>
-#include <OMXPluginBase.h>
+#include <media/hardware/OMXPluginBase.h>
namespace android {
diff --git a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h b/media/libstagefright/omx/include/media/stagefright/omx/SoftVideoDecoderOMXComponent.h
similarity index 100%
rename from media/libstagefright/include/SoftVideoDecoderOMXComponent.h
rename to media/libstagefright/omx/include/media/stagefright/omx/SoftVideoDecoderOMXComponent.h
diff --git a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h b/media/libstagefright/omx/include/media/stagefright/omx/SoftVideoEncoderOMXComponent.h
similarity index 100%
rename from media/libstagefright/include/SoftVideoEncoderOMXComponent.h
rename to media/libstagefright/omx/include/media/stagefright/omx/SoftVideoEncoderOMXComponent.h
diff --git a/media/libstagefright/omx/tests/FrameDropper_test.cpp b/media/libstagefright/omx/tests/FrameDropper_test.cpp
index f966b5e..a925da6 100644
--- a/media/libstagefright/omx/tests/FrameDropper_test.cpp
+++ b/media/libstagefright/omx/tests/FrameDropper_test.cpp
@@ -20,7 +20,7 @@
#include <gtest/gtest.h>
-#include "FrameDropper.h"
+#include <media/stagefright/omx/FrameDropper.h>
#include <media/stagefright/foundation/ADebug.h>
namespace android {
diff --git a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
index 2599608..0c22a42 100644
--- a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
+++ b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
@@ -26,6 +26,8 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaCodecList.h>
+#include <vector>
+
namespace android {
static const char kTestOverridesStr[] =
@@ -117,7 +119,7 @@
// TODO: the codec component never returns OMX_EventCmdComplete in unit test.
TEST_F(MediaCodecListOverridesTest, DISABLED_profileCodecs) {
sp<IMediaCodecList> list = MediaCodecList::getInstance();
- Vector<sp<MediaCodecInfo>> infos;
+ std::vector<sp<MediaCodecInfo>> infos;
for (size_t i = 0; i < list->countCodecs(); ++i) {
infos.push_back(list->getCodecInfo(i));
}
diff --git a/media/vndk/xmlparser/1.0/Android.bp b/media/libstagefright/xmlparser/Android.bp
similarity index 67%
rename from media/vndk/xmlparser/1.0/Android.bp
rename to media/libstagefright/xmlparser/Android.bp
index 2f10cb1..3507284 100644
--- a/media/vndk/xmlparser/1.0/Android.bp
+++ b/media/libstagefright/xmlparser/Android.bp
@@ -1,14 +1,16 @@
cc_library_shared {
- name: "libstagefright_xmlparser@1.0",
+ name: "libstagefright_xmlparser",
vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: [
"MediaCodecsXmlParser.cpp",
],
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/av/include",
+ export_include_dirs: [
+ "include",
],
shared_libs: [
@@ -17,6 +19,7 @@
"liblog",
"libcutils",
"libstagefright_foundation",
+ "libstagefright_omx_utils",
],
cflags: [
@@ -31,6 +34,10 @@
"unsigned-integer-overflow",
"signed-integer-overflow",
],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
},
}
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
new file mode 100644
index 0000000..ffd30ea
--- /dev/null
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -0,0 +1,1054 @@
+/*
+ * Copyright 2017, 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 "MediaCodecsXmlParser"
+
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
+
+#include <utils/Log.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/omx/OMXUtils.h>
+#include <sys/stat.h>
+#include <expat.h>
+
+#include <cctype>
+#include <algorithm>
+
+namespace android {
+
+namespace {
+
+/**
+ * Search for a file in a list of search directories.
+ *
+ * For each string `searchDir` in `searchDirs`, `searchDir/fileName` will be
+ * tested whether it is a valid file name or not. If it is a valid file name,
+ * the concatenated name (`searchDir/fileName`) will be stored in the output
+ * variable `outPath`, and the function will return `true`. Otherwise, the
+ * search continues until the `nullptr` element in `searchDirs` is reached, at
+ * which point the function returns `false`.
+ *
+ * \param[in] searchDirs Null-terminated array of search paths.
+ * \param[in] fileName Name of the file to search.
+ * \param[out] outPath Full path of the file. `outPath` will hold a valid file
+ * name if the return value of this function is `true`.
+ * \return `true` if some element in `searchDirs` combined with `fileName` is a
+ * valid file name; `false` otherwise.
+ */
+bool findFileInDirs(
+ const char* const* searchDirs,
+ const char *fileName,
+ std::string *outPath) {
+ for (; *searchDirs != nullptr; ++searchDirs) {
+ *outPath = std::string(*searchDirs) + "/" + fileName;
+ struct stat fileStat;
+ if (stat(outPath->c_str(), &fileStat) == 0 &&
+ S_ISREG(fileStat.st_mode)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool strnEq(const char* s1, const char* s2, size_t count) {
+ return strncmp(s1, s2, count) == 0;
+}
+
+bool strEq(const char* s1, const char* s2) {
+ return strcmp(s1, s2) == 0;
+}
+
+bool striEq(const char* s1, const char* s2) {
+ return strcasecmp(s1, s2) == 0;
+}
+
+bool strHasPrefix(const char* test, const char* prefix) {
+ return strnEq(test, prefix, strlen(prefix));
+}
+
+bool parseBoolean(const char* s) {
+ return striEq(s, "y") ||
+ striEq(s, "yes") ||
+ striEq(s, "t") ||
+ striEq(s, "true") ||
+ striEq(s, "1");
+}
+
+status_t limitFoundMissingAttr(const char* name, const char *attr, bool found = true) {
+ ALOGE("limit '%s' with %s'%s' attribute", name,
+ (found ? "" : "no "), attr);
+ return -EINVAL;
+}
+
+status_t limitError(const char* name, const char *msg) {
+ ALOGE("limit '%s' %s", name, msg);
+ return -EINVAL;
+}
+
+status_t limitInvalidAttr(const char* name, const char* attr, const char* value) {
+ ALOGE("limit '%s' with invalid '%s' attribute (%s)", name,
+ attr, value);
+ return -EINVAL;
+}
+
+}; // unnamed namespace
+
+constexpr char const* MediaCodecsXmlParser::defaultSearchDirs[];
+constexpr char const* MediaCodecsXmlParser::defaultMainXmlName;
+constexpr char const* MediaCodecsXmlParser::defaultPerformanceXmlName;
+constexpr char const* MediaCodecsXmlParser::defaultProfilingResultsXmlPath;
+
+MediaCodecsXmlParser::MediaCodecsXmlParser(
+ const char* const* searchDirs,
+ const char* mainXmlName,
+ const char* performanceXmlName,
+ const char* profilingResultsXmlPath) :
+ mParsingStatus(NO_INIT),
+ mUpdate(false),
+ mCodecCounter(0) {
+ std::string path;
+ if (findFileInDirs(searchDirs, mainXmlName, &path)) {
+ parseTopLevelXMLFile(path.c_str(), false);
+ } else {
+ ALOGE("Cannot find %s", mainXmlName);
+ mParsingStatus = NAME_NOT_FOUND;
+ }
+ if (findFileInDirs(searchDirs, performanceXmlName, &path)) {
+ parseTopLevelXMLFile(path.c_str(), true);
+ }
+ if (profilingResultsXmlPath != nullptr) {
+ parseTopLevelXMLFile(profilingResultsXmlPath, true);
+ }
+}
+
+bool MediaCodecsXmlParser::parseTopLevelXMLFile(
+ const char *codecs_xml,
+ bool ignore_errors) {
+ // get href_base
+ const char *href_base_end = strrchr(codecs_xml, '/');
+ if (href_base_end != nullptr) {
+ mHrefBase = std::string(codecs_xml, href_base_end - codecs_xml + 1);
+ }
+
+ mParsingStatus = OK; // keeping this here for safety
+ mCurrentSection = SECTION_TOPLEVEL;
+
+ parseXMLFile(codecs_xml);
+
+ if (mParsingStatus != OK) {
+ ALOGW("parseTopLevelXMLFile(%s) failed", codecs_xml);
+ if (ignore_errors) {
+ mParsingStatus = OK;
+ return false;
+ }
+ mCodecMap.clear();
+ return false;
+ }
+ return true;
+}
+
+MediaCodecsXmlParser::~MediaCodecsXmlParser() {
+}
+
+void MediaCodecsXmlParser::parseXMLFile(const char *path) {
+ FILE *file = fopen(path, "r");
+
+ if (file == nullptr) {
+ ALOGW("unable to open media codecs configuration xml file: %s", path);
+ mParsingStatus = NAME_NOT_FOUND;
+ return;
+ }
+
+ XML_Parser parser = ::XML_ParserCreate(nullptr);
+ LOG_FATAL_IF(parser == nullptr, "XML_MediaCodecsXmlParserCreate() failed.");
+
+ ::XML_SetUserData(parser, this);
+ ::XML_SetElementHandler(
+ parser, StartElementHandlerWrapper, EndElementHandlerWrapper);
+
+ static constexpr int BUFF_SIZE = 512;
+ while (mParsingStatus == OK) {
+ void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
+ if (buff == nullptr) {
+ ALOGE("failed in call to XML_GetBuffer()");
+ mParsingStatus = UNKNOWN_ERROR;
+ break;
+ }
+
+ int bytes_read = ::fread(buff, 1, BUFF_SIZE, file);
+ if (bytes_read < 0) {
+ ALOGE("failed in call to read");
+ mParsingStatus = ERROR_IO;
+ break;
+ }
+
+ XML_Status status = ::XML_ParseBuffer(parser, bytes_read, bytes_read == 0);
+ if (status != XML_STATUS_OK) {
+ ALOGE("malformed (%s)", ::XML_ErrorString(::XML_GetErrorCode(parser)));
+ mParsingStatus = ERROR_MALFORMED;
+ break;
+ }
+
+ if (bytes_read == 0) {
+ break;
+ }
+ }
+
+ ::XML_ParserFree(parser);
+
+ fclose(file);
+ file = nullptr;
+}
+
+// static
+void MediaCodecsXmlParser::StartElementHandlerWrapper(
+ void *me, const char *name, const char **attrs) {
+ static_cast<MediaCodecsXmlParser*>(me)->startElementHandler(name, attrs);
+}
+
+// static
+void MediaCodecsXmlParser::EndElementHandlerWrapper(void *me, const char *name) {
+ static_cast<MediaCodecsXmlParser*>(me)->endElementHandler(name);
+}
+
+status_t MediaCodecsXmlParser::includeXMLFile(const char **attrs) {
+ const char *href = nullptr;
+ size_t i = 0;
+ while (attrs[i] != nullptr) {
+ if (strEq(attrs[i], "href")) {
+ if (attrs[++i] == nullptr) {
+ return -EINVAL;
+ }
+ href = attrs[i];
+ } else {
+ ALOGE("includeXMLFile: unrecognized attribute: %s", attrs[i]);
+ return -EINVAL;
+ }
+ ++i;
+ }
+
+ // For security reasons and for simplicity, file names can only contain
+ // [a-zA-Z0-9_.] and must start with media_codecs_ and end with .xml
+ for (i = 0; href[i] != '\0'; i++) {
+ if (href[i] == '.' || href[i] == '_' ||
+ (href[i] >= '0' && href[i] <= '9') ||
+ (href[i] >= 'A' && href[i] <= 'Z') ||
+ (href[i] >= 'a' && href[i] <= 'z')) {
+ continue;
+ }
+ ALOGE("invalid include file name: %s", href);
+ return -EINVAL;
+ }
+
+ std::string filename = href;
+ if (filename.compare(0, 13, "media_codecs_") != 0 ||
+ filename.compare(filename.size() - 4, 4, ".xml") != 0) {
+ ALOGE("invalid include file name: %s", href);
+ return -EINVAL;
+ }
+ filename.insert(0, mHrefBase);
+
+ parseXMLFile(filename.c_str());
+ return mParsingStatus;
+}
+
+void MediaCodecsXmlParser::startElementHandler(
+ const char *name, const char **attrs) {
+ if (mParsingStatus != OK) {
+ return;
+ }
+
+ bool inType = true;
+
+ if (strEq(name, "Include")) {
+ mParsingStatus = includeXMLFile(attrs);
+ if (mParsingStatus == OK) {
+ mSectionStack.push_back(mCurrentSection);
+ mCurrentSection = SECTION_INCLUDE;
+ }
+ return;
+ }
+
+ switch (mCurrentSection) {
+ case SECTION_TOPLEVEL:
+ {
+ if (strEq(name, "Decoders")) {
+ mCurrentSection = SECTION_DECODERS;
+ } else if (strEq(name, "Encoders")) {
+ mCurrentSection = SECTION_ENCODERS;
+ } else if (strEq(name, "Settings")) {
+ mCurrentSection = SECTION_SETTINGS;
+ }
+ break;
+ }
+
+ case SECTION_SETTINGS:
+ {
+ if (strEq(name, "Setting")) {
+ mParsingStatus = addSettingFromAttributes(attrs);
+ }
+ break;
+ }
+
+ case SECTION_DECODERS:
+ {
+ if (strEq(name, "MediaCodec")) {
+ mParsingStatus =
+ addMediaCodecFromAttributes(false /* encoder */, attrs);
+
+ mCurrentSection = SECTION_DECODER;
+ }
+ break;
+ }
+
+ case SECTION_ENCODERS:
+ {
+ if (strEq(name, "MediaCodec")) {
+ mParsingStatus =
+ addMediaCodecFromAttributes(true /* encoder */, attrs);
+
+ mCurrentSection = SECTION_ENCODER;
+ }
+ break;
+ }
+
+ case SECTION_DECODER:
+ case SECTION_ENCODER:
+ {
+ if (strEq(name, "Quirk")) {
+ mParsingStatus = addQuirk(attrs);
+ } else if (strEq(name, "Type")) {
+ mParsingStatus = addTypeFromAttributes(attrs,
+ (mCurrentSection == SECTION_ENCODER));
+ mCurrentSection =
+ (mCurrentSection == SECTION_DECODER ?
+ SECTION_DECODER_TYPE : SECTION_ENCODER_TYPE);
+ }
+ }
+ inType = false;
+ // fall through
+
+ case SECTION_DECODER_TYPE:
+ case SECTION_ENCODER_TYPE:
+ {
+ // ignore limits and features specified outside of type
+ bool outside = !inType &&
+ mCurrentType == mCurrentCodec->second.typeMap.end();
+ if (outside &&
+ (strEq(name, "Limit") || strEq(name, "Feature"))) {
+ ALOGW("ignoring %s specified outside of a Type", name);
+ } else if (strEq(name, "Limit")) {
+ mParsingStatus = addLimit(attrs);
+ } else if (strEq(name, "Feature")) {
+ mParsingStatus = addFeature(attrs);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+}
+
+void MediaCodecsXmlParser::endElementHandler(const char *name) {
+ if (mParsingStatus != OK) {
+ return;
+ }
+
+ switch (mCurrentSection) {
+ case SECTION_SETTINGS:
+ {
+ if (strEq(name, "Settings")) {
+ mCurrentSection = SECTION_TOPLEVEL;
+ }
+ break;
+ }
+
+ case SECTION_DECODERS:
+ {
+ if (strEq(name, "Decoders")) {
+ mCurrentSection = SECTION_TOPLEVEL;
+ }
+ break;
+ }
+
+ case SECTION_ENCODERS:
+ {
+ if (strEq(name, "Encoders")) {
+ mCurrentSection = SECTION_TOPLEVEL;
+ }
+ break;
+ }
+
+ case SECTION_DECODER_TYPE:
+ case SECTION_ENCODER_TYPE:
+ {
+ if (strEq(name, "Type")) {
+ mCurrentSection =
+ (mCurrentSection == SECTION_DECODER_TYPE ?
+ SECTION_DECODER : SECTION_ENCODER);
+
+ mCurrentType = mCurrentCodec->second.typeMap.end();
+ }
+ break;
+ }
+
+ case SECTION_DECODER:
+ {
+ if (strEq(name, "MediaCodec")) {
+ mCurrentSection = SECTION_DECODERS;
+ mCurrentName.clear();
+ }
+ break;
+ }
+
+ case SECTION_ENCODER:
+ {
+ if (strEq(name, "MediaCodec")) {
+ mCurrentSection = SECTION_ENCODERS;
+ mCurrentName.clear();
+ }
+ break;
+ }
+
+ case SECTION_INCLUDE:
+ {
+ if (strEq(name, "Include") && (mSectionStack.size() > 0)) {
+ mCurrentSection = mSectionStack.back();
+ mSectionStack.pop_back();
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+}
+
+status_t MediaCodecsXmlParser::addSettingFromAttributes(const char **attrs) {
+ const char *name = nullptr;
+ const char *value = nullptr;
+ const char *update = nullptr;
+
+ size_t i = 0;
+ while (attrs[i] != nullptr) {
+ if (strEq(attrs[i], "name")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addSettingFromAttributes: name is null");
+ return -EINVAL;
+ }
+ name = attrs[i];
+ } else if (strEq(attrs[i], "value")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addSettingFromAttributes: value is null");
+ return -EINVAL;
+ }
+ value = attrs[i];
+ } else if (strEq(attrs[i], "update")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addSettingFromAttributes: update is null");
+ return -EINVAL;
+ }
+ update = attrs[i];
+ } else {
+ ALOGE("addSettingFromAttributes: unrecognized attribute: %s", attrs[i]);
+ return -EINVAL;
+ }
+ ++i;
+ }
+
+ if (name == nullptr || value == nullptr) {
+ ALOGE("addSettingFromAttributes: name or value unspecified");
+ return -EINVAL;
+ }
+
+ // Boolean values are converted to "0" or "1".
+ if (strHasPrefix(name, "supports-")) {
+ value = parseBoolean(value) ? "1" : "0";
+ }
+
+ mUpdate = (update != nullptr) && parseBoolean(update);
+ auto attribute = mServiceAttributeMap.find(name);
+ if (attribute == mServiceAttributeMap.end()) { // New attribute name
+ if (mUpdate) {
+ ALOGE("addSettingFromAttributes: updating non-existing setting");
+ return -EINVAL;
+ }
+ mServiceAttributeMap.insert(Attribute(name, value));
+ } else { // Existing attribute name
+ if (!mUpdate) {
+ ALOGE("addSettingFromAttributes: adding existing setting");
+ }
+ attribute->second = value;
+ }
+
+ return OK;
+}
+
+status_t MediaCodecsXmlParser::addMediaCodecFromAttributes(
+ bool encoder, const char **attrs) {
+ const char *name = nullptr;
+ const char *type = nullptr;
+ const char *update = nullptr;
+
+ size_t i = 0;
+ while (attrs[i] != nullptr) {
+ if (strEq(attrs[i], "name")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addMediaCodecFromAttributes: name is null");
+ return -EINVAL;
+ }
+ name = attrs[i];
+ } else if (strEq(attrs[i], "type")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addMediaCodecFromAttributes: type is null");
+ return -EINVAL;
+ }
+ type = attrs[i];
+ } else if (strEq(attrs[i], "update")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addMediaCodecFromAttributes: update is null");
+ return -EINVAL;
+ }
+ update = attrs[i];
+ } else {
+ ALOGE("addMediaCodecFromAttributes: unrecognized attribute: %s", attrs[i]);
+ return -EINVAL;
+ }
+ ++i;
+ }
+
+ if (name == nullptr) {
+ ALOGE("addMediaCodecFromAttributes: name not found");
+ return -EINVAL;
+ }
+
+ mUpdate = (update != nullptr) && parseBoolean(update);
+ mCurrentCodec = mCodecMap.find(name);
+ if (mCurrentCodec == mCodecMap.end()) { // New codec name
+ if (mUpdate) {
+ ALOGE("addMediaCodecFromAttributes: updating non-existing codec");
+ return -EINVAL;
+ }
+ // Create a new codec in mCodecMap
+ mCurrentCodec = mCodecMap.insert(
+ Codec(name, CodecProperties())).first;
+ if (type != nullptr) {
+ mCurrentType = mCurrentCodec->second.typeMap.insert(
+ Type(type, AttributeMap())).first;
+ } else {
+ mCurrentType = mCurrentCodec->second.typeMap.end();
+ }
+ mCurrentCodec->second.isEncoder = encoder;
+ mCurrentCodec->second.order = mCodecCounter++;
+ } else { // Existing codec name
+ if (!mUpdate) {
+ ALOGE("addMediaCodecFromAttributes: adding existing codec");
+ return -EINVAL;
+ }
+ if (type != nullptr) {
+ mCurrentType = mCurrentCodec->second.typeMap.find(type);
+ if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
+ ALOGE("addMediaCodecFromAttributes: updating non-existing type");
+ return -EINVAL;
+ }
+ } else {
+ // This should happen only when the codec has at most one type.
+ mCurrentType = mCurrentCodec->second.typeMap.begin();
+ }
+ }
+
+ return OK;
+}
+
+status_t MediaCodecsXmlParser::addQuirk(const char **attrs) {
+ const char *name = nullptr;
+
+ size_t i = 0;
+ while (attrs[i] != nullptr) {
+ if (strEq(attrs[i], "name")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addQuirk: name is null");
+ return -EINVAL;
+ }
+ name = attrs[i];
+ } else {
+ ALOGE("addQuirk: unrecognized attribute: %s", attrs[i]);
+ return -EINVAL;
+ }
+ ++i;
+ }
+
+ if (name == nullptr) {
+ ALOGE("addQuirk: name not found");
+ return -EINVAL;
+ }
+
+ mCurrentCodec->second.quirkSet.emplace(name);
+ return OK;
+}
+
+status_t MediaCodecsXmlParser::addTypeFromAttributes(const char **attrs, bool encoder) {
+ const char *name = nullptr;
+ const char *update = nullptr;
+
+ size_t i = 0;
+ while (attrs[i] != nullptr) {
+ if (strEq(attrs[i], "name")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addTypeFromAttributes: name is null");
+ return -EINVAL;
+ }
+ name = attrs[i];
+ } else if (strEq(attrs[i], "update")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addTypeFromAttributes: update is null");
+ return -EINVAL;
+ }
+ update = attrs[i];
+ } else {
+ ALOGE("addTypeFromAttributes: unrecognized attribute: %s", attrs[i]);
+ return -EINVAL;
+ }
+ ++i;
+ }
+
+ if (name == nullptr) {
+ return -EINVAL;
+ }
+
+ mCurrentCodec->second.isEncoder = encoder;
+ mCurrentType = mCurrentCodec->second.typeMap.find(name);
+ if (!mUpdate) {
+ if (mCurrentType != mCurrentCodec->second.typeMap.end()) {
+ ALOGE("addTypeFromAttributes: re-defining existing type without update");
+ return -EINVAL;
+ }
+ mCurrentType = mCurrentCodec->second.typeMap.insert(
+ Type(name, AttributeMap())).first;
+ } else if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
+ ALOGE("addTypeFromAttributes: updating non-existing type");
+ }
+ return OK;
+}
+
+status_t MediaCodecsXmlParser::addLimit(const char **attrs) {
+ const char* a_name = nullptr;
+ const char* a_default = nullptr;
+ const char* a_in = nullptr;
+ const char* a_max = nullptr;
+ const char* a_min = nullptr;
+ const char* a_range = nullptr;
+ const char* a_ranges = nullptr;
+ const char* a_scale = nullptr;
+ const char* a_value = nullptr;
+
+ size_t i = 0;
+ while (attrs[i] != nullptr) {
+ if (strEq(attrs[i], "name")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addLimit: name is null");
+ return -EINVAL;
+ }
+ a_name = attrs[i];
+ } else if (strEq(attrs[i], "default")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addLimit: default is null");
+ return -EINVAL;
+ }
+ a_default = attrs[i];
+ } else if (strEq(attrs[i], "in")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addLimit: in is null");
+ return -EINVAL;
+ }
+ a_in = attrs[i];
+ } else if (strEq(attrs[i], "max")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addLimit: max is null");
+ return -EINVAL;
+ }
+ a_max = attrs[i];
+ } else if (strEq(attrs[i], "min")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addLimit: min is null");
+ return -EINVAL;
+ }
+ a_min = attrs[i];
+ } else if (strEq(attrs[i], "range")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addLimit: range is null");
+ return -EINVAL;
+ }
+ a_range = attrs[i];
+ } else if (strEq(attrs[i], "ranges")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addLimit: ranges is null");
+ return -EINVAL;
+ }
+ a_ranges = attrs[i];
+ } else if (strEq(attrs[i], "scale")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addLimit: scale is null");
+ return -EINVAL;
+ }
+ a_scale = attrs[i];
+ } else if (strEq(attrs[i], "value")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addLimit: value is null");
+ return -EINVAL;
+ }
+ a_value = attrs[i];
+ } else {
+ ALOGE("addLimit: unrecognized limit: %s", attrs[i]);
+ return -EINVAL;
+ }
+ ++i;
+ }
+
+ if (a_name == nullptr) {
+ ALOGE("limit with no 'name' attribute");
+ return -EINVAL;
+ }
+
+ // size, blocks, bitrate, frame-rate, blocks-per-second, aspect-ratio,
+ // measured-frame-rate, measured-blocks-per-second: range
+ // quality: range + default + [scale]
+ // complexity: range + default
+ if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
+ ALOGW("ignoring null type");
+ return OK;
+ }
+
+ std::string range;
+ if (strEq(a_name, "aspect-ratio") ||
+ strEq(a_name, "bitrate") ||
+ strEq(a_name, "block-count") ||
+ strEq(a_name, "blocks-per-second") ||
+ strEq(a_name, "complexity") ||
+ strEq(a_name, "frame-rate") ||
+ strEq(a_name, "quality") ||
+ strEq(a_name, "size") ||
+ strEq(a_name, "measured-blocks-per-second") ||
+ strHasPrefix(a_name, "measured-frame-rate-")) {
+ // "range" is specified in exactly one of the following forms:
+ // 1) min-max
+ // 2) value-value
+ // 3) range
+ if (a_min != nullptr && a_max != nullptr) {
+ // min-max
+ if (a_range != nullptr || a_value != nullptr) {
+ return limitError(a_name, "has 'min' and 'max' as well as 'range' or "
+ "'value' attributes");
+ }
+ range = a_min;
+ range += '-';
+ range += a_max;
+ } else if (a_min != nullptr || a_max != nullptr) {
+ return limitError(a_name, "has only 'min' or 'max' attribute");
+ } else if (a_value != nullptr) {
+ // value-value
+ if (a_range != nullptr) {
+ return limitError(a_name, "has both 'range' and 'value' attributes");
+ }
+ range = a_value;
+ range += '-';
+ range += a_value;
+ } else if (a_range == nullptr) {
+ return limitError(a_name, "with no 'range', 'value' or 'min'/'max' attributes");
+ } else {
+ // range
+ range = a_range;
+ }
+
+ // "aspect-ratio" requires some special treatment.
+ if (strEq(a_name, "aspect-ratio")) {
+ // "aspect-ratio" must have "in".
+ if (a_in == nullptr) {
+ return limitFoundMissingAttr(a_name, "in", false);
+ }
+ // "in" must be either "pixels" or "blocks".
+ if (!strEq(a_in, "pixels") && !strEq(a_in, "blocks")) {
+ return limitInvalidAttr(a_name, "in", a_in);
+ }
+ // name will be "pixel-aspect-ratio-range" or
+ // "block-aspect-ratio-range".
+ mCurrentType->second[
+ std::string(a_in).substr(0, strlen(a_in) - 1) +
+ "-aspect-ratio-range"] = range;
+ } else {
+ // For everything else (apart from "aspect-ratio"), simply append
+ // "-range" to the name for the range-type property.
+ mCurrentType->second[std::string(a_name) + "-range"] = range;
+
+ // Only "quality" may have "scale".
+ if (!strEq(a_name, "quality") && a_scale != nullptr) {
+ return limitFoundMissingAttr(a_name, "scale");
+ } else if (strEq(a_name, "quality")) {
+ // The default value of "quality-scale" is "linear".
+ mCurrentType->second["quality-scale"] = a_scale == nullptr ?
+ "linear" : a_scale;
+ }
+
+ // "quality" and "complexity" must have "default".
+ // Other limits must not have "default".
+ if (strEq(a_name, "quality") || strEq(a_name, "complexity")) {
+ if (a_default == nullptr) {
+ return limitFoundMissingAttr(a_name, "default", false);
+ }
+ // name will be "quality-default" or "complexity-default".
+ mCurrentType->second[std::string(a_name) + "-default"] = a_default;
+ } else if (a_default != nullptr) {
+ return limitFoundMissingAttr(a_name, "default", true);
+ }
+ }
+ } else {
+ if (a_default != nullptr) {
+ return limitFoundMissingAttr(a_name, "default");
+ }
+ if (a_in != nullptr) {
+ return limitFoundMissingAttr(a_name, "in");
+ }
+ if (a_scale != nullptr) {
+ return limitFoundMissingAttr(a_name, "scale");
+ }
+ if (a_range != nullptr) {
+ return limitFoundMissingAttr(a_name, "range");
+ }
+ if (a_min != nullptr) {
+ return limitFoundMissingAttr(a_name, "min");
+ }
+
+ if (a_max != nullptr) {
+ // "max" must exist if and only if name is "channel-count" or
+ // "concurrent-instances".
+ // "min" is not ncessary.
+ if (strEq(a_name, "channel-count") ||
+ strEq(a_name, "concurrent-instances")) {
+ mCurrentType->second[std::string("max-") + a_name] = a_max;
+ } else {
+ return limitFoundMissingAttr(a_name, "max", false);
+ }
+ } else if (strEq(a_name, "channel-count") ||
+ strEq(a_name, "concurrent-instances")) {
+ return limitFoundMissingAttr(a_name, "max");
+ }
+
+ if (a_ranges != nullptr) {
+ // "ranges" must exist if and only if name is "sample-rate".
+ if (strEq(a_name, "sample-rate")) {
+ mCurrentType->second["sample-rate-ranges"] = a_ranges;
+ } else {
+ return limitFoundMissingAttr(a_name, "ranges", false);
+ }
+ } else if (strEq(a_name, "sample-rate")) {
+ return limitFoundMissingAttr(a_name, "ranges");
+ }
+
+ if (a_value != nullptr) {
+ // "value" must exist if and only if name is "alignment" or
+ // "block-size".
+ if (strEq(a_name, "alignment") || strEq(a_name, "block-size")) {
+ mCurrentType->second[a_name] = a_value;
+ } else {
+ return limitFoundMissingAttr(a_name, "value", false);
+ }
+ } else if (strEq(a_name, "alignment") || strEq(a_name, "block-size")) {
+ return limitFoundMissingAttr(a_name, "value", false);
+ }
+
+ }
+
+ return OK;
+}
+
+status_t MediaCodecsXmlParser::addFeature(const char **attrs) {
+ size_t i = 0;
+ const char *name = nullptr;
+ int32_t optional = -1;
+ int32_t required = -1;
+ const char *value = nullptr;
+
+ while (attrs[i] != nullptr) {
+ if (strEq(attrs[i], "name")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addFeature: name is null");
+ return -EINVAL;
+ }
+ name = attrs[i];
+ } else if (strEq(attrs[i], "optional")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addFeature: optional is null");
+ return -EINVAL;
+ }
+ optional = parseBoolean(attrs[i]) ? 1 : 0;
+ } else if (strEq(attrs[i], "required")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addFeature: required is null");
+ return -EINVAL;
+ }
+ required = parseBoolean(attrs[i]) ? 1 : 0;
+ } else if (strEq(attrs[i], "value")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addFeature: value is null");
+ return -EINVAL;
+ }
+ value = attrs[i];
+ } else {
+ ALOGE("addFeature: unrecognized attribute: %s", attrs[i]);
+ return -EINVAL;
+ }
+ ++i;
+ }
+
+ // Every feature must have a name.
+ if (name == nullptr) {
+ ALOGE("feature with no 'name' attribute");
+ return -EINVAL;
+ }
+
+ if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
+ ALOGW("ignoring null type");
+ return OK;
+ }
+
+ if ((optional != -1) || (required != -1)) {
+ if (optional == required) {
+ ALOGE("feature '%s' is both/neither optional and required", name);
+ return -EINVAL;
+ }
+ if ((optional == 1) || (required == 1)) {
+ if (value != nullptr) {
+ ALOGE("feature '%s' cannot have extra 'value'", name);
+ return -EINVAL;
+ }
+ mCurrentType->second[std::string("feature-") + name] =
+ optional == 1 ? "0" : "1";
+ return OK;
+ }
+ }
+ mCurrentType->second[std::string("feature-") + name] = value == nullptr ?
+ "0" : value;
+ return OK;
+}
+
+const MediaCodecsXmlParser::AttributeMap&
+ MediaCodecsXmlParser::getServiceAttributeMap() const {
+ return mServiceAttributeMap;
+}
+
+const MediaCodecsXmlParser::CodecMap&
+ MediaCodecsXmlParser::getCodecMap() const {
+ return mCodecMap;
+}
+
+const MediaCodecsXmlParser::RoleMap&
+ MediaCodecsXmlParser::getRoleMap() const {
+ if (mRoleMap.empty()) {
+ generateRoleMap();
+ }
+ return mRoleMap;
+}
+
+const char* MediaCodecsXmlParser::getCommonPrefix() const {
+ if (mCommonPrefix.empty()) {
+ generateCommonPrefix();
+ }
+ return mCommonPrefix.data();
+}
+
+status_t MediaCodecsXmlParser::getParsingStatus() const {
+ return mParsingStatus;
+}
+
+void MediaCodecsXmlParser::generateRoleMap() const {
+ for (const auto& codec : mCodecMap) {
+ const auto& codecName = codec.first;
+ bool isEncoder = codec.second.isEncoder;
+ size_t order = codec.second.order;
+ const auto& typeMap = codec.second.typeMap;
+ for (const auto& type : typeMap) {
+ const auto& typeName = type.first;
+ const char* roleName = GetComponentRole(isEncoder, typeName.data());
+ if (roleName == nullptr) {
+ ALOGE("Cannot find the role for %s of type %s",
+ isEncoder ? "an encoder" : "a decoder",
+ typeName.data());
+ continue;
+ }
+ const auto& typeAttributeMap = type.second;
+
+ auto roleIterator = mRoleMap.find(roleName);
+ std::multimap<size_t, NodeInfo>* nodeList;
+ if (roleIterator == mRoleMap.end()) {
+ RoleProperties roleProperties;
+ roleProperties.type = typeName;
+ roleProperties.isEncoder = isEncoder;
+ auto insertResult = mRoleMap.insert(
+ std::make_pair(roleName, roleProperties));
+ if (!insertResult.second) {
+ ALOGE("Cannot add role %s", roleName);
+ continue;
+ }
+ nodeList = &insertResult.first->second.nodeList;
+ } else {
+ if (roleIterator->second.type != typeName) {
+ ALOGE("Role %s has mismatching types: %s and %s",
+ roleName,
+ roleIterator->second.type.data(),
+ typeName.data());
+ continue;
+ }
+ if (roleIterator->second.isEncoder != isEncoder) {
+ ALOGE("Role %s cannot be both an encoder and a decoder",
+ roleName);
+ continue;
+ }
+ nodeList = &roleIterator->second.nodeList;
+ }
+
+ NodeInfo nodeInfo;
+ nodeInfo.name = codecName;
+ nodeInfo.attributeList.reserve(typeAttributeMap.size());
+ for (const auto& attribute : typeAttributeMap) {
+ nodeInfo.attributeList.push_back(
+ Attribute{attribute.first, attribute.second});
+ }
+ nodeList->insert(std::make_pair(
+ std::move(order), std::move(nodeInfo)));
+ }
+ }
+}
+
+void MediaCodecsXmlParser::generateCommonPrefix() const {
+ if (mCodecMap.empty()) {
+ return;
+ }
+ auto i = mCodecMap.cbegin();
+ auto first = i->first.cbegin();
+ auto last = i->first.cend();
+ for (++i; i != mCodecMap.cend(); ++i) {
+ last = std::mismatch(
+ first, last, i->first.cbegin(), i->first.cend()).first;
+ }
+ mCommonPrefix.insert(mCommonPrefix.begin(), first, last);
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h b/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
new file mode 100644
index 0000000..cc69e52
--- /dev/null
+++ b/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2017, 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 MEDIA_STAGEFRIGHT_XMLPARSER_H_
+#define MEDIA_STAGEFRIGHT_XMLPARSER_H_
+
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+#include <utils/StrongPointer.h>
+
+#include <string>
+#include <set>
+#include <map>
+#include <vector>
+
+namespace android {
+
+class MediaCodecsXmlParser {
+public:
+
+ // Treblized media codec list will be located in /odm/etc or /vendor/etc.
+ static constexpr char const* defaultSearchDirs[] =
+ {"/odm/etc", "/vendor/etc", "/etc", nullptr};
+ static constexpr char const* defaultMainXmlName =
+ "media_codecs.xml";
+ static constexpr char const* defaultPerformanceXmlName =
+ "media_codecs_performance.xml";
+ static constexpr char const* defaultProfilingResultsXmlPath =
+ "/data/misc/media/media_codecs_profiling_results.xml";
+
+ MediaCodecsXmlParser(
+ const char* const* searchDirs = defaultSearchDirs,
+ const char* mainXmlName = defaultMainXmlName,
+ const char* performanceXmlName = defaultPerformanceXmlName,
+ const char* profilingResultsXmlPath = defaultProfilingResultsXmlPath);
+ ~MediaCodecsXmlParser();
+
+ typedef std::pair<std::string, std::string> Attribute;
+ typedef std::map<std::string, std::string> AttributeMap;
+
+ typedef std::pair<std::string, AttributeMap> Type;
+ typedef std::map<std::string, AttributeMap> TypeMap;
+
+ typedef std::set<std::string> QuirkSet;
+
+ /**
+ * Properties of a codec (node)
+ */
+ struct CodecProperties {
+ bool isEncoder; ///< Whether this codec is an encoder or a decoder
+ size_t order; ///< Order of appearance in the file (starting from 0)
+ QuirkSet quirkSet; ///< Set of quirks requested by this codec
+ TypeMap typeMap; ///< Map of types supported by this codec
+ };
+
+ typedef std::pair<std::string, CodecProperties> Codec;
+ typedef std::map<std::string, CodecProperties> CodecMap;
+
+ /**
+ * Properties of a node (for IOmxStore)
+ */
+ struct NodeInfo {
+ std::string name;
+ std::vector<Attribute> attributeList;
+ };
+
+ /**
+ * Properties of a role (for IOmxStore)
+ */
+ struct RoleProperties {
+ std::string type;
+ bool isEncoder;
+ std::multimap<size_t, NodeInfo> nodeList;
+ };
+
+ typedef std::pair<std::string, RoleProperties> Role;
+ typedef std::map<std::string, RoleProperties> RoleMap;
+
+ /**
+ * Return a map for attributes that are service-specific.
+ */
+ const AttributeMap& getServiceAttributeMap() const;
+
+ /**
+ * Return a map for codecs and their properties.
+ */
+ const CodecMap& getCodecMap() const;
+
+ /**
+ * Return a map for roles and their properties.
+ * This map is generated from the CodecMap.
+ */
+ const RoleMap& getRoleMap() const;
+
+ /**
+ * Return a common prefix of all node names.
+ *
+ * The prefix is not provided in the xml, so it has to be computed by taking
+ * the longest common prefix of all node names.
+ */
+ const char* getCommonPrefix() const;
+
+ status_t getParsingStatus() const;
+
+private:
+ enum Section {
+ SECTION_TOPLEVEL,
+ SECTION_SETTINGS,
+ SECTION_DECODERS,
+ SECTION_DECODER,
+ SECTION_DECODER_TYPE,
+ SECTION_ENCODERS,
+ SECTION_ENCODER,
+ SECTION_ENCODER_TYPE,
+ SECTION_INCLUDE,
+ };
+
+ status_t mParsingStatus;
+ Section mCurrentSection;
+ bool mUpdate;
+ std::vector<Section> mSectionStack;
+ std::string mHrefBase;
+
+ // Service attributes
+ AttributeMap mServiceAttributeMap;
+
+ // Codec attributes
+ std::string mCurrentName;
+ std::set<std::string> mCodecSet;
+ Codec mCodecListTemp[2048];
+ CodecMap mCodecMap;
+ size_t mCodecCounter;
+ CodecMap::iterator mCurrentCodec;
+ TypeMap::iterator mCurrentType;
+
+ // Role map
+ mutable RoleMap mRoleMap;
+
+ // Computed longest common prefix
+ mutable std::string mCommonPrefix;
+
+ bool parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
+
+ void parseXMLFile(const char *path);
+
+ static void StartElementHandlerWrapper(
+ void *me, const char *name, const char **attrs);
+
+ static void EndElementHandlerWrapper(void *me, const char *name);
+
+ void startElementHandler(const char *name, const char **attrs);
+ void endElementHandler(const char *name);
+
+ status_t includeXMLFile(const char **attrs);
+ status_t addSettingFromAttributes(const char **attrs);
+ status_t addMediaCodecFromAttributes(bool encoder, const char **attrs);
+ void addMediaCodec(bool encoder, const char *name,
+ const char *type = nullptr);
+
+ status_t addQuirk(const char **attrs);
+ status_t addTypeFromAttributes(const char **attrs, bool encoder);
+ status_t addLimit(const char **attrs);
+ status_t addFeature(const char **attrs);
+ void addType(const char *name);
+
+ void generateRoleMap() const;
+ void generateCommonPrefix() const;
+
+ MediaCodecsXmlParser(const MediaCodecsXmlParser&) = delete;
+ MediaCodecsXmlParser& operator=(const MediaCodecsXmlParser&) = delete;
+};
+
+} // namespace android
+
+#endif // MEDIA_STAGEFRIGHT_XMLPARSER_H_
+
diff --git a/media/mtp/MtpDebug.cpp b/media/mtp/MtpDebug.cpp
index 1c04bcf..d2ede1c 100644
--- a/media/mtp/MtpDebug.cpp
+++ b/media/mtp/MtpDebug.cpp
@@ -102,6 +102,7 @@
{ "MTP_FORMAT_JP2", 0x380F },
{ "MTP_FORMAT_JPX", 0x3810 },
{ "MTP_FORMAT_DNG", 0x3811 },
+ { "MTP_FORMAT_HEIF", 0x3812 },
{ "MTP_FORMAT_UNDEFINED_FIRMWARE", 0xB802 },
{ "MTP_FORMAT_WINDOWS_IMAGE_FORMAT", 0xB881 },
{ "MTP_FORMAT_UNDEFINED_AUDIO", 0xB900 },
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index c50af2f..9139925 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -62,6 +62,8 @@
constexpr int USB_FFS_MAX_WRITE = MTP_BUFFER_SIZE;
constexpr int USB_FFS_MAX_READ = MTP_BUFFER_SIZE;
+constexpr unsigned FFS_NUM_EVENTS = 5;
+
static_assert(USB_FFS_MAX_WRITE > 0, "Max r/w values must be > 0!");
static_assert(USB_FFS_MAX_READ > 0, "Max r/w values must be > 0!");
@@ -102,8 +104,11 @@
__le32 fs_count;
__le32 hs_count;
__le32 ss_count;
+ __le32 os_count;
struct func_desc fs_descs, hs_descs;
struct ss_func_desc ss_descs;
+ struct usb_os_desc_header os_header;
+ struct usb_ext_compat_desc os_desc;
} __attribute__((packed));
const struct usb_interface_descriptor mtp_interface_desc = {
@@ -287,6 +292,36 @@
},
};
+struct usb_os_desc_header mtp_os_desc_header = {
+ .interface = htole32(1),
+ .dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
+ .bcdVersion = htole16(1),
+ .wIndex = htole16(4),
+ .bCount = htole16(1),
+ .Reserved = htole16(0),
+};
+
+struct usb_ext_compat_desc mtp_os_desc_compat = {
+ .bFirstInterfaceNumber = 0,
+ .Reserved1 = htole32(1),
+ .CompatibleID = { 'M', 'T', 'P' },
+ .SubCompatibleID = {0},
+ .Reserved2 = {0},
+};
+
+struct usb_ext_compat_desc ptp_os_desc_compat = {
+ .bFirstInterfaceNumber = 0,
+ .Reserved1 = htole32(1),
+ .CompatibleID = { 'P', 'T', 'P' },
+ .SubCompatibleID = {0},
+ .Reserved2 = {0},
+};
+
+struct mtp_device_status {
+ uint16_t wLength;
+ uint16_t wCode;
+};
+
} // anonymous namespace
namespace android {
@@ -311,13 +346,16 @@
v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor));
v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
- FUNCTIONFS_HAS_SS_DESC;
+ FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
v2_descriptor.fs_count = 4;
v2_descriptor.hs_count = 4;
v2_descriptor.ss_count = 7;
+ v2_descriptor.os_count = 1;
v2_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
v2_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
v2_descriptor.ss_descs = mPtp ? ptp_ss_descriptors : mtp_ss_descriptors;
+ v2_descriptor.os_header = mtp_os_desc_header;
+ v2_descriptor.os_desc = mPtp ? ptp_os_desc_compat : mtp_os_desc_compat;
if (mControl < 0) { // might have already done this before
mControl.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP0, O_RDWR)));
@@ -361,6 +399,88 @@
mControl.reset();
}
+void MtpFfsHandle::controlLoop() {
+ while (!handleEvent()) {}
+ LOG(DEBUG) << "Mtp server shutting down";
+}
+
+int MtpFfsHandle::handleEvent() {
+ std::vector<usb_functionfs_event> events(FFS_NUM_EVENTS);
+ usb_functionfs_event *event = events.data();
+ int nbytes = TEMP_FAILURE_RETRY(::read(mControl, event,
+ events.size() * sizeof(usb_functionfs_event)));
+ if (nbytes == -1) {
+ return -1;
+ }
+ int ret = 0;
+ for (size_t n = nbytes / sizeof *event; n; --n, ++event) {
+ switch (event->type) {
+ case FUNCTIONFS_BIND:
+ case FUNCTIONFS_ENABLE:
+ case FUNCTIONFS_RESUME:
+ ret = 0;
+ errno = 0;
+ break;
+ case FUNCTIONFS_SUSPEND:
+ case FUNCTIONFS_UNBIND:
+ case FUNCTIONFS_DISABLE:
+ errno = ESHUTDOWN;
+ ret = -1;
+ break;
+ case FUNCTIONFS_SETUP:
+ if (handleControlRequest(&event->u.setup) == -1)
+ ret = -1;
+ break;
+ default:
+ LOG(DEBUG) << "Mtp Event " << event->type << " (unknown)";
+ }
+ }
+ return ret;
+}
+
+int MtpFfsHandle::handleControlRequest(const struct usb_ctrlrequest *setup) {
+ uint8_t type = setup->bRequestType;
+ uint8_t code = setup->bRequest;
+ uint16_t length = setup->wLength;
+ uint16_t index = setup->wIndex;
+ uint16_t value = setup->wValue;
+ std::vector<char> buf;
+ buf.resize(length);
+
+ if (!(type & USB_DIR_IN)) {
+ if (::read(mControl, buf.data(), length) != length) {
+ PLOG(DEBUG) << "Mtp error ctrlreq read data";
+ }
+ }
+
+ if ((type & USB_TYPE_MASK) == USB_TYPE_CLASS && index == 0 && value == 0) {
+ switch(code) {
+ case MTP_REQ_GET_DEVICE_STATUS:
+ {
+ if (length < sizeof(struct mtp_device_status)) {
+ return -1;
+ }
+ struct mtp_device_status *st = reinterpret_cast<struct mtp_device_status*>(buf.data());
+ st->wLength = htole16(sizeof(st));
+ st->wCode = MTP_RESPONSE_OK;
+ length = st->wLength;
+ break;
+ }
+ default:
+ LOG(DEBUG) << "Unrecognized Mtp class request! " << code;
+ }
+ } else {
+ LOG(DEBUG) << "Unrecognized request type " << type;
+ }
+
+ if (type & USB_DIR_IN) {
+ if (::write(mControl, buf.data(), length) != length) {
+ PLOG(DEBUG) << "Mtp error ctrlreq write data";
+ }
+ }
+ return 0;
+}
+
int MtpFfsHandle::writeHandle(int fd, const void* data, int len) {
LOG(VERBOSE) << "MTP about to write fd = " << fd << ", len=" << len;
int ret = 0;
@@ -460,6 +580,10 @@
posix_madvise(mBuffer2.data(), MAX_FILE_CHUNK_SIZE,
POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED);
+ // Handle control requests.
+ std::thread t([this]() { this->controlLoop(); });
+ t.detach();
+
// Get device specific r/w size
mMaxWrite = android::base::GetIntProperty("sys.usb.ffs.max_write", USB_FFS_MAX_WRITE);
mMaxRead = android::base::GetIntProperty("sys.usb.ffs.max_read", USB_FFS_MAX_READ);
@@ -490,7 +614,7 @@
int MtpFfsHandle::configure(bool usePtp) {
// Wait till previous server invocation has closed
- if (!mLock.try_lock_for(std::chrono::milliseconds(1000))) {
+ if (!mLock.try_lock_for(std::chrono::milliseconds(300))) {
LOG(ERROR) << "MtpServer was unable to get configure lock";
return -1;
}
@@ -542,6 +666,7 @@
size_t length;
bool read = false;
bool write = false;
+ bool short_packet = false;
posix_fadvise(mfr.fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
@@ -586,6 +711,7 @@
// For larger files, receive until a short packet is received.
if (static_cast<size_t>(ret) < length) {
file_length = 0;
+ short_packet = true;
}
} else {
// Receive an empty packet if size is a multiple of the endpoint size.
@@ -605,7 +731,7 @@
read = false;
}
}
- if (ret % packet_size == 0 || zero_packet) {
+ if ((ret % packet_size == 0 && !short_packet) || zero_packet) {
if (TEMP_FAILURE_RETRY(::read(mBulkOut, data, packet_size)) != 0) {
return -1;
}
@@ -719,9 +845,22 @@
}
int MtpFfsHandle::sendEvent(mtp_event me) {
+ // Mimic the behavior of f_mtp by sending the event async.
+ // Events aren't critical to the connection, so we don't need to check the return value.
+ char *temp = new char[me.length];
+ memcpy(temp, me.data, me.length);
+ me.data = temp;
+ std::thread t([this, me]() { return this->doSendEvent(me); });
+ t.detach();
+ return 0;
+}
+
+void MtpFfsHandle::doSendEvent(mtp_event me) {
unsigned length = me.length;
- int ret = writeHandle(mIntr, me.data, length);
- return static_cast<unsigned>(ret) == length ? 0 : -1;
+ int ret = ::write(mIntr, me.data, length);
+ if (static_cast<unsigned>(ret) != length)
+ PLOG(ERROR) << "Mtp error sending event thread!";
+ delete[] reinterpret_cast<char*>(me.data);
}
} // namespace android
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index 98669ff..da0cd9f 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -33,6 +33,11 @@
bool initFunctionfs();
void closeConfig();
void closeEndpoints();
+ void doSendEvent(mtp_event me);
+
+ void controlLoop();
+ int handleEvent();
+ int handleControlRequest(const struct usb_ctrlrequest *setup);
bool mPtp;
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 2180462..67fd221 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -132,7 +132,7 @@
int ret = sHandle->configure(usePtp);
if (ret) ALOGE("Failed to configure MTP driver!");
- else android::base::SetProperty("sys.usb.ffs.mtp.ready", "1");
+ android::base::SetProperty("sys.usb.ffs.mtp.ready", "1");
return ret;
}
diff --git a/media/mtp/mtp.h b/media/mtp/mtp.h
index adfb102..1c7829d 100644
--- a/media/mtp/mtp.h
+++ b/media/mtp/mtp.h
@@ -94,6 +94,7 @@
#define MTP_FORMAT_JP2 0x380F // JPEG2000 Baseline File Format
#define MTP_FORMAT_JPX 0x3810 // JPEG2000 Extended File Format
#define MTP_FORMAT_DNG 0x3811 // Digital Negative
+#define MTP_FORMAT_HEIF 0x3812 // HEIF images
#define MTP_FORMAT_UNDEFINED_FIRMWARE 0xB802
#define MTP_FORMAT_WINDOWS_IMAGE_FORMAT 0xB881
#define MTP_FORMAT_UNDEFINED_AUDIO 0xB900
@@ -493,4 +494,10 @@
#define MTP_ASSOCIATION_TYPE_UNDEFINED 0x0000
#define MTP_ASSOCIATION_TYPE_GENERIC_FOLDER 0x0001
+// MTP class reqeusts
+#define MTP_REQ_CANCEL 0x64
+#define MTP_REQ_GET_EXT_EVENT_DATA 0x65
+#define MTP_REQ_RESET 0x66
+#define MTP_REQ_GET_DEVICE_STATUS 0x67
+
#endif // _MTP_H
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 40974f3..0d48de1 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -90,3 +90,9 @@
},
},
}
+
+llndk_library {
+ name: "libmediandk",
+ symbol_file: "libmediandk.map.txt",
+ export_include_dirs: ["include"],
+}
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index 6d28d1b..c4ff537 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -58,11 +58,13 @@
return;
}
sp<AImageReader> reader = mReader.promote();
- if (reader == nullptr) {
- LOG_ALWAYS_FATAL("Error: AImage not closed before AImageReader close!");
- return;
+ if (reader != nullptr) {
+ reader->releaseImageLocked(this, releaseFenceFd);
+ } else if (mBuffer != nullptr) {
+ LOG_ALWAYS_FATAL("%s: parent AImageReader closed without releasing image %p",
+ __FUNCTION__, this);
}
- reader->releaseImageLocked(this, releaseFenceFd);
+
// Should have been set to nullptr in releaseImageLocked
// Set to nullptr here for extra safety only
mBuffer = nullptr;
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index 5d1a20b..fd6ecb5 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -44,7 +44,11 @@
const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";
bool
-AImageReader::isSupportedFormat(int32_t format) {
+AImageReader::isSupportedFormatAndUsage(int32_t format, uint64_t usage) {
+ // Check whether usage has either CPU_READ_OFTEN or CPU_READ set. Note that check against
+ // AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN (0x6) is sufficient as it implies
+ // AHARDWAREBUFFER_USAGE_CPU_READ (0x2).
+ bool hasCpuUsage = usage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
switch (format) {
case AIMAGE_FORMAT_RGBA_8888:
case AIMAGE_FORMAT_RGBX_8888:
@@ -60,6 +64,9 @@
case AIMAGE_FORMAT_DEPTH16:
case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
return true;
+ case AIMAGE_FORMAT_PRIVATE:
+ // For private format, cpu usage is prohibited.
+ return !hasCpuUsage;
default:
return false;
}
@@ -83,6 +90,8 @@
case AIMAGE_FORMAT_DEPTH16:
case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
return 1;
+ case AIMAGE_FORMAT_PRIVATE:
+ return 0;
default:
return -1;
}
@@ -340,7 +349,8 @@
for (auto it = mAcquiredImages.begin();
it != mAcquiredImages.end(); it++) {
AImage* image = *it;
- image->close();
+ Mutex::Autolock _l(image->mLock);
+ releaseImageLocked(image, /*releaseFenceFd*/-1);
}
// Delete Buffer Items
@@ -492,6 +502,8 @@
mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
returnBufferItemLocked(buffer);
image->mBuffer = nullptr;
+ image->mLockedBuffer = nullptr;
+ image->mIsClosed = true;
bool found = false;
// cleanup acquired image list
@@ -606,9 +618,9 @@
return AMEDIA_ERROR_INVALID_PARAMETER;
}
- if (!AImageReader::isSupportedFormat(format)) {
- ALOGE("%s: format %d is not supported by AImageReader",
- __FUNCTION__, format);
+ if (!AImageReader::isSupportedFormatAndUsage(format, usage)) {
+ ALOGE("%s: format %d is not supported with usage 0x%" PRIx64 " by AImageReader",
+ __FUNCTION__, format, usage);
return AMEDIA_ERROR_INVALID_PARAMETER;
}
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index 989c1fd..bed8a21 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -49,7 +49,7 @@
struct AImageReader : public RefBase {
public:
- static bool isSupportedFormat(int32_t format);
+ static bool isSupportedFormatAndUsage(int32_t format, uint64_t usage0);
static int getNumPlanesForFormat(int32_t format);
AImageReader(int32_t width,
@@ -85,7 +85,7 @@
// Called by AImageReader_acquireXXX to acquire a Buffer and setup AImage.
media_status_t acquireImageLocked(/*out*/AImage** image, /*out*/int* fenceFd);
- // Called by AImage to close image
+ // Called by AImage/~AImageReader to close image. Caller is responsible to grab AImage::mLock
void releaseImageLocked(AImage* image, int releaseFenceFd);
static int getBufferWidth(BufferItem* buffer);
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 51143ac..eecc858 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -421,7 +421,7 @@
for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
- keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
+ keyValuePairs[i].mValue = mObj->mQueryResults.valueAt(i).string();
}
*numPairs = mObj->mQueryResults.size();
return AMEDIA_OK;
diff --git a/media/ndk/include/media/NdkImage.h b/media/ndk/include/media/NdkImage.h
index d7443be..1931496 100644
--- a/media/ndk/include/media/NdkImage.h
+++ b/media/ndk/include/media/NdkImage.h
@@ -495,7 +495,13 @@
/**
* Android private opaque image format.
*
- * <p>This format is not currently supported by {@link AImageReader}.</p>
+ * <p>The choices of the actual format and pixel data layout are entirely up to the
+ * device-specific and framework internal implementations, and may vary depending on use cases
+ * even for the same device. Also note that the contents of these buffers are not directly
+ * accessible to the application.</p>
+ *
+ * <p>When an {@link AImage} of this format is obtained from an {@link AImageReader} or
+ * {@link AImage_getNumberOfPlanes()} method will return zero.</p>
*/
AIMAGE_FORMAT_PRIVATE = 0x22
};
diff --git a/media/ndk/include/media/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
index 59ae507..7a0c17b 100644
--- a/media/ndk/include/media/NdkImageReader.h
+++ b/media/ndk/include/media/NdkImageReader.h
@@ -70,7 +70,9 @@
* @param height The default height in pixels of the Images that this reader will produce.
* @param format The format of the Image that this reader will produce. This must be one of the
* AIMAGE_FORMAT_* enum value defined in {@link AIMAGE_FORMATS}. Note that not all
- * formats are supported, like {@link AIMAGE_FORMAT_PRIVATE}.
+ * formats are supported. One example is {@link AIMAGE_FORMAT_PRIVATE}, as it is not
+ * intended to be read by applications directly. That format is supported by
+ * {@link AImageReader_newWithUsage} introduced in API 26.
* @param maxImages The maximum number of images the user will want to access simultaneously. This
* should be as small as possible to limit memory use. Once maxImages Images are obtained
* by the user, one of them has to be released before a new {@link AImage} will become
@@ -307,6 +309,28 @@
* for the consumer usage. All other parameters and the return values are identical to those passed
* to {@line AImageReader_new}.
*
+ * <p>If the {@code format} is {@link AIMAGE_FORMAT_PRIVATE}, the created {@link AImageReader}
+ * will produce images whose contents are not directly accessible by the application. The application can
+ * still acquire images from this {@link AImageReader} and access {@link AHardwareBuffer} via
+ * {@link AImage_getHardwareBuffer()}. The {@link AHardwareBuffer} gained this way can then
+ * be passed back to hardware (such as GPU or hardware encoder if supported) for future processing.
+ * For example, you can obtain an {@link EGLClientBuffer} from the {@link AHardwareBuffer} by using
+ * {@link eglGetNativeClientBufferANDROID} extension and pass that {@link EGLClientBuffer} to {@link
+ * eglCreateImageKHR} to create an {@link EGLImage} resource type, which may then be bound to a
+ * texture via {@link glEGLImageTargetTexture2DOES} on supported devices. This can be useful for
+ * transporting textures that may be shared cross-process.</p>
+ * <p>In general, when software access to image data is not necessary, an {@link AImageReader}
+ * created with {@link AIMAGE_FORMAT_PRIVATE} format is more efficient, compared with {@link
+ * AImageReader}s using other format such as {@link AIMAGE_FORMAT_YUV_420_888}.</p>
+ *
+ * <p>Note that not all format and usage flag combination is supported by the {@link AImageReader},
+ * especially if {@code format} is {@link AIMAGE_FORMAT_PRIVATE}, {@code usage} must not include either
+ * {@link AHARDWAREBUFFER_USAGE_READ_RARELY} or {@link AHARDWAREBUFFER_USAGE_READ_OFTEN}</p>
+ *
+ * @param width The default width in pixels of the Images that this reader will produce.
+ * @param height The default height in pixels of the Images that this reader will produce.
+ * @param format The format of the Image that this reader will produce. This must be one of the
+ * AIMAGE_FORMAT_* enum value defined in {@link AIMAGE_FORMATS}.
* @param usage specifies how the consumer will access the AImage, using combination of the
* AHARDWAREBUFFER_USAGE flags described in {@link hardware_buffer.h}.
* Passing {@link AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN} is equivalent to calling
@@ -331,6 +355,11 @@
* {@link AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE}, or combined</td>
* </tr>
* </table>
+ * @return <ul>
+ * <li>{@link AMEDIA_OK} if the method call succeeds.</li>
+ * <li>{@link AMEDIA_ERROR_INVALID_PARAMETER} if reader is NULL, or one or more of width,
+ * height, format, maxImages, or usage arguments is not supported.</li>
+ * <li>{@link AMEDIA_ERROR_UNKNOWN} if the method fails for some other reasons.</li></ul>
*
* @see AImage
* @see AImageReader_new
diff --git a/media/ndk/include/media/NdkMediaCodec.h b/media/ndk/include/media/NdkMediaCodec.h
index 637bf9b..7e7e81e 100644
--- a/media/ndk/include/media/NdkMediaCodec.h
+++ b/media/ndk/include/media/NdkMediaCodec.h
@@ -27,6 +27,7 @@
#ifndef _NDK_MEDIA_CODEC_H
#define _NDK_MEDIA_CODEC_H
+#include <stdint.h>
#include <sys/cdefs.h>
#include "NdkMediaCrypto.h"
@@ -130,17 +131,45 @@
*/
ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec*, int64_t timeoutUs);
-/**
- * Send the specified buffer to the codec for processing.
+/*
+ * __USE_FILE_OFFSET64 changes the type of off_t in LP32, which changes the ABI
+ * of these declarations to not match the platform. In that case, define these
+ * APIs in terms of int32_t instead. Passing an off_t in this situation will
+ * result in silent truncation unless the user builds with -Wconversion, but the
+ * only alternative it to not expose them at all for this configuration, which
+ * makes the whole API unusable.
+ *
+ * https://github.com/android-ndk/ndk/issues/459
*/
-media_status_t AMediaCodec_queueInputBuffer(AMediaCodec*,
- size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags);
+#if defined(__USE_FILE_OFFSET64) && !defined(__LP64__)
+#define _off_t_compat int32_t
+#else
+#define _off_t_compat off_t
+#endif /* defined(__USE_FILE_OFFSET64) && !defined(__LP64__) */
+
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ __STDC_VERSION__ >= 201112L
+static_assert(sizeof(_off_t_compat) == sizeof(long),
+ "_off_t_compat does not match the NDK ABI. See "
+ "https://github.com/android-ndk/ndk/issues/459.");
+#endif
/**
* Send the specified buffer to the codec for processing.
*/
-media_status_t AMediaCodec_queueSecureInputBuffer(AMediaCodec*,
- size_t idx, off_t offset, AMediaCodecCryptoInfo*, uint64_t time, uint32_t flags);
+media_status_t AMediaCodec_queueInputBuffer(AMediaCodec*, size_t idx,
+ _off_t_compat offset, size_t size,
+ uint64_t time, uint32_t flags);
+
+/**
+ * Send the specified buffer to the codec for processing.
+ */
+media_status_t AMediaCodec_queueSecureInputBuffer(AMediaCodec*, size_t idx,
+ _off_t_compat offset,
+ AMediaCodecCryptoInfo*,
+ uint64_t time, uint32_t flags);
+
+#undef _off_t_compat
/**
* Get the index of the next available buffer of processed data.
diff --git a/media/vndk/Android.bp b/media/vndk/Android.bp
deleted file mode 100644
index e93fd16..0000000
--- a/media/vndk/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-subdirs = [
- "xmlparser/1.0",
-]
-
diff --git a/media/vndk/xmlparser/1.0/MediaCodecsXmlParser.cpp b/media/vndk/xmlparser/1.0/MediaCodecsXmlParser.cpp
deleted file mode 100644
index 84e5514..0000000
--- a/media/vndk/xmlparser/1.0/MediaCodecsXmlParser.cpp
+++ /dev/null
@@ -1,862 +0,0 @@
-/*
- * Copyright 2017, 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 "MediaCodecsXmlParser"
-#include <utils/Log.h>
-
-#include <media/vndk/xmlparser/1.0/MediaCodecsXmlParser.h>
-
-#include <media/MediaCodecInfo.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/MediaErrors.h>
-
-#include <sys/stat.h>
-
-#include <expat.h>
-#include <string>
-
-#define MEDIA_CODECS_CONFIG_FILE_PATH_MAX_LENGTH 256
-
-namespace android {
-
-namespace { // Local variables and functions
-
-const char *kProfilingResults =
- "/data/misc/media/media_codecs_profiling_results.xml";
-
-// Treblized media codec list will be located in /odm/etc or /vendor/etc.
-const char *kConfigLocationList[] =
- {"/odm/etc", "/vendor/etc", "/etc"};
-constexpr int kConfigLocationListSize =
- (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
-
-bool findMediaCodecListFileFullPath(
- const char *file_name, std::string *out_path) {
- for (int i = 0; i < kConfigLocationListSize; i++) {
- *out_path = std::string(kConfigLocationList[i]) + "/" + file_name;
- struct stat file_stat;
- if (stat(out_path->c_str(), &file_stat) == 0 &&
- S_ISREG(file_stat.st_mode)) {
- return true;
- }
- }
- return false;
-}
-
-// Find TypeInfo by name.
-std::vector<TypeInfo>::iterator findTypeInfo(
- CodecInfo &codecInfo, const AString &typeName) {
- return std::find_if(
- codecInfo.mTypes.begin(), codecInfo.mTypes.end(),
- [typeName](const auto &typeInfo) {
- return typeInfo.mName == typeName;
- });
-}
-
-// Convert a string into a boolean value.
-bool ParseBoolean(const char *s) {
- if (!strcasecmp(s, "true") || !strcasecmp(s, "yes") || !strcasecmp(s, "y")) {
- return true;
- }
- char *end;
- unsigned long res = strtoul(s, &end, 10);
- return *s != '\0' && *end == '\0' && res > 0;
-}
-
-} // unnamed namespace
-
-MediaCodecsXmlParser::MediaCodecsXmlParser() :
- mInitCheck(NO_INIT),
- mUpdate(false) {
- std::string config_file_path;
- if (findMediaCodecListFileFullPath(
- "media_codecs.xml", &config_file_path)) {
- parseTopLevelXMLFile(config_file_path.c_str(), false);
- } else {
- mInitCheck = NAME_NOT_FOUND;
- }
- if (findMediaCodecListFileFullPath(
- "media_codecs_performance.xml", &config_file_path)) {
- parseTopLevelXMLFile(config_file_path.c_str(), true);
- }
- parseTopLevelXMLFile(kProfilingResults, true);
-}
-
-void MediaCodecsXmlParser::parseTopLevelXMLFile(
- const char *codecs_xml, bool ignore_errors) {
- // get href_base
- const char *href_base_end = strrchr(codecs_xml, '/');
- if (href_base_end != NULL) {
- mHrefBase = AString(codecs_xml, href_base_end - codecs_xml + 1);
- }
-
- mInitCheck = OK; // keeping this here for safety
- mCurrentSection = SECTION_TOPLEVEL;
- mDepth = 0;
-
- parseXMLFile(codecs_xml);
-
- if (mInitCheck != OK) {
- if (ignore_errors) {
- mInitCheck = OK;
- return;
- }
- mCodecInfos.clear();
- return;
- }
-}
-
-MediaCodecsXmlParser::~MediaCodecsXmlParser() {
-}
-
-status_t MediaCodecsXmlParser::initCheck() const {
- return mInitCheck;
-}
-
-void MediaCodecsXmlParser::parseXMLFile(const char *path) {
- FILE *file = fopen(path, "r");
-
- if (file == NULL) {
- ALOGW("unable to open media codecs configuration xml file: %s", path);
- mInitCheck = NAME_NOT_FOUND;
- return;
- }
-
- ALOGV("Start parsing %s", path);
- XML_Parser parser = ::XML_ParserCreate(NULL);
- CHECK(parser != NULL);
-
- ::XML_SetUserData(parser, this);
- ::XML_SetElementHandler(
- parser, StartElementHandlerWrapper, EndElementHandlerWrapper);
-
- const int BUFF_SIZE = 512;
- while (mInitCheck == OK) {
- void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
- if (buff == NULL) {
- ALOGE("failed in call to XML_GetBuffer()");
- mInitCheck = UNKNOWN_ERROR;
- break;
- }
-
- int bytes_read = ::fread(buff, 1, BUFF_SIZE, file);
- if (bytes_read < 0) {
- ALOGE("failed in call to read");
- mInitCheck = ERROR_IO;
- break;
- }
-
- XML_Status status = ::XML_ParseBuffer(parser, bytes_read, bytes_read == 0);
- if (status != XML_STATUS_OK) {
- ALOGE("malformed (%s)", ::XML_ErrorString(::XML_GetErrorCode(parser)));
- mInitCheck = ERROR_MALFORMED;
- break;
- }
-
- if (bytes_read == 0) {
- break;
- }
- }
-
- ::XML_ParserFree(parser);
-
- fclose(file);
- file = NULL;
-}
-
-// static
-void MediaCodecsXmlParser::StartElementHandlerWrapper(
- void *me, const char *name, const char **attrs) {
- static_cast<MediaCodecsXmlParser *>(me)->startElementHandler(name, attrs);
-}
-
-// static
-void MediaCodecsXmlParser::EndElementHandlerWrapper(void *me, const char *name) {
- static_cast<MediaCodecsXmlParser *>(me)->endElementHandler(name);
-}
-
-status_t MediaCodecsXmlParser::includeXMLFile(const char **attrs) {
- const char *href = NULL;
- size_t i = 0;
- while (attrs[i] != NULL) {
- if (!strcmp(attrs[i], "href")) {
- if (attrs[i + 1] == NULL) {
- return -EINVAL;
- }
- href = attrs[i + 1];
- ++i;
- } else {
- ALOGE("includeXMLFile: unrecognized attribute: %s", attrs[i]);
- return -EINVAL;
- }
- ++i;
- }
-
- // For security reasons and for simplicity, file names can only contain
- // [a-zA-Z0-9_.] and must start with media_codecs_ and end with .xml
- for (i = 0; href[i] != '\0'; i++) {
- if (href[i] == '.' || href[i] == '_' ||
- (href[i] >= '0' && href[i] <= '9') ||
- (href[i] >= 'A' && href[i] <= 'Z') ||
- (href[i] >= 'a' && href[i] <= 'z')) {
- continue;
- }
- ALOGE("invalid include file name: %s", href);
- return -EINVAL;
- }
-
- AString filename = href;
- if (!filename.startsWith("media_codecs_") ||
- !filename.endsWith(".xml")) {
- ALOGE("invalid include file name: %s", href);
- return -EINVAL;
- }
- filename.insert(mHrefBase, 0);
-
- parseXMLFile(filename.c_str());
- return mInitCheck;
-}
-
-void MediaCodecsXmlParser::startElementHandler(
- const char *name, const char **attrs) {
- if (mInitCheck != OK) {
- return;
- }
-
- bool inType = true;
-
- if (!strcmp(name, "Include")) {
- mInitCheck = includeXMLFile(attrs);
- if (mInitCheck == OK) {
- mPastSections.push(mCurrentSection);
- mCurrentSection = SECTION_INCLUDE;
- }
- ++mDepth;
- return;
- }
-
- switch (mCurrentSection) {
- case SECTION_TOPLEVEL:
- {
- if (!strcmp(name, "Decoders")) {
- mCurrentSection = SECTION_DECODERS;
- } else if (!strcmp(name, "Encoders")) {
- mCurrentSection = SECTION_ENCODERS;
- } else if (!strcmp(name, "Settings")) {
- mCurrentSection = SECTION_SETTINGS;
- }
- break;
- }
-
- case SECTION_SETTINGS:
- {
- if (!strcmp(name, "Setting")) {
- mInitCheck = addSettingFromAttributes(attrs);
- }
- break;
- }
-
- case SECTION_DECODERS:
- {
- if (!strcmp(name, "MediaCodec")) {
- mInitCheck =
- addMediaCodecFromAttributes(false /* encoder */, attrs);
-
- mCurrentSection = SECTION_DECODER;
- }
- break;
- }
-
- case SECTION_ENCODERS:
- {
- if (!strcmp(name, "MediaCodec")) {
- mInitCheck =
- addMediaCodecFromAttributes(true /* encoder */, attrs);
-
- mCurrentSection = SECTION_ENCODER;
- }
- break;
- }
-
- case SECTION_DECODER:
- case SECTION_ENCODER:
- {
- if (!strcmp(name, "Quirk")) {
- mInitCheck = addQuirk(attrs);
- } else if (!strcmp(name, "Type")) {
- mInitCheck = addTypeFromAttributes(attrs, (mCurrentSection == SECTION_ENCODER));
- mCurrentSection =
- (mCurrentSection == SECTION_DECODER
- ? SECTION_DECODER_TYPE : SECTION_ENCODER_TYPE);
- }
- }
- inType = false;
- // fall through
-
- case SECTION_DECODER_TYPE:
- case SECTION_ENCODER_TYPE:
- {
- // ignore limits and features specified outside of type
- bool outside = !inType && mCurrentType == mCodecInfos[mCurrentName].mTypes.end();
- if (outside && (!strcmp(name, "Limit") || !strcmp(name, "Feature"))) {
- ALOGW("ignoring %s specified outside of a Type", name);
- } else if (!strcmp(name, "Limit")) {
- mInitCheck = addLimit(attrs);
- } else if (!strcmp(name, "Feature")) {
- mInitCheck = addFeature(attrs);
- }
- break;
- }
-
- default:
- break;
- }
-
- ++mDepth;
-}
-
-void MediaCodecsXmlParser::endElementHandler(const char *name) {
- if (mInitCheck != OK) {
- return;
- }
-
- switch (mCurrentSection) {
- case SECTION_SETTINGS:
- {
- if (!strcmp(name, "Settings")) {
- mCurrentSection = SECTION_TOPLEVEL;
- }
- break;
- }
-
- case SECTION_DECODERS:
- {
- if (!strcmp(name, "Decoders")) {
- mCurrentSection = SECTION_TOPLEVEL;
- }
- break;
- }
-
- case SECTION_ENCODERS:
- {
- if (!strcmp(name, "Encoders")) {
- mCurrentSection = SECTION_TOPLEVEL;
- }
- break;
- }
-
- case SECTION_DECODER_TYPE:
- case SECTION_ENCODER_TYPE:
- {
- if (!strcmp(name, "Type")) {
- mCurrentSection =
- (mCurrentSection == SECTION_DECODER_TYPE
- ? SECTION_DECODER : SECTION_ENCODER);
-
- mCurrentType = mCodecInfos[mCurrentName].mTypes.end();
- }
- break;
- }
-
- case SECTION_DECODER:
- {
- if (!strcmp(name, "MediaCodec")) {
- mCurrentSection = SECTION_DECODERS;
- mCurrentName.clear();
- }
- break;
- }
-
- case SECTION_ENCODER:
- {
- if (!strcmp(name, "MediaCodec")) {
- mCurrentSection = SECTION_ENCODERS;
- mCurrentName.clear();
- }
- break;
- }
-
- case SECTION_INCLUDE:
- {
- if (!strcmp(name, "Include") && mPastSections.size() > 0) {
- mCurrentSection = mPastSections.top();
- mPastSections.pop();
- }
- break;
- }
-
- default:
- break;
- }
-
- --mDepth;
-}
-
-status_t MediaCodecsXmlParser::addSettingFromAttributes(const char **attrs) {
- const char *name = NULL;
- const char *value = NULL;
- const char *update = NULL;
-
- size_t i = 0;
- while (attrs[i] != NULL) {
- if (!strcmp(attrs[i], "name")) {
- if (attrs[i + 1] == NULL) {
- ALOGE("addSettingFromAttributes: name is null");
- return -EINVAL;
- }
- name = attrs[i + 1];
- ++i;
- } else if (!strcmp(attrs[i], "value")) {
- if (attrs[i + 1] == NULL) {
- ALOGE("addSettingFromAttributes: value is null");
- return -EINVAL;
- }
- value = attrs[i + 1];
- ++i;
- } else if (!strcmp(attrs[i], "update")) {
- if (attrs[i + 1] == NULL) {
- ALOGE("addSettingFromAttributes: update is null");
- return -EINVAL;
- }
- update = attrs[i + 1];
- ++i;
- } else {
- ALOGE("addSettingFromAttributes: unrecognized attribute: %s", attrs[i]);
- return -EINVAL;
- }
-
- ++i;
- }
-
- if (name == NULL || value == NULL) {
- ALOGE("addSettingFromAttributes: name or value unspecified");
- return -EINVAL;
- }
-
- mUpdate = (update != NULL) && ParseBoolean(update);
- if (mUpdate != (mGlobalSettings.count(name) > 0)) {
- ALOGE("addSettingFromAttributes: updating non-existing setting");
- return -EINVAL;
- }
- mGlobalSettings[name] = value;
-
- return OK;
-}
-
-status_t MediaCodecsXmlParser::addMediaCodecFromAttributes(
- bool encoder, const char **attrs) {
- const char *name = NULL;
- const char *type = NULL;
- const char *update = NULL;
-
- size_t i = 0;
- while (attrs[i] != NULL) {
- if (!strcmp(attrs[i], "name")) {
- if (attrs[i + 1] == NULL) {
- ALOGE("addMediaCodecFromAttributes: name is null");
- return -EINVAL;
- }
- name = attrs[i + 1];
- ++i;
- } else if (!strcmp(attrs[i], "type")) {
- if (attrs[i + 1] == NULL) {
- ALOGE("addMediaCodecFromAttributes: type is null");
- return -EINVAL;
- }
- type = attrs[i + 1];
- ++i;
- } else if (!strcmp(attrs[i], "update")) {
- if (attrs[i + 1] == NULL) {
- ALOGE("addMediaCodecFromAttributes: update is null");
- return -EINVAL;
- }
- update = attrs[i + 1];
- ++i;
- } else {
- ALOGE("addMediaCodecFromAttributes: unrecognized attribute: %s", attrs[i]);
- return -EINVAL;
- }
-
- ++i;
- }
-
- if (name == NULL) {
- ALOGE("addMediaCodecFromAttributes: name not found");
- return -EINVAL;
- }
-
- mUpdate = (update != NULL) && ParseBoolean(update);
- if (mUpdate != (mCodecInfos.count(name) > 0)) {
- ALOGE("addMediaCodecFromAttributes: updating non-existing codec or vice versa");
- return -EINVAL;
- }
-
- CodecInfo *info = &mCodecInfos[name];
- if (mUpdate) {
- // existing codec
- mCurrentName = name;
- mCurrentType = info->mTypes.begin();
- if (type != NULL) {
- // existing type
- mCurrentType = findTypeInfo(*info, type);
- if (mCurrentType == info->mTypes.end()) {
- ALOGE("addMediaCodecFromAttributes: updating non-existing type");
- return -EINVAL;
- }
- }
- } else {
- // new codec
- mCurrentName = name;
- mQuirks[name].clear();
- info->mTypes.clear();
- info->mTypes.emplace_back();
- mCurrentType = --info->mTypes.end();
- mCurrentType->mName = type;
- info->mIsEncoder = encoder;
- }
-
- return OK;
-}
-
-status_t MediaCodecsXmlParser::addQuirk(const char **attrs) {
- const char *name = NULL;
-
- size_t i = 0;
- while (attrs[i] != NULL) {
- if (!strcmp(attrs[i], "name")) {
- if (attrs[i + 1] == NULL) {
- ALOGE("addQuirk: name is null");
- return -EINVAL;
- }
- name = attrs[i + 1];
- ++i;
- } else {
- ALOGE("addQuirk: unrecognized attribute: %s", attrs[i]);
- return -EINVAL;
- }
-
- ++i;
- }
-
- if (name == NULL) {
- ALOGE("addQuirk: name not found");
- return -EINVAL;
- }
-
- mQuirks[mCurrentName].emplace_back(name);
- return OK;
-}
-
-status_t MediaCodecsXmlParser::addTypeFromAttributes(const char **attrs, bool encoder) {
- const char *name = NULL;
- const char *update = NULL;
-
- size_t i = 0;
- while (attrs[i] != NULL) {
- if (!strcmp(attrs[i], "name")) {
- if (attrs[i + 1] == NULL) {
- ALOGE("addTypeFromAttributes: name is null");
- return -EINVAL;
- }
- name = attrs[i + 1];
- ++i;
- } else if (!strcmp(attrs[i], "update")) {
- if (attrs[i + 1] == NULL) {
- ALOGE("addTypeFromAttributes: update is null");
- return -EINVAL;
- }
- update = attrs[i + 1];
- ++i;
- } else {
- ALOGE("addTypeFromAttributes: unrecognized attribute: %s", attrs[i]);
- return -EINVAL;
- }
-
- ++i;
- }
-
- if (name == NULL) {
- return -EINVAL;
- }
-
- CodecInfo *info = &mCodecInfos[mCurrentName];
- info->mIsEncoder = encoder;
- mCurrentType = findTypeInfo(*info, name);
- if (!mUpdate) {
- if (mCurrentType != info->mTypes.end()) {
- ALOGE("addTypeFromAttributes: re-defining existing type without update");
- return -EINVAL;
- }
- info->mTypes.emplace_back();
- mCurrentType = --info->mTypes.end();
- } else if (mCurrentType == info->mTypes.end()) {
- ALOGE("addTypeFromAttributes: updating non-existing type");
- return -EINVAL;
- }
-
- return OK;
-}
-
-static status_t limitFoundMissingAttr(const AString &name, const char *attr, bool found = true) {
- ALOGE("limit '%s' with %s'%s' attribute", name.c_str(),
- (found ? "" : "no "), attr);
- return -EINVAL;
-}
-
-static status_t limitError(const AString &name, const char *msg) {
- ALOGE("limit '%s' %s", name.c_str(), msg);
- return -EINVAL;
-}
-
-static status_t limitInvalidAttr(const AString &name, const char *attr, const AString &value) {
- ALOGE("limit '%s' with invalid '%s' attribute (%s)", name.c_str(),
- attr, value.c_str());
- return -EINVAL;
-}
-
-status_t MediaCodecsXmlParser::addLimit(const char **attrs) {
- sp<AMessage> msg = new AMessage();
-
- size_t i = 0;
- while (attrs[i] != NULL) {
- if (attrs[i + 1] == NULL) {
- ALOGE("addLimit: limit is not given");
- return -EINVAL;
- }
-
- // attributes with values
- if (!strcmp(attrs[i], "name")
- || !strcmp(attrs[i], "default")
- || !strcmp(attrs[i], "in")
- || !strcmp(attrs[i], "max")
- || !strcmp(attrs[i], "min")
- || !strcmp(attrs[i], "range")
- || !strcmp(attrs[i], "ranges")
- || !strcmp(attrs[i], "scale")
- || !strcmp(attrs[i], "value")) {
- msg->setString(attrs[i], attrs[i + 1]);
- ++i;
- } else {
- ALOGE("addLimit: unrecognized limit: %s", attrs[i]);
- return -EINVAL;
- }
- ++i;
- }
-
- AString name;
- if (!msg->findString("name", &name)) {
- ALOGE("limit with no 'name' attribute");
- return -EINVAL;
- }
-
- // size, blocks, bitrate, frame-rate, blocks-per-second, aspect-ratio,
- // measured-frame-rate, measured-blocks-per-second: range
- // quality: range + default + [scale]
- // complexity: range + default
- bool found;
- if (mCurrentType == mCodecInfos[mCurrentName].mTypes.end()) {
- ALOGW("ignoring null type");
- return OK;
- }
-
- if (name == "aspect-ratio" || name == "bitrate" || name == "block-count"
- || name == "blocks-per-second" || name == "complexity"
- || name == "frame-rate" || name == "quality" || name == "size"
- || name == "measured-blocks-per-second" || name.startsWith("measured-frame-rate-")) {
- AString min, max;
- if (msg->findString("min", &min) && msg->findString("max", &max)) {
- min.append("-");
- min.append(max);
- if (msg->contains("range") || msg->contains("value")) {
- return limitError(name, "has 'min' and 'max' as well as 'range' or "
- "'value' attributes");
- }
- msg->setString("range", min);
- } else if (msg->contains("min") || msg->contains("max")) {
- return limitError(name, "has only 'min' or 'max' attribute");
- } else if (msg->findString("value", &max)) {
- min = max;
- min.append("-");
- min.append(max);
- if (msg->contains("range")) {
- return limitError(name, "has both 'range' and 'value' attributes");
- }
- msg->setString("range", min);
- }
-
- AString range, scale = "linear", def, in_;
- if (!msg->findString("range", &range)) {
- return limitError(name, "with no 'range', 'value' or 'min'/'max' attributes");
- }
-
- if ((name == "quality" || name == "complexity") ^
- (found = msg->findString("default", &def))) {
- return limitFoundMissingAttr(name, "default", found);
- }
- if (name != "quality" && msg->findString("scale", &scale)) {
- return limitFoundMissingAttr(name, "scale");
- }
- if ((name == "aspect-ratio") ^ (found = msg->findString("in", &in_))) {
- return limitFoundMissingAttr(name, "in", found);
- }
-
- if (name == "aspect-ratio") {
- if (!(in_ == "pixels") && !(in_ == "blocks")) {
- return limitInvalidAttr(name, "in", in_);
- }
- in_.erase(5, 1); // (pixel|block)-aspect-ratio
- in_.append("-");
- in_.append(name);
- name = in_;
- }
- if (name == "quality") {
- mCurrentType->mDetails["quality-scale"] = scale;
- }
- if (name == "quality" || name == "complexity") {
- AString tag = name;
- tag.append("-default");
- mCurrentType->mDetails[tag] = def;
- }
- AString tag = name;
- tag.append("-range");
- mCurrentType->mDetails[tag] = range;
- } else {
- AString max, value, ranges;
- if (msg->contains("default")) {
- return limitFoundMissingAttr(name, "default");
- } else if (msg->contains("in")) {
- return limitFoundMissingAttr(name, "in");
- } else if ((name == "channel-count" || name == "concurrent-instances") ^
- (found = msg->findString("max", &max))) {
- return limitFoundMissingAttr(name, "max", found);
- } else if (msg->contains("min")) {
- return limitFoundMissingAttr(name, "min");
- } else if (msg->contains("range")) {
- return limitFoundMissingAttr(name, "range");
- } else if ((name == "sample-rate") ^
- (found = msg->findString("ranges", &ranges))) {
- return limitFoundMissingAttr(name, "ranges", found);
- } else if (msg->contains("scale")) {
- return limitFoundMissingAttr(name, "scale");
- } else if ((name == "alignment" || name == "block-size") ^
- (found = msg->findString("value", &value))) {
- return limitFoundMissingAttr(name, "value", found);
- }
-
- if (max.size()) {
- AString tag = "max-";
- tag.append(name);
- mCurrentType->mDetails[tag] = max;
- } else if (value.size()) {
- mCurrentType->mDetails[name] = value;
- } else if (ranges.size()) {
- AString tag = name;
- tag.append("-ranges");
- mCurrentType->mDetails[tag] = ranges;
- } else {
- ALOGW("Ignoring unrecognized limit '%s'", name.c_str());
- }
- }
-
- return OK;
-}
-
-status_t MediaCodecsXmlParser::addFeature(const char **attrs) {
- size_t i = 0;
- const char *name = NULL;
- int32_t optional = -1;
- int32_t required = -1;
- const char *value = NULL;
-
- while (attrs[i] != NULL) {
- if (attrs[i + 1] == NULL) {
- ALOGE("addFeature: feature is not given");
- return -EINVAL;
- }
-
- // attributes with values
- if (!strcmp(attrs[i], "name")) {
- name = attrs[i + 1];
- ++i;
- } else if (!strcmp(attrs[i], "optional") || !strcmp(attrs[i], "required")) {
- int value = (int)ParseBoolean(attrs[i + 1]);
- if (!strcmp(attrs[i], "optional")) {
- optional = value;
- } else {
- required = value;
- }
- ++i;
- } else if (!strcmp(attrs[i], "value")) {
- value = attrs[i + 1];
- ++i;
- } else {
- ALOGE("addFeature: unrecognized attribute: %s", attrs[i]);
- return -EINVAL;
- }
- ++i;
- }
- if (name == NULL) {
- ALOGE("feature with no 'name' attribute");
- return -EINVAL;
- }
-
- if (optional == required && optional != -1) {
- ALOGE("feature '%s' is both/neither optional and required", name);
- return -EINVAL;
- }
-
- if (mCurrentType == mCodecInfos[mCurrentName].mTypes.end()) {
- ALOGW("ignoring null type");
- return OK;
- }
- if (value != NULL) {
- mCurrentType->mStringFeatures[name] = value;
- } else {
- mCurrentType->mBoolFeatures[name] = (required == 1) || (optional == 0);
- }
- return OK;
-}
-
-void MediaCodecsXmlParser::getGlobalSettings(
- std::map<AString, AString> *settings) const {
- settings->clear();
- settings->insert(mGlobalSettings.begin(), mGlobalSettings.end());
-}
-
-status_t MediaCodecsXmlParser::getCodecInfo(const char *name, CodecInfo *info) const {
- if (mCodecInfos.count(name) == 0) {
- ALOGE("Codec not found with name '%s'", name);
- return NAME_NOT_FOUND;
- }
- *info = mCodecInfos.at(name);
- return OK;
-}
-
-status_t MediaCodecsXmlParser::getQuirks(const char *name, std::vector<AString> *quirks) const {
- if (mQuirks.count(name) == 0) {
- ALOGE("Codec not found with name '%s'", name);
- return NAME_NOT_FOUND;
- }
- quirks->clear();
- quirks->insert(quirks->end(), mQuirks.at(name).begin(), mQuirks.at(name).end());
- return OK;
-}
-
-} // namespace android
diff --git a/radio/Android.bp b/radio/Android.bp
deleted file mode 100644
index 8e614f2..0000000
--- a/radio/Android.bp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2014 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_library_shared {
- name: "libradio",
-
- srcs: [
- "Radio.cpp",
- "IRadio.cpp",
- "IRadioClient.cpp",
- "IRadioService.cpp",
- ],
-
- shared_libs: [
- "libcutils",
- "libutils",
- "liblog",
- "libbinder",
- "libradio_metadata",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- ],
-}
diff --git a/radio/IRadio.cpp b/radio/IRadio.cpp
deleted file mode 100644
index 72f3b68..0000000
--- a/radio/IRadio.cpp
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
-**
-** Copyright 2015, 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_TAG "IRadio"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-#include <utils/Errors.h>
-#include <binder/IMemory.h>
-#include <radio/IRadio.h>
-#include <radio/IRadioService.h>
-#include <radio/IRadioClient.h>
-#include <system/radio.h>
-#include <system/RadioMetadataWrapper.h>
-
-namespace android {
-
-enum {
- DETACH = IBinder::FIRST_CALL_TRANSACTION,
- SET_CONFIGURATION,
- GET_CONFIGURATION,
- SET_MUTE,
- GET_MUTE,
- SCAN,
- STEP,
- TUNE,
- CANCEL,
- GET_PROGRAM_INFORMATION,
- HAS_CONTROL
-};
-
-class BpRadio: public BpInterface<IRadio>
-{
-public:
- explicit BpRadio(const sp<IBinder>& impl)
- : BpInterface<IRadio>(impl)
- {
- }
-
- void detach()
- {
- ALOGV("detach");
- Parcel data, reply;
- data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
- remote()->transact(DETACH, data, &reply);
- }
-
- virtual status_t setConfiguration(const struct radio_band_config *config)
- {
- Parcel data, reply;
- if (config == NULL) {
- return BAD_VALUE;
- }
- data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
- data.write(config, sizeof(struct radio_band_config));
- status_t status = remote()->transact(SET_CONFIGURATION, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- }
- return status;
- }
-
- virtual status_t getConfiguration(struct radio_band_config *config)
- {
- Parcel data, reply;
- if (config == NULL) {
- return BAD_VALUE;
- }
- data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
- status_t status = remote()->transact(GET_CONFIGURATION, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- if (status == NO_ERROR) {
- reply.read(config, sizeof(struct radio_band_config));
- }
- }
- return status;
- }
-
- virtual status_t setMute(bool mute)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
- data.writeInt32(mute ? 1 : 0);
- status_t status = remote()->transact(SET_MUTE, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- }
- return status;
- }
-
- virtual status_t getMute(bool *mute)
- {
- Parcel data, reply;
- if (mute == NULL) {
- return BAD_VALUE;
- }
- data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
- status_t status = remote()->transact(GET_MUTE, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- if (status == NO_ERROR) {
- int32_t muteread = reply.readInt32();
- *mute = muteread != 0;
- }
- }
- return status;
- }
-
- virtual status_t scan(radio_direction_t direction, bool skipSubChannel)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
- data.writeInt32(direction);
- data.writeInt32(skipSubChannel ? 1 : 0);
- status_t status = remote()->transact(SCAN, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- }
- return status;
- }
-
- virtual status_t step(radio_direction_t direction, bool skipSubChannel)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
- data.writeInt32(direction);
- data.writeInt32(skipSubChannel ? 1 : 0);
- status_t status = remote()->transact(STEP, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- }
- return status;
- }
-
- virtual status_t tune(uint32_t channel, uint32_t subChannel)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
- data.writeUint32(channel);
- data.writeUint32(subChannel);
- status_t status = remote()->transact(TUNE, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- }
- return status;
- }
-
- virtual status_t cancel()
- {
- Parcel data, reply;
- data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
- status_t status = remote()->transact(CANCEL, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- }
- return status;
- }
-
- virtual status_t getProgramInformation(struct radio_program_info *info)
- {
- Parcel data, reply;
- if (info == nullptr || info->metadata == nullptr) {
- return BAD_VALUE;
- }
- radio_metadata_t *metadata = info->metadata;
- data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
- status_t status = remote()->transact(GET_PROGRAM_INFORMATION, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- if (status == NO_ERROR) {
- reply.read(info, sizeof(struct radio_program_info));
- // restore local metadata pointer
- info->metadata = metadata;
-
- uint32_t metadataSize = reply.readUint32();
- if (metadataSize != 0) {
- radio_metadata_t *newMetadata = (radio_metadata_t *)malloc(metadataSize);
- if (newMetadata == NULL) {
- return NO_MEMORY;
- }
- reply.read(newMetadata, metadataSize);
- status = radio_metadata_add_metadata(&info->metadata, newMetadata);
- free(newMetadata);
- }
- }
- }
- return status;
- }
-
- virtual status_t hasControl(bool *hasControl)
- {
- Parcel data, reply;
- if (hasControl == NULL) {
- return BAD_VALUE;
- }
- data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
- status_t status = remote()->transact(HAS_CONTROL, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- if (status == NO_ERROR) {
- *hasControl = reply.readInt32() != 0;
- }
- }
- return status;
- }
-};
-
-IMPLEMENT_META_INTERFACE(Radio, "android.hardware.IRadio");
-
-// ----------------------------------------------------------------------
-
-status_t BnRadio::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case DETACH: {
- ALOGV("DETACH");
- CHECK_INTERFACE(IRadio, data, reply);
- detach();
- return NO_ERROR;
- } break;
- case SET_CONFIGURATION: {
- CHECK_INTERFACE(IRadio, data, reply);
- struct radio_band_config config;
- data.read(&config, sizeof(struct radio_band_config));
- status_t status = setConfiguration(&config);
- reply->writeInt32(status);
- return NO_ERROR;
- }
- case GET_CONFIGURATION: {
- CHECK_INTERFACE(IRadio, data, reply);
- struct radio_band_config config;
- status_t status = getConfiguration(&config);
- reply->writeInt32(status);
- if (status == NO_ERROR) {
- reply->write(&config, sizeof(struct radio_band_config));
- }
- return NO_ERROR;
- }
- case SET_MUTE: {
- CHECK_INTERFACE(IRadio, data, reply);
- bool mute = data.readInt32() != 0;
- status_t status = setMute(mute);
- reply->writeInt32(status);
- return NO_ERROR;
- }
- case GET_MUTE: {
- CHECK_INTERFACE(IRadio, data, reply);
- bool mute;
- status_t status = getMute(&mute);
- reply->writeInt32(status);
- if (status == NO_ERROR) {
- reply->writeInt32(mute ? 1 : 0);
- }
- return NO_ERROR;
- }
- case SCAN: {
- CHECK_INTERFACE(IRadio, data, reply);
- radio_direction_t direction = (radio_direction_t)data.readInt32();
- bool skipSubChannel = data.readInt32() == 1;
- status_t status = scan(direction, skipSubChannel);
- reply->writeInt32(status);
- return NO_ERROR;
- }
- case STEP: {
- CHECK_INTERFACE(IRadio, data, reply);
- radio_direction_t direction = (radio_direction_t)data.readInt32();
- bool skipSubChannel = data.readInt32() == 1;
- status_t status = step(direction, skipSubChannel);
- reply->writeInt32(status);
- return NO_ERROR;
- }
- case TUNE: {
- CHECK_INTERFACE(IRadio, data, reply);
- uint32_t channel = data.readUint32();
- uint32_t subChannel = data.readUint32();
- status_t status = tune(channel, subChannel);
- reply->writeInt32(status);
- return NO_ERROR;
- }
- case CANCEL: {
- CHECK_INTERFACE(IRadio, data, reply);
- status_t status = cancel();
- reply->writeInt32(status);
- return NO_ERROR;
- }
- case GET_PROGRAM_INFORMATION: {
- CHECK_INTERFACE(IRadio, data, reply);
- struct radio_program_info info;
- RadioMetadataWrapper metadataWrapper(&info.metadata);
-
- status_t status = getProgramInformation(&info);
- reply->writeInt32(status);
- if (status == NO_ERROR) {
- reply->write(&info, sizeof(struct radio_program_info));
- if (radio_metadata_get_count(info.metadata) > 0) {
- size_t size = radio_metadata_get_size(info.metadata);
- reply->writeUint32((uint32_t)size);
- reply->write(info.metadata, size);
- } else {
- reply->writeUint32(0);
- }
- }
- return NO_ERROR;
- }
- case HAS_CONTROL: {
- CHECK_INTERFACE(IRadio, data, reply);
- bool control;
- status_t status = hasControl(&control);
- reply->writeInt32(status);
- if (status == NO_ERROR) {
- reply->writeInt32(control ? 1 : 0);
- }
- return NO_ERROR;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/radio/IRadioClient.cpp b/radio/IRadioClient.cpp
deleted file mode 100644
index ca21949..0000000
--- a/radio/IRadioClient.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <binder/IMemory.h>
-#include <binder/Parcel.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <radio/IRadioClient.h>
-
-namespace android {
-
-enum {
- ON_EVENT = IBinder::FIRST_CALL_TRANSACTION,
-};
-
-class BpRadioClient: public BpInterface<IRadioClient>
-{
-
-public:
- explicit BpRadioClient(const sp<IBinder>& impl)
- : BpInterface<IRadioClient>(impl)
- {
- }
-
- virtual void onEvent(const sp<IMemory>& eventMemory)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IRadioClient::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(eventMemory));
- remote()->transact(ON_EVENT,
- data,
- &reply);
- }
-};
-
-IMPLEMENT_META_INTERFACE(RadioClient,
- "android.hardware.IRadioClient");
-
-// ----------------------------------------------------------------------
-
-status_t BnRadioClient::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case ON_EVENT: {
- CHECK_INTERFACE(IRadioClient, data, reply);
- sp<IMemory> eventMemory = interface_cast<IMemory>(
- data.readStrongBinder());
- onEvent(eventMemory);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- } return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/radio/IRadioService.cpp b/radio/IRadioService.cpp
deleted file mode 100644
index 72e3a61..0000000
--- a/radio/IRadioService.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
-**
-** Copyright 2015, 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_TAG "BpRadioService"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <utils/Errors.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <binder/IMemory.h>
-#include <binder/Parcel.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-
-#include <radio/IRadioService.h>
-#include <radio/IRadio.h>
-#include <radio/IRadioClient.h>
-
-namespace android {
-
-enum {
- LIST_MODULES = IBinder::FIRST_CALL_TRANSACTION,
- ATTACH,
-};
-
-#define MAX_ITEMS_PER_LIST 1024
-
-class BpRadioService: public BpInterface<IRadioService>
-{
-public:
- explicit BpRadioService(const sp<IBinder>& impl)
- : BpInterface<IRadioService>(impl)
- {
- }
-
- virtual status_t listModules(struct radio_properties *properties,
- uint32_t *numModules)
- {
- if (numModules == NULL || (*numModules != 0 && properties == NULL)) {
- return BAD_VALUE;
- }
- Parcel data, reply;
- data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
- uint32_t numModulesReq = (properties == NULL) ? 0 : *numModules;
- data.writeInt32(numModulesReq);
- status_t status = remote()->transact(LIST_MODULES, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- *numModules = (uint32_t)reply.readInt32();
- }
- ALOGV("listModules() status %d got *numModules %d", status, *numModules);
- if (status == NO_ERROR) {
- if (numModulesReq > *numModules) {
- numModulesReq = *numModules;
- }
- if (numModulesReq > 0) {
- reply.read(properties, numModulesReq * sizeof(struct radio_properties));
- }
- }
- return status;
- }
-
- virtual status_t attach(radio_handle_t handle,
- const sp<IRadioClient>& client,
- const struct radio_band_config *config,
- bool withAudio,
- sp<IRadio>& radio)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
- data.writeInt32(handle);
- data.writeStrongBinder(IInterface::asBinder(client));
- ALOGV("attach() config %p withAudio %d region %d type %d",
- config == NULL ? 0 : config, withAudio,
- config == NULL ? 0 : config->region,
- config == NULL ? 0 : config->band.type);
- if (config == NULL) {
- data.writeInt32(0);
- } else {
- data.writeInt32(1);
- data.write(config, sizeof(struct radio_band_config));
- }
- data.writeInt32(withAudio ? 1 : 0);
- status_t status = remote()->transact(ATTACH, data, &reply);
- if (status != NO_ERROR) {
- return status;
- }
- status = reply.readInt32();
- if (reply.readInt32() != 0) {
- radio = interface_cast<IRadio>(reply.readStrongBinder());
- }
- return status;
- }
-};
-
-IMPLEMENT_META_INTERFACE(RadioService, "android.hardware.IRadioService");
-
-// ----------------------------------------------------------------------
-
-status_t BnRadioService::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case LIST_MODULES: {
- CHECK_INTERFACE(IRadioService, data, reply);
- uint32_t numModulesReq = data.readInt32();
- if (numModulesReq > MAX_ITEMS_PER_LIST) {
- numModulesReq = MAX_ITEMS_PER_LIST;
- }
- uint32_t numModules = numModulesReq;
- struct radio_properties *properties =
- (struct radio_properties *)calloc(numModulesReq,
- sizeof(struct radio_properties));
- if (properties == NULL) {
- reply->writeInt32(NO_MEMORY);
- reply->writeInt32(0);
- return NO_ERROR;
- }
-
- status_t status = listModules(properties, &numModules);
- reply->writeInt32(status);
- reply->writeInt32(numModules);
- ALOGV("LIST_MODULES status %d got numModules %d", status, numModules);
-
- if (status == NO_ERROR) {
- if (numModulesReq > numModules) {
- numModulesReq = numModules;
- }
- reply->write(properties,
- numModulesReq * sizeof(struct radio_properties));
- }
- free(properties);
- return NO_ERROR;
- } break;
-
- case ATTACH: {
- CHECK_INTERFACE(IRadioService, data, reply);
- radio_handle_t handle = data.readInt32();
- sp<IRadioClient> client =
- interface_cast<IRadioClient>(data.readStrongBinder());
- struct radio_band_config config;
- struct radio_band_config *configPtr = NULL;
- if (data.readInt32() != 0) {
- data.read(&config, sizeof(struct radio_band_config));
- configPtr = &config;
- }
- bool withAudio = data.readInt32() != 0;
- ALOGV("ATTACH configPtr %p withAudio %d", configPtr, withAudio);
- sp<IRadio> radio;
- status_t status = attach(handle, client, configPtr, withAudio, radio);
- reply->writeInt32(status);
- if (radio != 0) {
- reply->writeInt32(1);
- reply->writeStrongBinder(IInterface::asBinder(radio));
- } else {
- reply->writeInt32(0);
- }
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/radio/Radio.cpp b/radio/Radio.cpp
deleted file mode 100644
index 9ddd221..0000000
--- a/radio/Radio.cpp
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
-**
-** Copyright (C) 2015, 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_TAG "Radio"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <utils/threads.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/IMemory.h>
-
-#include <radio/Radio.h>
-#include <radio/IRadio.h>
-#include <radio/IRadioService.h>
-#include <radio/IRadioClient.h>
-#include <radio/RadioCallback.h>
-
-namespace android {
-
-namespace {
- sp<IRadioService> gRadioService;
- const int kRadioServicePollDelay = 500000; // 0.5s
- const char* kRadioServiceName = "media.radio";
- Mutex gLock;
-
- class DeathNotifier : public IBinder::DeathRecipient
- {
- public:
- DeathNotifier() {
- }
-
- virtual void binderDied(const wp<IBinder>& who __unused) {
- ALOGV("binderDied");
- Mutex::Autolock _l(gLock);
- gRadioService.clear();
- ALOGW("Radio service died!");
- }
- };
-
- sp<DeathNotifier> gDeathNotifier;
-}; // namespace anonymous
-
-const sp<IRadioService> Radio::getRadioService()
-{
- Mutex::Autolock _l(gLock);
- if (gRadioService.get() == 0) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- do {
- binder = sm->getService(String16(kRadioServiceName));
- if (binder != 0) {
- break;
- }
- ALOGW("RadioService not published, waiting...");
- usleep(kRadioServicePollDelay);
- } while(true);
- if (gDeathNotifier == NULL) {
- gDeathNotifier = new DeathNotifier();
- }
- binder->linkToDeath(gDeathNotifier);
- gRadioService = interface_cast<IRadioService>(binder);
- }
- ALOGE_IF(gRadioService == 0, "no RadioService!?");
- return gRadioService;
-}
-
-// Static methods
-status_t Radio::listModules(struct radio_properties *properties,
- uint32_t *numModules)
-{
- ALOGV("listModules()");
- const sp<IRadioService> service = getRadioService();
- if (service == 0) {
- return NO_INIT;
- }
- return service->listModules(properties, numModules);
-}
-
-sp<Radio> Radio::attach(radio_handle_t handle,
- const struct radio_band_config *config,
- bool withAudio,
- const sp<RadioCallback>& callback)
-{
- ALOGV("attach()");
- sp<Radio> radio;
- const sp<IRadioService> service = getRadioService();
- if (service == 0) {
- return radio;
- }
- radio = new Radio(handle, callback);
- status_t status = service->attach(handle, radio, config, withAudio, radio->mIRadio);
-
- if (status == NO_ERROR && radio->mIRadio != 0) {
- IInterface::asBinder(radio->mIRadio)->linkToDeath(radio);
- } else {
- ALOGW("Error %d connecting to radio service", status);
- radio.clear();
- }
- return radio;
-}
-
-
-
-// Radio
-Radio::Radio(radio_handle_t /*handle*/, const sp<RadioCallback>& callback)
- : mCallback(callback)
-{
-}
-
-Radio::~Radio()
-{
- if (mIRadio != 0) {
- mIRadio->detach();
- }
-}
-
-
-void Radio::detach() {
- ALOGV("detach()");
- Mutex::Autolock _l(mLock);
- mCallback.clear();
- if (mIRadio != 0) {
- mIRadio->detach();
- IInterface::asBinder(mIRadio)->unlinkToDeath(this);
- mIRadio = 0;
- }
-}
-
-status_t Radio::setConfiguration(const struct radio_band_config *config)
-{
- Mutex::Autolock _l(mLock);
- if (mIRadio == 0) {
- return NO_INIT;
- }
- return mIRadio->setConfiguration(config);
-}
-
-status_t Radio::getConfiguration(struct radio_band_config *config)
-{
- Mutex::Autolock _l(mLock);
- if (mIRadio == 0) {
- return NO_INIT;
- }
- return mIRadio->getConfiguration(config);
-}
-
-status_t Radio::setMute(bool mute)
-{
- Mutex::Autolock _l(mLock);
- if (mIRadio == 0) {
- return NO_INIT;
- }
- return mIRadio->setMute(mute);
-}
-
-status_t Radio::getMute(bool *mute)
-{
- Mutex::Autolock _l(mLock);
- if (mIRadio == 0) {
- return NO_INIT;
- }
- return mIRadio->getMute(mute);
-}
-
-status_t Radio::scan(radio_direction_t direction, bool skipSubchannel)
-{
- Mutex::Autolock _l(mLock);
- if (mIRadio == 0) {
- return NO_INIT;
- }
- return mIRadio->scan(direction, skipSubchannel);
-}
-
-status_t Radio::step(radio_direction_t direction, bool skipSubchannel)
-{
- Mutex::Autolock _l(mLock);
- if (mIRadio == 0) {
- return NO_INIT;
- }
- return mIRadio->step(direction, skipSubchannel);
-}
-
-status_t Radio::tune(unsigned int channel, unsigned int subChannel)
-{
- Mutex::Autolock _l(mLock);
- if (mIRadio == 0) {
- return NO_INIT;
- }
- return mIRadio->tune(channel, subChannel);
-}
-
-status_t Radio::cancel()
-{
- Mutex::Autolock _l(mLock);
- if (mIRadio == 0) {
- return NO_INIT;
- }
- return mIRadio->cancel();
-}
-
-status_t Radio::getProgramInformation(struct radio_program_info *info)
-{
- Mutex::Autolock _l(mLock);
- if (mIRadio == 0) {
- return NO_INIT;
- }
- return mIRadio->getProgramInformation(info);
-}
-
-status_t Radio::hasControl(bool *hasControl)
-{
- Mutex::Autolock _l(mLock);
- if (mIRadio == 0) {
- return NO_INIT;
- }
- return mIRadio->hasControl(hasControl);
-}
-
-
-// BpRadioClient
-void Radio::onEvent(const sp<IMemory>& eventMemory)
-{
- Mutex::Autolock _l(mLock);
- if (eventMemory == 0 || eventMemory->pointer() == NULL) {
- return;
- }
-
- // The event layout in shared memory is:
- // sizeof(struct radio_event) bytes : the event itself
- // 4 bytes : metadata size or 0
- // N bytes : metadata if present
- struct radio_event *event = (struct radio_event *)eventMemory->pointer();
- uint32_t metadataOffset = sizeof(struct radio_event) + sizeof(uint32_t);
- uint32_t metadataSize = *(uint32_t *)((uint8_t *)event + metadataOffset - sizeof(uint32_t));
-
- // restore local metadata pointer from offset
- switch (event->type) {
- case RADIO_EVENT_TUNED:
- case RADIO_EVENT_AF_SWITCH:
- if (metadataSize != 0) {
- event->info.metadata =
- (radio_metadata_t *)((uint8_t *)event + metadataOffset);
- } else {
- event->info.metadata = 0;
- }
- break;
- case RADIO_EVENT_METADATA:
- if (metadataSize != 0) {
- event->metadata =
- (radio_metadata_t *)((uint8_t *)event + metadataOffset);
- } else {
- event->metadata = 0;
- }
- break;
- default:
- break;
- }
-
- if (mCallback != 0) {
- mCallback->onEvent(event);
- }
-}
-
-
-//IBinder::DeathRecipient
-void Radio::binderDied(const wp<IBinder>& who __unused) {
- Mutex::Autolock _l(mLock);
- ALOGW("Radio server binder Died ");
- mIRadio = 0;
- struct radio_event event;
- memset(&event, 0, sizeof(struct radio_event));
- event.type = RADIO_EVENT_SERVER_DIED;
- event.status = DEAD_OBJECT;
- if (mCallback != 0) {
- mCallback->onEvent(&event);
- }
-}
-
-}; // namespace android
diff --git a/services/OWNERS b/services/OWNERS
new file mode 100644
index 0000000..d500dce
--- /dev/null
+++ b/services/OWNERS
@@ -0,0 +1,4 @@
+elaurent@google.com
+etalvala@google.com
+gkasten@android.com
+hunga@google.com
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 111193c..ff5f745 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -326,9 +326,14 @@
sp<MmapThread> thread = mMmapThreads.valueFor(io);
if (thread != 0) {
interface = new MmapThreadHandle(thread);
- thread->configure(attr, streamType, sessionId, callback, portId);
+ thread->configure(attr, streamType, sessionId, callback, *deviceId, portId);
*handle = portId;
} else {
+ if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
+ AudioSystem::releaseOutput(io, streamType, sessionId);
+ } else {
+ AudioSystem::releaseInput(io, sessionId);
+ }
ret = NO_INIT;
}
@@ -1397,11 +1402,11 @@
// the config change is always sent from playback or record threads to avoid deadlock
// with AudioSystem::gLock
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_OPENED, pid);
+ mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_REGISTERED, pid);
}
for (size_t i = 0; i < mRecordThreads.size(); i++) {
- mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_OPENED, pid);
+ mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_REGISTERED, pid);
}
}
@@ -2603,7 +2608,7 @@
while (ec->mEffects.size()) {
sp<EffectModule> effect = ec->mEffects[0];
effect->unPin();
- t->removeEffect_l(effect);
+ t->removeEffect_l(effect, /*release*/ true);
if (effect->purgeHandles()) {
t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId());
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 9023b2d..63898a0 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -604,7 +604,7 @@
virtual status_t standby();
private:
- sp<MmapThread> mThread;
+ const sp<MmapThread> mThread;
};
ThreadBase *checkThread_l(audio_io_handle_t ioHandle) const;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index f2c1c4f..bd5f146 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -25,6 +25,7 @@
#include <system/audio_effects/effect_ns.h>
#include <system/audio_effects/effect_visualizer.h>
#include <audio_utils/primitives.h>
+#include <media/AudioEffect.h>
#include <media/audiohal/EffectHalInterface.h>
#include <media/audiohal/EffectsFactoryHalInterface.h>
@@ -109,7 +110,10 @@
{
ALOGV("Destructor %p", this);
if (mEffectInterface != 0) {
- ALOGW("EffectModule %p destructor called with unreleased interface", this);
+ char uuidStr[64];
+ AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
+ ALOGW("EffectModule %p destructor called with unreleased interface, effect %s",
+ this, uuidStr);
release_l();
}
@@ -1081,18 +1085,12 @@
result.append(buffer);
result.append("\t\tDescriptor:\n");
- snprintf(buffer, SIZE, "\t\t- UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
- mDescriptor.uuid.timeLow, mDescriptor.uuid.timeMid, mDescriptor.uuid.timeHiAndVersion,
- mDescriptor.uuid.clockSeq, mDescriptor.uuid.node[0], mDescriptor.uuid.node[1],
- mDescriptor.uuid.node[2],
- mDescriptor.uuid.node[3],mDescriptor.uuid.node[4],mDescriptor.uuid.node[5]);
+ char uuidStr[64];
+ AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
+ snprintf(buffer, SIZE, "\t\t- UUID: %s\n", uuidStr);
result.append(buffer);
- snprintf(buffer, SIZE, "\t\t- TYPE: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
- mDescriptor.type.timeLow, mDescriptor.type.timeMid,
- mDescriptor.type.timeHiAndVersion,
- mDescriptor.type.clockSeq, mDescriptor.type.node[0], mDescriptor.type.node[1],
- mDescriptor.type.node[2],
- mDescriptor.type.node[3],mDescriptor.type.node[4],mDescriptor.type.node[5]);
+ AudioEffect::guidToString(&mDescriptor.type, uuidStr, sizeof(uuidStr));
+ snprintf(buffer, SIZE, "\t\t- TYPE: %s\n", uuidStr);
result.append(buffer);
snprintf(buffer, SIZE, "\t\t- apiVersion: %08X\n\t\t- flags: %08X (%s)\n",
mDescriptor.apiVersion,
@@ -1306,11 +1304,10 @@
if (thread != 0) {
thread->disconnectEffectHandle(this, unpinIfLast);
} else {
- ALOGW("%s Effect handle %p disconnected after thread destruction", __FUNCTION__, this);
// try to cleanup as much as we can
sp<EffectModule> effect = mEffect.promote();
- if (effect != 0) {
- effect->disconnectHandle(this, unpinIfLast);
+ if (effect != 0 && effect->disconnectHandle(this, unpinIfLast) > 0) {
+ ALOGW("%s Effect handle %p disconnected after thread destruction", __FUNCTION__, this);
}
}
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index c4f1af3..c10fa05 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -138,7 +138,8 @@
void FastMixer::onStateChange()
{
- LOG_HIST_FLUSH();
+ // log that audio was turned on/off
+ LOG_AUDIO_STATE();
const FastMixerState * const current = (const FastMixerState *) mCurrent;
const FastMixerState * const previous = (const FastMixerState *) mPrevious;
FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState;
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
index 2a27dfd..366a164 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -28,6 +28,7 @@
audio_channel_mask_t channelMask,
audio_session_t sessionId,
uid_t uid,
+ pid_t pid,
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
virtual ~MmapTrack();
@@ -39,7 +40,7 @@
virtual bool isFastTrack() const { return false; }
static void appendDumpHeader(String8& result);
- void dump(char* buffer, size_t size);
+ void appendDump(String8& result, bool active);
private:
friend class MmapThread;
@@ -55,5 +56,6 @@
virtual int64_t framesReleased() const;
virtual void onTimestamp(const ExtendedTimestamp ×tamp);
+ pid_t mPid;
}; // end of Track
diff --git a/services/audioflinger/OWNERS b/services/audioflinger/OWNERS
new file mode 100644
index 0000000..703e4d2
--- /dev/null
+++ b/services/audioflinger/OWNERS
@@ -0,0 +1,3 @@
+hunga@google.com
+jmtrivi@google.com
+mnaganov@google.com
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index d7c0728..27c6d35 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -474,6 +474,7 @@
format,
frameCount,
NULL,
+ (size_t)0 /* bufferSize */,
AUDIO_INPUT_FLAG_NONE);
if (patch->mPatchRecord == 0) {
return NO_MEMORY;
@@ -494,6 +495,7 @@
format,
frameCount,
patch->mPatchRecord->buffer(),
+ patch->mPatchRecord->bufferSize(),
AUDIO_OUTPUT_FLAG_NONE);
if (patch->mPatchTrack == 0) {
return NO_MEMORY;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 3f1a0c0..1c1a989 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -30,6 +30,7 @@
audio_channel_mask_t channelMask,
size_t frameCount,
void *buffer,
+ size_t bufferSize,
const sp<IMemory>& sharedBuffer,
audio_session_t sessionId,
uid_t uid,
@@ -40,7 +41,7 @@
virtual status_t initCheck() const;
static void appendDumpHeader(String8& result);
- void dump(char* buffer, size_t size, bool active);
+ void appendDump(String8& result, bool active);
virtual status_t start(AudioSystem::sync_event_t event =
AudioSystem::SYNC_EVENT_NONE,
audio_session_t triggerSession = AUDIO_SESSION_NONE);
@@ -240,6 +241,7 @@
audio_format_t format,
size_t frameCount,
void *buffer,
+ size_t bufferSize,
audio_output_flags_t flags);
virtual ~PatchTrack();
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 3f83ca8..f8da780 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -29,6 +29,7 @@
audio_channel_mask_t channelMask,
size_t frameCount,
void *buffer,
+ size_t bufferSize,
audio_session_t sessionId,
uid_t uid,
audio_input_flags_t flags,
@@ -50,7 +51,7 @@
return tmp; }
static void appendDumpHeader(String8& result);
- void dump(char* buffer, size_t size, bool active);
+ void appendDump(String8& result, bool active);
void handleSyncStartEvent(const sp<SyncEvent>& event);
void clearSyncStartEvent();
@@ -102,6 +103,7 @@
audio_format_t format,
size_t frameCount,
void *buffer,
+ size_t bufferSize,
audio_input_flags_t flags);
virtual ~PatchRecord();
diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp
index 3c73543..c1044ef 100644
--- a/services/audioflinger/ServiceUtilities.cpp
+++ b/services/audioflinger/ServiceUtilities.cpp
@@ -113,10 +113,15 @@
return ok;
}
-bool captureHotwordAllowed() {
- static const String16 sCaptureHotwordAllowed("android.permission.CAPTURE_AUDIO_HOTWORD");
- // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
- bool ok = PermissionCache::checkCallingPermission(sCaptureHotwordAllowed);
+bool captureHotwordAllowed(pid_t pid, uid_t uid) {
+ // CAPTURE_AUDIO_HOTWORD permission implies RECORD_AUDIO permission
+ bool ok = recordingAllowed(String16(""), pid, uid);
+
+ if (ok) {
+ static const String16 sCaptureHotwordAllowed("android.permission.CAPTURE_AUDIO_HOTWORD");
+ // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
+ ok = PermissionCache::checkCallingPermission(sCaptureHotwordAllowed);
+ }
if (!ok) ALOGE("android.permission.CAPTURE_AUDIO_HOTWORD");
return ok;
}
diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h
index 8b1bc00..04cb9cd 100644
--- a/services/audioflinger/ServiceUtilities.h
+++ b/services/audioflinger/ServiceUtilities.h
@@ -22,7 +22,7 @@
bool isTrustedCallingUid(uid_t uid);
bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
bool captureAudioOutputAllowed(pid_t pid, uid_t uid);
-bool captureHotwordAllowed();
+bool captureHotwordAllowed(pid_t pid, uid_t uid);
bool settingsAllowed();
bool modifyAudioRoutingAllowed();
bool dumpAllowed();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 65eccb6..e202ca4 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -197,7 +197,7 @@
// Initially this heap is used to allocate client buffers for "fast" AudioRecord.
// Eventually it will be the single buffer that FastCapture writes into via HAL read(),
// and that all "fast" AudioRecord clients read from. In either case, the size can be small.
-static const size_t kRecordThreadReadOnlyHeapSize = 0x2000;
+static const size_t kRecordThreadReadOnlyHeapSize = 0x4000;
// ----------------------------------------------------------------------------
@@ -1544,6 +1544,7 @@
ALOGW("ActiveTracks<T>::add track %p already there", track.get());
return index;
}
+ logTrack("add", track);
mActiveTracksGeneration++;
mLatestActiveTrack = track;
++mBatteryCounter[track->uid()].second;
@@ -1557,6 +1558,7 @@
ALOGW("ActiveTracks<T>::remove nonexistent track %p", track.get());
return index;
}
+ logTrack("remove", track);
mActiveTracksGeneration++;
--mBatteryCounter[track->uid()].second;
// mLatestActiveTrack is not cleared even if is the same as track.
@@ -1567,6 +1569,7 @@
void AudioFlinger::ThreadBase::ActiveTracks<T>::clear() {
for (const sp<T> &track : mActiveTracks) {
BatteryNotifier::getInstance().noteStopAudio(track->uid());
+ logTrack("clear", track);
}
mLastActiveTracksGeneration = mActiveTracksGeneration;
mActiveTracks.clear();
@@ -1605,6 +1608,16 @@
}
}
+template <typename T>
+void AudioFlinger::ThreadBase::ActiveTracks<T>::logTrack(
+ const char *funcName, const sp<T> &track) const {
+ if (mLocalLog != nullptr) {
+ String8 result;
+ track->appendDump(result, false /* active */);
+ mLocalLog->log("AT::%-10s(%p) %s", funcName, track.get(), result.string());
+ }
+}
+
void AudioFlinger::ThreadBase::broadcast_l()
{
// Thread could be blocked waiting for async
@@ -1640,6 +1653,7 @@
mSuspended(0), mBytesWritten(0),
mFramesWritten(0),
mSuspendedFrames(0),
+ mActiveTracks(&this->mLocalLog),
// mStreamTypes[] initialized in constructor body
mOutput(output),
mLastWriteTime(-1), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
@@ -1654,7 +1668,8 @@
mScreenState(AudioFlinger::mScreenState),
// index 0 is reserved for normal mixer's submix
mFastTrackAvailMask(((1 << FastMixerState::sMaxFastTracks) - 1) & ~1),
- mHwSupportsPause(false), mHwPaused(false), mFlushPending(false)
+ mHwSupportsPause(false), mHwPaused(false), mFlushPending(false),
+ mLeftVolFloat(-1.0), mRightVolFloat(-1.0)
{
snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id);
mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
@@ -1707,8 +1722,6 @@
void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args __unused)
{
- const size_t SIZE = 256;
- char buffer[SIZE];
String8 result;
result.appendFormat(" Stream volumes in dB: ");
@@ -1735,8 +1748,10 @@
size_t numactive = mActiveTracks.size();
dprintf(fd, " %zu Tracks", numtracks);
size_t numactiveseen = 0;
+ const char *prefix = " ";
if (numtracks) {
dprintf(fd, " of which %zu are active\n", numactive);
+ result.append(prefix);
Track::appendDumpHeader(result);
for (size_t i = 0; i < numtracks; ++i) {
sp<Track> track = mTracks[i];
@@ -1745,8 +1760,8 @@
if (active) {
numactiveseen++;
}
- track->dump(buffer, SIZE, active);
- result.append(buffer);
+ result.append(prefix);
+ track->appendDump(result, active);
}
}
} else {
@@ -1754,15 +1769,15 @@
}
if (numactiveseen != numactive) {
// some tracks in the active list were not in the tracks list
- snprintf(buffer, SIZE, " The following tracks are in the active list but"
+ result.append(" The following tracks are in the active list but"
" not in the track list\n");
- result.append(buffer);
+ result.append(prefix);
Track::appendDumpHeader(result);
for (size_t i = 0; i < numactive; ++i) {
sp<Track> track = mActiveTracks[i];
if (mTracks.indexOf(track) < 0) {
- track->dump(buffer, SIZE, true);
- result.append(buffer);
+ result.append(prefix);
+ track->appendDump(result, true /* active */);
}
}
}
@@ -2013,7 +2028,8 @@
}
track = new Track(this, client, streamType, sampleRate, format,
- channelMask, frameCount, NULL, sharedBuffer,
+ channelMask, frameCount,
+ nullptr /* buffer */, (size_t)0 /* bufferSize */, sharedBuffer,
sessionId, uid, *flags, TrackBase::TYPE_DEFAULT, portId);
lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY;
@@ -2172,10 +2188,6 @@
chain->incActiveTrackCnt();
}
- char buffer[256];
- track->dump(buffer, arraysize(buffer), false /* active */);
- mLocalLog.log("addTrack_l (%p) %s", track.get(), buffer + 4); // log for analysis
-
status = NO_ERROR;
}
@@ -2202,9 +2214,9 @@
{
track->triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);
- char buffer[256];
- track->dump(buffer, arraysize(buffer), false /* active */);
- mLocalLog.log("removeTrack_l (%p) %s", track.get(), buffer + 4); // log for analysis
+ String8 result;
+ track->appendDump(result, false /* active */);
+ mLocalLog.log("removeTrack_l (%p) %s", track.get(), result.string());
mTracks.remove(track);
deleteTrackName_l(track->name());
@@ -2242,6 +2254,7 @@
switch (event) {
case AUDIO_OUTPUT_OPENED:
+ case AUDIO_OUTPUT_REGISTERED:
case AUDIO_OUTPUT_CONFIG_CHANGED:
desc->mPatch = mPatch;
desc->mChannelMask = mChannelMask;
@@ -3404,10 +3417,6 @@
}
if (track->isTerminated()) {
removeTrack_l(track);
- } else { // inactive but not terminated
- char buffer[256];
- track->dump(buffer, arraysize(buffer), false /* active */);
- mLocalLog.log("removeTracks_l(%p) %s", track.get(), buffer + 4);
}
}
}
@@ -4287,6 +4296,7 @@
param = AudioMixer::RAMP_VOLUME;
}
mAudioMixer->setParameter(name, AudioMixer::RESAMPLE, AudioMixer::RESET, NULL);
+ mLeftVolFloat = -1.0;
// FIXME should not make a decision based on mServer
} else if (cblk->mServer != 0) {
// If the track is stopped before the first frame was mixed,
@@ -4297,6 +4307,10 @@
// compute volume for this track
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;
+
if (track->isPausing() || mStreamTypes[track->streamType()].mute) {
vl = vr = 0;
vlf = vrf = vaf = 0.;
@@ -4304,10 +4318,6 @@
track->setPaused();
}
} else {
-
- // read original volumes with volume control
- float typeVolume = mStreamTypes[track->streamType()].volume;
- float v = masterVolume * typeVolume;
sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
gain_minifloat_packed_t vlr = proxy->getVolumeLR();
vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
@@ -4359,6 +4369,25 @@
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(name, track);
mAudioMixer->enable(name);
@@ -4800,7 +4829,6 @@
AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device, bool systemReady)
: PlaybackThread(audioFlinger, output, id, device, DIRECT, systemReady)
- // mLeftVolFloat, mRightVolFloat
{
}
@@ -4808,7 +4836,6 @@
AudioStreamOut* output, audio_io_handle_t id, uint32_t device,
ThreadBase::type_t type, bool systemReady)
: PlaybackThread(audioFlinger, output, id, device, type, systemReady)
- // mLeftVolFloat, mRightVolFloat
, mVolumeShaperActive(false)
{
}
@@ -5925,7 +5952,9 @@
#endif
) :
ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD, systemReady),
- mInput(input), mRsmpInBuffer(NULL),
+ mInput(input),
+ mActiveTracks(&this->mLocalLog),
+ mRsmpInBuffer(NULL),
// mRsmpInFrames, mRsmpInFramesP2, and mRsmpInFramesOA are set by readInputParameters_l()
mRsmpInRear(0)
#ifdef TEE_SINK
@@ -6696,7 +6725,8 @@
Mutex::Autolock _l(mLock);
track = new RecordTrack(this, client, sampleRate,
- format, channelMask, frameCount, NULL, sessionId, uid,
+ format, channelMask, frameCount,
+ nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, uid,
*flags, TrackBase::TYPE_DEFAULT, portId);
lStatus = track->initCheck();
@@ -6888,6 +6918,10 @@
void AudioFlinger::RecordThread::removeTrack_l(const sp<RecordTrack>& track)
{
+ String8 result;
+ track->appendDump(result, false /* active */);
+ mLocalLog.log("removeTrack_l (%p) %s", track.get(), result.string());
+
mTracks.remove(track);
// need anything related to effects here?
if (track->isFastTrack()) {
@@ -6901,6 +6935,8 @@
dumpInternals(fd, args);
dumpTracks(fd, args);
dumpEffectChains(fd, args);
+ dprintf(fd, " Local log:\n");
+ mLocalLog.dump(fd, " " /* prefix */, 40 /* lines */);
}
void AudioFlinger::RecordThread::dumpInternals(int fd, const Vector<String16>& args)
@@ -6914,6 +6950,12 @@
if (mActiveTracks.size() == 0) {
dprintf(fd, " No active record clients\n");
}
+
+ if (input != nullptr) {
+ dprintf(fd, " Hal stream dump:\n");
+ (void)input->stream->dump(fd);
+ }
+
dprintf(fd, " Fast capture thread: %s\n", hasFastCapture() ? "yes" : "no");
dprintf(fd, " Fast track available: %s\n", mFastTrackAvail ? "yes" : "no");
@@ -6928,16 +6970,15 @@
void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args __unused)
{
- const size_t SIZE = 256;
- char buffer[SIZE];
String8 result;
-
size_t numtracks = mTracks.size();
size_t numactive = mActiveTracks.size();
size_t numactiveseen = 0;
dprintf(fd, " %zu Tracks", numtracks);
+ const char *prefix = " ";
if (numtracks) {
dprintf(fd, " of which %zu are active\n", numactive);
+ result.append(prefix);
RecordTrack::appendDumpHeader(result);
for (size_t i = 0; i < numtracks ; ++i) {
sp<RecordTrack> track = mTracks[i];
@@ -6946,8 +6987,8 @@
if (active) {
numactiveseen++;
}
- track->dump(buffer, SIZE, active);
- result.append(buffer);
+ result.append(prefix);
+ track->appendDump(result, active);
}
}
} else {
@@ -6955,15 +6996,15 @@
}
if (numactiveseen != numactive) {
- snprintf(buffer, SIZE, " The following tracks are in the active list but"
+ result.append(" The following tracks are in the active list but"
" not in the track list\n");
- result.append(buffer);
+ result.append(prefix);
RecordTrack::appendDumpHeader(result);
for (size_t i = 0; i < numactive; ++i) {
sp<RecordTrack> track = mActiveTracks[i];
if (mTracks.indexOf(track) < 0) {
- track->dump(buffer, SIZE, true);
- result.append(buffer);
+ result.append(prefix);
+ track->appendDump(result, true /* active */);
}
}
@@ -7221,6 +7262,7 @@
switch (event) {
case AUDIO_INPUT_OPENED:
+ case AUDIO_INPUT_REGISTERED:
case AUDIO_INPUT_CONFIG_CHANGED:
desc->mPatch = mPatch;
desc->mChannelMask = mChannelMask;
@@ -7482,34 +7524,22 @@
AudioFlinger::MmapThreadHandle::MmapThreadHandle(const sp<MmapThread>& thread)
: mThread(thread)
{
+ assert(thread != 0); // thread must start non-null and stay non-null
}
AudioFlinger::MmapThreadHandle::~MmapThreadHandle()
{
- MmapThread *thread = mThread.get();
- // clear our strong reference before disconnecting the thread: the last strong reference
- // will be removed when closeInput/closeOutput is executed upon call from audio policy manager
- // and the thread removed from mMMapThreads list causing the thread destruction.
- mThread.clear();
- if (thread != nullptr) {
- thread->disconnect();
- }
+ mThread->disconnect();
}
status_t AudioFlinger::MmapThreadHandle::createMmapBuffer(int32_t minSizeFrames,
struct audio_mmap_buffer_info *info)
{
- if (mThread == 0) {
- return NO_INIT;
- }
return mThread->createMmapBuffer(minSizeFrames, info);
}
status_t AudioFlinger::MmapThreadHandle::getMmapPosition(struct audio_mmap_position *position)
{
- if (mThread == 0) {
- return NO_INIT;
- }
return mThread->getMmapPosition(position);
}
@@ -7517,25 +7547,16 @@
audio_port_handle_t *handle)
{
- if (mThread == 0) {
- return NO_INIT;
- }
return mThread->start(client, handle);
}
status_t AudioFlinger::MmapThreadHandle::stop(audio_port_handle_t handle)
{
- if (mThread == 0) {
- return NO_INIT;
- }
return mThread->stop(handle);
}
status_t AudioFlinger::MmapThreadHandle::standby()
{
- if (mThread == 0) {
- return NO_INIT;
- }
return mThread->standby();
}
@@ -7545,7 +7566,10 @@
AudioHwDevice *hwDev, sp<StreamHalInterface> stream,
audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
: ThreadBase(audioFlinger, id, outDevice, inDevice, MMAP, systemReady),
- mHalStream(stream), mHalDevice(hwDev->hwDevice()), mAudioHwDev(hwDev)
+ mSessionId(AUDIO_SESSION_NONE),
+ mDeviceId(AUDIO_PORT_HANDLE_NONE), mPortId(AUDIO_PORT_HANDLE_NONE),
+ mHalStream(stream), mHalDevice(hwDev->hwDevice()), mAudioHwDev(hwDev),
+ mActiveTracks(&this->mLocalLog)
{
mStandby = true;
readHalParameters_l();
@@ -7566,7 +7590,7 @@
for (const sp<MmapTrack> &t : mActiveTracks) {
stop(t->portId());
}
- // this will cause the destruction of this thread.
+ // This will decrement references and may cause the destruction of this thread.
if (isOutput()) {
AudioSystem::releaseOutput(mId, streamType(), mSessionId);
} else {
@@ -7579,11 +7603,13 @@
audio_stream_type_t streamType __unused,
audio_session_t sessionId,
const sp<MmapStreamCallback>& callback,
+ audio_port_handle_t deviceId,
audio_port_handle_t portId)
{
mAttr = *attr;
mSessionId = sessionId;
mCallback = callback;
+ mDeviceId = deviceId;
mPortId = portId;
}
@@ -7628,6 +7654,10 @@
return NO_ERROR;
}
+ if (!isOutput() && !recordingAllowed(client.packageName, client.clientPid, client.clientUid)) {
+ return PERMISSION_DENIED;
+ }
+
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
audio_io_handle_t io = mId;
@@ -7639,7 +7669,7 @@
audio_stream_type_t stream = streamType();
audio_output_flags_t flags =
(audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
- audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_port_handle_t deviceId = mDeviceId;
ret = AudioSystem::getOutputForAttr(&mAttr, &io,
mSessionId,
&stream,
@@ -7653,7 +7683,7 @@
config.sample_rate = mSampleRate;
config.channel_mask = mChannelMask;
config.format = mFormat;
- audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_port_handle_t deviceId = mDeviceId;
ret = AudioSystem::getInputForAttr(&mAttr, &io,
mSessionId,
client.clientPid,
@@ -7693,7 +7723,7 @@
}
sp<MmapTrack> track = new MmapTrack(this, mSampleRate, mFormat, mChannelMask, mSessionId,
- client.clientUid, portId);
+ client.clientUid, client.clientPid, portId);
mActiveTracks.add(track);
sp<EffectChain> chain = getEffectChain_l(mSessionId);
@@ -7904,8 +7934,10 @@
switch (event) {
case AUDIO_INPUT_OPENED:
+ case AUDIO_INPUT_REGISTERED:
case AUDIO_INPUT_CONFIG_CHANGED:
case AUDIO_OUTPUT_OPENED:
+ case AUDIO_OUTPUT_REGISTERED:
case AUDIO_OUTPUT_CONFIG_CHANGED:
desc->mPatch = mPatch;
desc->mChannelMask = mChannelMask;
@@ -7990,17 +8022,19 @@
mPrevOutDevice = type;
sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
sp<MmapStreamCallback> callback = mCallback.promote();
- if (callback != 0) {
+ if (mDeviceId != deviceId && callback != 0) {
callback->onRoutingChanged(deviceId);
}
+ mDeviceId = deviceId;
}
if (!isOutput() && mPrevInDevice != mInDevice) {
mPrevInDevice = type;
sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
sp<MmapStreamCallback> callback = mCallback.promote();
- if (callback != 0) {
+ if (mDeviceId != deviceId && callback != 0) {
callback->onRoutingChanged(deviceId);
}
+ mDeviceId = deviceId;
}
return status;
}
@@ -8114,10 +8148,8 @@
void AudioFlinger::MmapThread::threadLoop_exit()
{
- sp<MmapStreamCallback> callback = mCallback.promote();
- if (callback != 0) {
- callback->onTearDown();
- }
+ // Do not call callback->onTearDown() because it is redundant for thread exit
+ // and because it can cause a recursive mutex lock on stop().
}
status_t AudioFlinger::MmapThread::setSyncEvent(const sp<SyncEvent>& event __unused)
@@ -8178,6 +8210,8 @@
dumpInternals(fd, args);
dumpTracks(fd, args);
dumpEffectChains(fd, args);
+ dprintf(fd, " Local log:\n");
+ mLocalLog.dump(fd, " " /* prefix */, 40 /* lines */);
}
void AudioFlinger::MmapThread::dumpInternals(int fd, const Vector<String16>& args)
@@ -8194,18 +8228,17 @@
void AudioFlinger::MmapThread::dumpTracks(int fd, const Vector<String16>& args __unused)
{
- const size_t SIZE = 256;
- char buffer[SIZE];
String8 result;
-
size_t numtracks = mActiveTracks.size();
- dprintf(fd, " %zu Tracks", numtracks);
+ dprintf(fd, " %zu Tracks\n", numtracks);
+ const char *prefix = " ";
if (numtracks) {
+ result.append(prefix);
MmapTrack::appendDumpHeader(result);
for (size_t i = 0; i < numtracks ; ++i) {
sp<MmapTrack> track = mActiveTracks[i];
- track->dump(buffer, SIZE);
- result.append(buffer);
+ result.append(prefix);
+ track->appendDump(result, true /* active */);
}
} else {
dprintf(fd, "\n");
@@ -8240,9 +8273,10 @@
audio_stream_type_t streamType,
audio_session_t sessionId,
const sp<MmapStreamCallback>& callback,
+ audio_port_handle_t deviceId,
audio_port_handle_t portId)
{
- MmapThread::configure(attr, streamType, sessionId, callback, portId);
+ MmapThread::configure(attr, streamType, sessionId, callback, deviceId, portId);
mStreamType = streamType;
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 062bad6..dd2b89b 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -508,9 +508,10 @@
template <typename T>
class ActiveTracks {
public:
- ActiveTracks()
+ explicit ActiveTracks(SimpleLog *localLog = nullptr)
: mActiveTracksGeneration(0)
, mLastActiveTracksGeneration(0)
+ , mLocalLog(localLog)
{ }
~ActiveTracks() {
@@ -562,6 +563,8 @@
void updatePowerState(sp<ThreadBase> thread, bool force = false);
private:
+ void logTrack(const char *funcName, const sp<T> &track) const;
+
SortedVector<uid_t> getWakeLockUids() {
SortedVector<uid_t> wakeLockUids;
for (const sp<T> &track : mActiveTracks) {
@@ -576,6 +579,7 @@
int mActiveTracksGeneration;
int mLastActiveTracksGeneration;
wp<T> mLatestActiveTrack; // latest track added to ActiveTracks
+ SimpleLog * const mLocalLog;
};
SimpleLog mLocalLog;
@@ -995,6 +999,9 @@
bool mHwSupportsPause;
bool mHwPaused;
bool mFlushPending;
+ // volumes last sent to audio HAL with stream->setVolume()
+ float mLeftVolFloat;
+ float mRightVolFloat;
};
class MixerThread : public PlaybackThread {
@@ -1112,9 +1119,6 @@
virtual void onAddNewTrack_l();
- // volumes last sent to audio HAL with stream->set_volume()
- float mLeftVolFloat;
- float mRightVolFloat;
bool mVolumeShaperActive;
DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
@@ -1475,6 +1479,7 @@
audio_stream_type_t streamType,
audio_session_t sessionId,
const sp<MmapStreamCallback>& callback,
+ audio_port_handle_t deviceId,
audio_port_handle_t portId);
void disconnect();
@@ -1536,6 +1541,7 @@
audio_attributes_t mAttr;
audio_session_t mSessionId;
+ audio_port_handle_t mDeviceId;
audio_port_handle_t mPortId;
wp<MmapStreamCallback> mCallback;
@@ -1558,6 +1564,7 @@
audio_stream_type_t streamType,
audio_session_t sessionId,
const sp<MmapStreamCallback>& callback,
+ audio_port_handle_t deviceId,
audio_port_handle_t portId);
AudioStreamOut* clearOutput();
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index cb540ca..d4ce0b4 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -61,6 +61,7 @@
audio_channel_mask_t channelMask,
size_t frameCount,
void *buffer,
+ size_t bufferSize,
audio_session_t sessionId,
uid_t uid,
bool isOut,
@@ -82,6 +83,7 @@
sp<IMemory> getBuffers() const { return mBufferMemory; }
void* buffer() const { return mBuffer; }
+ size_t bufferSize() const { return mBufferSize; }
virtual bool isFastTrack() const = 0;
bool isOutputTrack() const { return (mType == TYPE_OUTPUT); }
bool isPatchTrack() const { return (mType == TYPE_PATCH); }
@@ -133,6 +135,40 @@
mTerminated = true;
}
+ // Upper case characters are final states.
+ // Lower case characters are transitory.
+ const char *getTrackStateString() const {
+ if (isTerminated()) {
+ return "T ";
+ }
+ switch (mState) {
+ case IDLE:
+ return "I ";
+ case STOPPING_1: // for Fast and Offload
+ return "s1";
+ case STOPPING_2: // for Fast and Offload
+ return "s2";
+ case STOPPED:
+ return "S ";
+ case RESUMING:
+ return "r ";
+ case ACTIVE:
+ return "A ";
+ case PAUSING:
+ return "p ";
+ case PAUSED:
+ return "P ";
+ case FLUSHED:
+ return "F ";
+ case STARTING_1: // for RecordTrack
+ return "r1";
+ case STARTING_2: // for RecordTrack
+ return "r2";
+ default:
+ return "? ";
+ }
+ }
+
bool isOut() const { return mIsOut; }
// true for Track, false for RecordTrack,
// this could be a track type if needed later
@@ -144,6 +180,7 @@
sp<IMemory> mBufferMemory; // currently non-0 for fast RecordTrack only
void* mBuffer; // start of track buffer, typically in shared memory
// except for OutputTrack when it is in local memory
+ size_t mBufferSize; // size of mBuffer in bytes
// we don't really need a lock for these
track_state mState;
const uint32_t mSampleRate; // initial sample rate only; for tracks which
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 9763bf2..0f25153 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -50,10 +50,6 @@
#define ALOGVV(a...) do { } while(0)
#endif
-// TODO move to a common header (Also shared with AudioTrack.cpp)
-#define NANOS_PER_SECOND 1000000000
-#define TIME_TO_NANOS(time) ((uint64_t)(time).tv_sec * NANOS_PER_SECOND + (time).tv_nsec)
-
namespace android {
// ----------------------------------------------------------------------------
@@ -71,6 +67,7 @@
audio_channel_mask_t channelMask,
size_t frameCount,
void *buffer,
+ size_t bufferSize,
audio_session_t sessionId,
uid_t clientUid,
bool isOut,
@@ -81,7 +78,7 @@
mThread(thread),
mClient(client),
mCblk(NULL),
- // mBuffer
+ // mBuffer, mBufferSize
mState(IDLE),
mSampleRate(sampleRate),
mFormat(format),
@@ -113,15 +110,22 @@
// ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
- size_t bufferSize = buffer == NULL ? roundup(frameCount) : frameCount;
+ size_t minBufferSize = buffer == NULL ? roundup(frameCount) : frameCount;
// check overflow when computing bufferSize due to multiplication by mFrameSize.
- if (bufferSize < frameCount // roundup rounds down for values above UINT_MAX / 2
+ if (minBufferSize < frameCount // roundup rounds down for values above UINT_MAX / 2
|| mFrameSize == 0 // format needs to be correct
- || bufferSize > SIZE_MAX / mFrameSize) {
+ || minBufferSize > SIZE_MAX / mFrameSize) {
android_errorWriteLog(0x534e4554, "34749571");
return;
}
- bufferSize *= mFrameSize;
+ minBufferSize *= mFrameSize;
+
+ if (buffer == nullptr) {
+ bufferSize = minBufferSize; // allocated here.
+ } else if (minBufferSize > bufferSize) {
+ android_errorWriteLog(0x534e4554, "38340117");
+ return;
+ }
size_t size = sizeof(audio_track_cblk_t);
if (buffer == NULL && alloc == ALLOC_CBLK) {
@@ -177,6 +181,7 @@
// It should references the buffer via the pipe.
// Therefore, to detect incorrect usage of the buffer, we set mBuffer to NULL.
mBuffer = NULL;
+ bufferSize = 0;
break;
case ALLOC_CBLK:
// clear all buffers
@@ -196,7 +201,10 @@
case ALLOC_NONE:
mBuffer = buffer;
break;
+ default:
+ LOG_ALWAYS_FATAL("invalid allocation type: %d", (int)alloc);
}
+ mBufferSize = bufferSize;
#ifdef TEE_SINK
if (mTeeSinkTrackEnabled) {
@@ -368,6 +376,7 @@
audio_channel_mask_t channelMask,
size_t frameCount,
void *buffer,
+ size_t bufferSize,
const sp<IMemory>& sharedBuffer,
audio_session_t sessionId,
uid_t uid,
@@ -376,6 +385,7 @@
audio_port_handle_t portId)
: TrackBase(thread, client, sampleRate, format, channelMask, frameCount,
(sharedBuffer != 0) ? sharedBuffer->pointer() : buffer,
+ (sharedBuffer != 0) ? sharedBuffer->size() : bufferSize,
sessionId, uid, true /*isOut*/,
(type == TYPE_PATCH) ? ( buffer == NULL ? ALLOC_LOCAL : ALLOC_NONE) : ALLOC_CBLK,
type, portId),
@@ -411,21 +421,6 @@
mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount,
mFrameSize, !isExternalTrack(), sampleRate);
} else {
- // Is the shared buffer of sufficient size?
- // (frameCount * mFrameSize) is <= SIZE_MAX, checked in TrackBase.
- if (sharedBuffer->size() < frameCount * mFrameSize) {
- // Workaround: clear out mCblk to indicate track hasn't been properly created.
- mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
- if (mClient == 0) {
- free(mCblk);
- }
- mCblk = NULL;
-
- mSharedBuffer.clear(); // release shared buffer early
- android_errorWriteLog(0x534e4554, "38340117");
- return;
- }
-
mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
mFrameSize);
}
@@ -503,58 +498,40 @@
/*static*/ void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result)
{
- result.append(" Name Active Client Type Fmt Chn mask Session fCount S F SRate "
- "L dB R dB VS dB Server Main buf Aux buf Flags UndFrmCnt Flushed\n");
+ result.append("T Name Active Client Session S Flags "
+ " Format Chn mask SRate "
+ "ST L dB R dB VS dB "
+ " Server FrmCnt FrmRdy F Underruns Flushed "
+ "Main Buf Aux Buf\n");
}
-void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size, bool active)
+void AudioFlinger::PlaybackThread::Track::appendDump(String8& result, bool active)
{
- gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR();
- if (isFastTrack()) {
- sprintf(buffer, " F %2d", mFastIndex);
- } else if (mName >= AudioMixer::TRACK0) {
- sprintf(buffer, " %4d", mName - AudioMixer::TRACK0);
- } else {
- sprintf(buffer, " none");
- }
- track_state state = mState;
- char stateChar;
- if (isTerminated()) {
- stateChar = 'T';
- } else {
- switch (state) {
- case IDLE:
- stateChar = 'I';
- break;
- case STOPPING_1:
- stateChar = 's';
- break;
- case STOPPING_2:
- stateChar = '5';
- break;
- case STOPPED:
- stateChar = 'S';
- break;
- case RESUMING:
- stateChar = 'R';
- break;
- case ACTIVE:
- stateChar = 'A';
- break;
- case PAUSING:
- stateChar = 'p';
- break;
- case PAUSED:
- stateChar = 'P';
- break;
- case FLUSHED:
- stateChar = 'F';
- break;
- default:
- stateChar = '?';
- break;
+ char trackType;
+ switch (mType) {
+ case TYPE_DEFAULT:
+ case TYPE_OUTPUT:
+ if (mSharedBuffer.get() != nullptr) {
+ trackType = 'S'; // static
+ } else {
+ trackType = ' '; // normal
}
+ break;
+ case TYPE_PATCH:
+ trackType = 'P';
+ break;
+ default:
+ trackType = '?';
}
+
+ if (isFastTrack()) {
+ result.appendFormat("F%c %3d", trackType, mFastIndex);
+ } else if (mName >= AudioMixer::TRACK0) {
+ result.appendFormat("%c %4d", trackType, mName - AudioMixer::TRACK0);
+ } else {
+ result.appendFormat("%c none", trackType);
+ }
+
char nowInUnderrun;
switch (mObservedUnderruns.mBitFields.mMostRecent) {
case UNDERRUN_FULL:
@@ -571,31 +548,75 @@
break;
}
- std::pair<float /* volume */, bool /* active */> vsVolume = mVolumeHandler->getLastVolume();
- snprintf(&buffer[8], size - 8, " %6s %6u %4u %08X %08X %7u %6zu %1c %1d %5u "
- "%5.2g %5.2g %5.2g%c "
- "%08X %08zX %08zX 0x%03X %9u%c %7u\n",
+ char fillingStatus;
+ switch (mFillingUpStatus) {
+ case FS_INVALID:
+ fillingStatus = 'I';
+ break;
+ case FS_FILLING:
+ fillingStatus = 'f';
+ break;
+ case FS_FILLED:
+ fillingStatus = 'F';
+ break;
+ case FS_ACTIVE:
+ fillingStatus = 'A';
+ break;
+ default:
+ fillingStatus = '?';
+ break;
+ }
+
+ // clip framesReadySafe to max representation in dump
+ const size_t framesReadySafe =
+ std::min(mAudioTrackServerProxy->framesReadySafe(), (size_t)99999999);
+
+ // obtain volumes
+ const gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR();
+ const std::pair<float /* volume */, bool /* active */> vsVolume =
+ mVolumeHandler->getLastVolume();
+
+ // Our effective frame count is obtained by ServerProxy::getBufferSizeInFrames()
+ // as it may be reduced by the application.
+ const size_t bufferSizeInFrames = (size_t)mAudioTrackServerProxy->getBufferSizeInFrames();
+ // Check whether the buffer size has been modified by the app.
+ const char modifiedBufferChar = bufferSizeInFrames < mFrameCount
+ ? 'r' /* buffer reduced */: bufferSizeInFrames > mFrameCount
+ ? 'e' /* error */ : ' ' /* identical */;
+
+ result.appendFormat("%7s %6u %7u %2s 0x%03X "
+ "%08X %08X %6u "
+ "%2u %5.2g %5.2g %5.2g%c "
+ "%08X %6zu%c %6zu %c %9u%c %7u "
+ "%08zX %08zX\n",
active ? "yes" : "no",
(mClient == 0) ? getpid_cached : mClient->pid(),
- mStreamType,
+ mSessionId,
+ getTrackStateString(),
+ mCblk->mFlags,
+
mFormat,
mChannelMask,
- mSessionId,
- mFrameCount,
- stateChar,
- mFillingUpStatus,
mAudioTrackServerProxy->getSampleRate(),
+
+ mStreamType,
20.0 * log10(float_from_gain(gain_minifloat_unpack_left(vlr))),
20.0 * log10(float_from_gain(gain_minifloat_unpack_right(vlr))),
20.0 * log10(vsVolume.first), // VolumeShaper(s) total volume
vsVolume.second ? 'A' : ' ', // if any VolumeShapers active
+
mCblk->mServer,
- (size_t)mMainBuffer, // use %zX as %p appends 0x
- (size_t)mAuxBuffer, // use %zX as %p appends 0x
- mCblk->mFlags,
+ bufferSizeInFrames,
+ modifiedBufferChar,
+ framesReadySafe,
+ fillingStatus,
mAudioTrackServerProxy->getUnderrunFrames(),
nowInUnderrun,
- (unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000); // 7 digits
+ (unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000,
+
+ (size_t)mMainBuffer, // use %zX as %p appends 0x
+ (size_t)mAuxBuffer // use %zX as %p appends 0x
+ );
}
uint32_t AudioFlinger::PlaybackThread::Track::sampleRate() const {
@@ -1235,7 +1256,8 @@
uid_t uid)
: Track(playbackThread, NULL, AUDIO_STREAM_PATCH,
sampleRate, format, channelMask, frameCount,
- NULL, 0, AUDIO_SESSION_NONE, uid, AUDIO_OUTPUT_FLAG_NONE,
+ nullptr /* buffer */, (size_t)0 /* bufferSize */, nullptr /* sharedBuffer */,
+ AUDIO_SESSION_NONE, uid, AUDIO_OUTPUT_FLAG_NONE,
TYPE_OUTPUT),
mActive(false), mSourceThread(sourceThread)
{
@@ -1351,7 +1373,9 @@
if (mBufferQueue.size()) {
mBufferQueue.removeAt(0);
free(pInBuffer->mBuffer);
- delete pInBuffer;
+ if (pInBuffer != &inBuffer) {
+ delete pInBuffer;
+ }
ALOGV("OutputTrack::write() %p thread %p released overflow buffer %zu", this,
mThread.unsafe_get(), mBufferQueue.size());
} else {
@@ -1430,10 +1454,12 @@
audio_format_t format,
size_t frameCount,
void *buffer,
+ size_t bufferSize,
audio_output_flags_t flags)
: Track(playbackThread, NULL, streamType,
sampleRate, format, channelMask, frameCount,
- buffer, 0, AUDIO_SESSION_NONE, getuid(), flags, TYPE_PATCH),
+ buffer, bufferSize, nullptr /* sharedBuffer */,
+ AUDIO_SESSION_NONE, getuid(), flags, TYPE_PATCH),
mProxy(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true))
{
uint64_t mixBufferNs = ((uint64_t)2 * playbackThread->frameCount() * 1000000000) /
@@ -1567,13 +1593,14 @@
audio_channel_mask_t channelMask,
size_t frameCount,
void *buffer,
+ size_t bufferSize,
audio_session_t sessionId,
uid_t uid,
audio_input_flags_t flags,
track_type type,
audio_port_handle_t portId)
: TrackBase(thread, client, sampleRate, format,
- channelMask, frameCount, buffer, sessionId, uid, false /*isOut*/,
+ channelMask, frameCount, buffer, bufferSize, sessionId, uid, false /*isOut*/,
(type == TYPE_DEFAULT) ?
((flags & AUDIO_INPUT_FLAG_FAST) ? ALLOC_PIPE : ALLOC_CBLK) :
((buffer == NULL) ? ALLOC_LOCAL : ALLOC_NONE),
@@ -1701,22 +1728,28 @@
/*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result)
{
- result.append(" Active Client Fmt Chn mask Session S Server fCount SRate\n");
+ result.append("Active Client Session S Flags Format Chn mask SRate Server FrmCnt\n");
}
-void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size, bool active)
+void AudioFlinger::RecordThread::RecordTrack::appendDump(String8& result, bool active)
{
- snprintf(buffer, size, " %6s %6u %3u %08X %7u %1d %08X %6zu %5u\n",
+ result.appendFormat("%c%5s %6u %7u %2s 0x%03X "
+ "%08X %08X %6u "
+ "%08X %6zu\n",
+ isFastTrack() ? 'F' : ' ',
active ? "yes" : "no",
(mClient == 0) ? getpid_cached : mClient->pid(),
+ mSessionId,
+ getTrackStateString(),
+ mCblk->mFlags,
+
mFormat,
mChannelMask,
- mSessionId,
- mState,
- mCblk->mServer,
- mFrameCount,
- mSampleRate);
+ mSampleRate,
+ mCblk->mServer,
+ mFrameCount
+ );
}
void AudioFlinger::RecordThread::RecordTrack::handleSyncStartEvent(const sp<SyncEvent>& event)
@@ -1767,9 +1800,10 @@
audio_format_t format,
size_t frameCount,
void *buffer,
+ size_t bufferSize,
audio_input_flags_t flags)
: RecordTrack(recordThread, NULL, sampleRate, format, channelMask, frameCount,
- buffer, AUDIO_SESSION_NONE, getuid(), flags, TYPE_PATCH),
+ buffer, bufferSize, AUDIO_SESSION_NONE, getuid(), flags, TYPE_PATCH),
mProxy(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, false, true))
{
uint64_t mixBufferNs = ((uint64_t)2 * recordThread->frameCount() * 1000000000) /
@@ -1834,11 +1868,15 @@
audio_channel_mask_t channelMask,
audio_session_t sessionId,
uid_t uid,
+ pid_t pid,
audio_port_handle_t portId)
: TrackBase(thread, NULL, sampleRate, format,
- channelMask, 0, NULL, sessionId, uid, false,
+ channelMask, (size_t)0 /* frameCount */,
+ nullptr /* buffer */, (size_t)0 /* bufferSize */,
+ sessionId, uid, false /* isOut */,
ALLOC_NONE,
- TYPE_DEFAULT, portId)
+ TYPE_DEFAULT, portId),
+ mPid(pid)
{
}
@@ -1885,17 +1923,17 @@
/*static*/ void AudioFlinger::MmapThread::MmapTrack::appendDumpHeader(String8& result)
{
- result.append(" Client Fmt Chn mask SRate\n");
+ result.append("Client Session Format Chn mask SRate\n");
}
-void AudioFlinger::MmapThread::MmapTrack::dump(char* buffer, size_t size)
+void AudioFlinger::MmapThread::MmapTrack::appendDump(String8& result, bool active __unused)
{
- snprintf(buffer, size, " %6u %3u %08X %5u\n",
- mUid,
+ result.appendFormat("%6u %7u %08X %08X %6u\n",
+ mPid,
+ mSessionId,
mFormat,
mChannelMask,
mSampleRate);
-
}
} // namespace android
diff --git a/services/audioflinger/TypedLogger.h b/services/audioflinger/TypedLogger.h
index 2d84028..909af09 100644
--- a/services/audioflinger/TypedLogger.h
+++ b/services/audioflinger/TypedLogger.h
@@ -88,11 +88,11 @@
// Write histogram timestamp entry
#define LOG_HIST_TS() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
- x->logHistTS(hash(__FILE__, __LINE__)); } while(0)
+ x->logEventHistTs(NBLog::EVENT_HISTOGRAM_ENTRY_TS, hash(__FILE__, __LINE__)); } while(0)
-// flush all histogram
-#define LOG_HIST_FLUSH() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
- x->logHistFlush(hash(__FILE__, __LINE__)); } while(0)
+// Record that audio was turned on/off
+#define LOG_AUDIO_STATE() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+ x->logEventHistTs(NBLog::EVENT_AUDIO_STATE, hash(__FILE__, __LINE__)); } while(0)
namespace android {
extern "C" {
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index ad340e5..65571f9 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -24,7 +24,8 @@
libhardware_legacy \
libserviceutility \
libaudiopolicymanager \
- libmedia_helper
+ libmedia_helper \
+ libeffectsconfig
LOCAL_STATIC_LIBRARIES := \
libaudiopolicycomponents
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index c868206..7b19f58 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -349,8 +349,8 @@
virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
- virtual void onRecordingConfigurationUpdate(int event, audio_session_t session,
- audio_source_t source,
+ virtual void onRecordingConfigurationUpdate(int event,
+ const record_client_info_t *clientInfo,
const struct audio_config_base *clientConfig,
const struct audio_config_base *deviceConfig,
audio_patch_handle_t patchHandle) = 0;
diff --git a/services/audiopolicy/OWNERS b/services/audiopolicy/OWNERS
new file mode 100644
index 0000000..a8483fa
--- /dev/null
+++ b/services/audiopolicy/OWNERS
@@ -0,0 +1,3 @@
+jmtrivi@google.com
+krocard@google.com
+mnaganov@google.com
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
index 202b417..3a2a7ad 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -22,6 +22,7 @@
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <media/AudioPolicy.h>
+#include <media/IAudioPolicyServiceClient.h>
#include "AudioSessionInfoProvider.h"
namespace android {
@@ -45,14 +46,14 @@
status_t dump(int fd, int spaces, int index) const;
- audio_session_t session() const { return mSession; }
- audio_source_t inputSource()const { return mInputSource; }
+ audio_session_t session() const { return mRecordClientInfo.session; }
+ audio_source_t inputSource()const { return mRecordClientInfo.source; }
audio_format_t format() const { return mConfig.format; }
uint32_t sampleRate() const { return mConfig.sample_rate; }
audio_channel_mask_t channelMask() const { return mConfig.channel_mask; }
audio_input_flags_t flags() const { return mFlags; }
- uid_t uid() const { return mUid; }
- void setUid(uid_t uid) { mUid = uid; }
+ uid_t uid() const { return mRecordClientInfo.uid; }
+ void setUid(uid_t uid) { mRecordClientInfo.uid = uid; }
bool matches(const sp<AudioSession> &other) const;
bool isSoundTrigger() const { return mIsSoundTrigger; }
uint32_t openCount() const { return mOpenCount; } ;
@@ -66,11 +67,9 @@
virtual void onSessionInfoUpdate() const;
private:
- const audio_session_t mSession;
- const audio_source_t mInputSource;
+ record_client_info_t mRecordClientInfo;
const struct audio_config_base mConfig;
const audio_input_flags_t mFlags;
- uid_t mUid;
bool mIsSoundTrigger;
uint32_t mOpenCount;
uint32_t mActiveCount;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
index 2c45833..8c4733a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
@@ -39,9 +39,9 @@
bool isSoundTrigger,
const sp<AudioPolicyMix> &policyMix,
AudioPolicyClientInterface *clientInterface) :
- mSession(session), mInputSource(inputSource),
+ mRecordClientInfo({ .uid = uid, .session = session, .source = inputSource}),
mConfig({ .format = format, .sample_rate = sampleRate, .channel_mask = channelMask}),
- mFlags(flags), mUid(uid), mIsSoundTrigger(isSoundTrigger),
+ mFlags(flags), mIsSoundTrigger(isSoundTrigger),
mOpenCount(1), mActiveCount(0), mPolicyMix(policyMix), mClientInterface(clientInterface),
mInfoProvider(NULL)
{
@@ -94,7 +94,7 @@
const audio_patch_handle_t patchHandle = (provider != NULL) ? provider->getPatchHandle() :
AUDIO_PATCH_HANDLE_NONE;
if (patchHandle != AUDIO_PATCH_HANDLE_NONE) {
- mClientInterface->onRecordingConfigurationUpdate(event, mSession, mInputSource,
+ mClientInterface->onRecordingConfigurationUpdate(event, &mRecordClientInfo,
&mConfig, &deviceConfig, patchHandle);
}
}
@@ -104,13 +104,13 @@
bool AudioSession::matches(const sp<AudioSession> &other) const
{
- if (other->session() == mSession &&
- other->inputSource() == mInputSource &&
+ if (other->session() == mRecordClientInfo.session &&
+ other->inputSource() == mRecordClientInfo.source &&
other->format() == mConfig.format &&
other->sampleRate() == mConfig.sample_rate &&
other->channelMask() == mConfig.channel_mask &&
other->flags() == mFlags &&
- other->uid() == mUid) {
+ other->uid() == mRecordClientInfo.uid) {
return true;
}
return false;
@@ -132,8 +132,7 @@
AUDIO_PATCH_HANDLE_NONE;
if (patchHandle != AUDIO_PATCH_HANDLE_NONE) {
mClientInterface->onRecordingConfigurationUpdate(RECORD_CONFIG_EVENT_START,
- mSession, mInputSource,
- &mConfig, &deviceConfig, patchHandle);
+ &mRecordClientInfo, &mConfig, &deviceConfig, patchHandle);
}
}
}
@@ -146,11 +145,11 @@
snprintf(buffer, SIZE, "%*sAudio session %d:\n", spaces, "", index+1);
result.append(buffer);
- snprintf(buffer, SIZE, "%*s- session: %2d\n", spaces, "", mSession);
+ snprintf(buffer, SIZE, "%*s- session: %2d\n", spaces, "", mRecordClientInfo.session);
result.append(buffer);
- snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mUid);
+ snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mRecordClientInfo.uid);
result.append(buffer);
- snprintf(buffer, SIZE, "%*s- input source: %d\n", spaces, "", mInputSource);
+ snprintf(buffer, SIZE, "%*s- input source: %d\n", spaces, "", mRecordClientInfo.source);
result.append(buffer);
snprintf(buffer, SIZE, "%*s- format: %08x\n", spaces, "", mConfig.format);
result.append(buffer);
diff --git a/services/audiopolicy/config/primary_audio_policy_configuration.xml b/services/audiopolicy/config/primary_audio_policy_configuration.xml
index bf508ac..5b7ae7f 100644
--- a/services/audiopolicy/config/primary_audio_policy_configuration.xml
+++ b/services/audiopolicy/config/primary_audio_policy_configuration.xml
@@ -13,7 +13,7 @@
</mixPort>
<mixPort name="primary input" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
- samplingRates="8000, 16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
</mixPort>
</mixPorts>
<devicePorts>
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index b600940..ed7a23b 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1319,9 +1319,9 @@
// apply volume rules for current stream and device if necessary
checkAndSetVolume(stream,
- mVolumeCurves->getVolumeIndex(stream, device),
+ mVolumeCurves->getVolumeIndex(stream, outputDesc->device()),
outputDesc,
- device);
+ outputDesc->device());
// update the outputs if starting an output with a stream that can affect notification
// routing
@@ -1499,62 +1499,13 @@
"session %d, flags %#x",
attr->source, config->sample_rate, config->format, config->channel_mask, session, flags);
- // special case for mmap capture: if an input IO handle is specified, we reuse this input if
- // possible
- if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
- *input != AUDIO_IO_HANDLE_NONE) {
- ssize_t index = mInputs.indexOfKey(*input);
- if (index < 0) {
- ALOGW("getInputForAttr() unknown MMAP input %d", *input);
- return BAD_VALUE;
- }
- sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
- sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
- if (audioSession == 0) {
- ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
- return BAD_VALUE;
- }
- // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
- // The second call is for the first active client and sets the UID. Any further call
- // corresponds to a new client and is only permitted from the same UId.
- if (audioSession->openCount() == 1) {
- audioSession->setUid(uid);
- } else if (audioSession->uid() != uid) {
- ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
- uid, session, audioSession->uid());
- return INVALID_OPERATION;
- }
- audioSession->changeOpenCount(1);
- *inputType = API_INPUT_LEGACY;
- if (*portId == AUDIO_PORT_HANDLE_NONE) {
- *portId = AudioPort::getNextUniqueId();
- }
- DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
- *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
- : AUDIO_PORT_HANDLE_NONE;
- ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
- return NO_ERROR;
- }
-
- *input = AUDIO_IO_HANDLE_NONE;
- *inputType = API_INPUT_INVALID;
-
- audio_devices_t device;
+ status_t status = NO_ERROR;
// handle legacy remote submix case where the address was not always specified
String8 address = String8("");
- audio_source_t inputSource = attr->source;
audio_source_t halInputSource;
+ audio_source_t inputSource = attr->source;
sp<AudioPolicyMix> policyMix;
-
- if (inputSource == AUDIO_SOURCE_DEFAULT) {
- inputSource = AUDIO_SOURCE_MIC;
- }
- halInputSource = inputSource;
-
- // TODO: check for existing client for this port ID
- if (*portId == AUDIO_PORT_HANDLE_NONE) {
- *portId = AudioPort::getNextUniqueId();
- }
+ DeviceVector inputDevices;
// Explicit routing?
sp<DeviceDescriptor> deviceDesc;
@@ -1568,11 +1519,67 @@
}
mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid);
+ // special case for mmap capture: if an input IO handle is specified, we reuse this input if
+ // possible
+ if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
+ *input != AUDIO_IO_HANDLE_NONE) {
+ ssize_t index = mInputs.indexOfKey(*input);
+ if (index < 0) {
+ ALOGW("getInputForAttr() unknown MMAP input %d", *input);
+ status = BAD_VALUE;
+ goto error;
+ }
+ sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
+ sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
+ if (audioSession == 0) {
+ ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
+ status = BAD_VALUE;
+ goto error;
+ }
+ // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
+ // The second call is for the first active client and sets the UID. Any further call
+ // corresponds to a new client and is only permitted from the same UId.
+ if (audioSession->openCount() == 1) {
+ audioSession->setUid(uid);
+ } else if (audioSession->uid() != uid) {
+ ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
+ uid, session, audioSession->uid());
+ status = INVALID_OPERATION;
+ goto error;
+ }
+ audioSession->changeOpenCount(1);
+ *inputType = API_INPUT_LEGACY;
+ if (*portId == AUDIO_PORT_HANDLE_NONE) {
+ *portId = AudioPort::getNextUniqueId();
+ }
+ inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
+ *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
+ : AUDIO_PORT_HANDLE_NONE;
+ ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
+
+ return NO_ERROR;
+ }
+
+ *input = AUDIO_IO_HANDLE_NONE;
+ *inputType = API_INPUT_INVALID;
+
+ if (inputSource == AUDIO_SOURCE_DEFAULT) {
+ inputSource = AUDIO_SOURCE_MIC;
+ }
+ halInputSource = inputSource;
+
+ // TODO: check for existing client for this port ID
+ if (*portId == AUDIO_PORT_HANDLE_NONE) {
+ *portId = AudioPort::getNextUniqueId();
+ }
+
+ audio_devices_t device;
+
if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
- status_t ret = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
- if (ret != NO_ERROR) {
- return ret;
+ status = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
+ if (status != NO_ERROR) {
+ goto error;
}
*inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
@@ -1581,7 +1588,8 @@
device = getDeviceAndMixForInputSource(inputSource, &policyMix);
if (device == AUDIO_DEVICE_NONE) {
ALOGW("getInputForAttr() could not find device for source %d", inputSource);
- return BAD_VALUE;
+ status = BAD_VALUE;
+ goto error;
}
if (policyMix != NULL) {
address = policyMix->mDeviceAddress;
@@ -1610,11 +1618,11 @@
config->sample_rate, config->format, config->channel_mask, flags,
policyMix);
if (*input == AUDIO_IO_HANDLE_NONE) {
- mInputRoutes.removeRoute(session);
- return INVALID_OPERATION;
+ status = INVALID_OPERATION;
+ goto error;
}
- DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(device);
+ inputDevices = mAvailableInputDevices.getDevicesFromType(device);
*selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
: AUDIO_PORT_HANDLE_NONE;
@@ -1622,6 +1630,10 @@
*input, *inputType, *selectedDeviceId);
return NO_ERROR;
+
+error:
+ mInputRoutes.removeRoute(session);
+ return status;
}
@@ -4723,10 +4735,10 @@
// use device for strategy enforced audible
// 2: we are in call or the strategy phone is active on the output:
// use device for strategy phone
- // 3: the strategy for enforced audible is active but not enforced on the output:
- // use the device for strategy enforced audible
- // 4: the strategy sonification is active on the output:
+ // 3: the strategy sonification is active on the output:
// use device for strategy sonification
+ // 4: the strategy for enforced audible is active but not enforced on the output:
+ // use the device for strategy enforced audible
// 5: the strategy accessibility is active on the output:
// use device for strategy accessibility
// 6: the strategy "respectful" sonification is active on the output:
@@ -4743,10 +4755,10 @@
} else if (isInCall() ||
isStrategyActive(outputDesc, STRATEGY_PHONE)) {
device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
- } else if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE)) {
- device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
} else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION)) {
device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
+ } else if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE)) {
+ device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
} else if (isStrategyActive(outputDesc, STRATEGY_ACCESSIBILITY)) {
device = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, fromCache);
} else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION_RESPECTFUL)) {
@@ -4928,12 +4940,13 @@
// scan the whole RouteMap, for each entry, convert the stream type to a strategy
// (getStrategy(stream)).
// if the strategy from the stream type in the RouteMap is the same as the argument above,
- // and activity count is non-zero
- // the device = the device from the descriptor in the RouteMap, and exit.
+ // and activity count is non-zero and the device in the route descriptor is available
+ // then select this device.
for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) {
sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex);
routing_strategy routeStrategy = getStrategy(route->mStreamType);
- if ((routeStrategy == strategy) && route->isActive()) {
+ if ((routeStrategy == strategy) && route->isActive() &&
+ (mAvailableOutputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
return route->mDeviceDescriptor->type();
}
}
@@ -5328,9 +5341,15 @@
audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource)
{
+ // Routing
+ // Scan the whole RouteMap to see if we have an explicit route:
+ // if the input source in the RouteMap is the same as the argument above,
+ // and activity count is non-zero and the device in the route descriptor is available
+ // then select this device.
for (size_t routeIndex = 0; routeIndex < mInputRoutes.size(); routeIndex++) {
sp<SessionRoute> route = mInputRoutes.valueAt(routeIndex);
- if (inputSource == route->mSource && route->isActive()) {
+ if ((inputSource == route->mSource) && route->isActive() &&
+ (mAvailableInputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
return route->mDeviceDescriptor->type();
}
}
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index dbcc070..31c9575 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -220,11 +220,11 @@
}
void AudioPolicyService::AudioPolicyClient::onRecordingConfigurationUpdate(
- int event, audio_session_t session, audio_source_t source,
+ int event, const record_client_info_t *clientInfo,
const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
audio_patch_handle_t patchHandle)
{
- mAudioPolicyService->onRecordingConfigurationUpdate(event, session, source,
+ mAudioPolicyService->onRecordingConfigurationUpdate(event, clientInfo,
clientConfig, deviceConfig, patchHandle);
}
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 654465d..84b1073 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -20,8 +20,10 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <memory>
#include <cutils/misc.h>
#include <media/AudioEffect.h>
+#include <media/EffectsConfig.h>
#include <system/audio.h>
#include <system/audio_effects/audio_effects_conf.h>
#include <utils/Vector.h>
@@ -39,11 +41,17 @@
AudioPolicyEffects::AudioPolicyEffects()
{
- // load automatic audio effect modules
- if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
- loadAudioEffectConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
- } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
- loadAudioEffectConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
+ status_t loadResult = loadAudioEffectXmlConfig();
+ if (loadResult < 0) {
+ ALOGW("Failed to load XML effect configuration, fallback to .conf");
+ // load automatic audio effect modules
+ if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
+ loadAudioEffectConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
+ } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
+ loadAudioEffectConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
+ }
+ } else if (loadResult > 0) {
+ ALOGE("Effect config is partially invalid, skipped %d elements", loadResult);
}
}
@@ -685,6 +693,28 @@
return NO_ERROR;
}
+status_t AudioPolicyEffects::loadAudioEffectXmlConfig() {
+ auto result = effectsConfig::parse();
+ if (result.parsedConfig == nullptr) {
+ return -ENOENT;
+ }
+
+ auto loadProcessingChain = [](auto& processingChain, auto& streams) {
+ for (auto& stream : processingChain) {
+ auto effectDescs = std::make_unique<EffectDescVector>();
+ for (auto& effect : stream.effects) {
+ effectDescs->mEffects.add(
+ new EffectDesc{effect.get().name.c_str(), effect.get().uuid});
+ }
+ streams.add(stream.type, effectDescs.release());
+ }
+ };
+ loadProcessingChain(result.parsedConfig->preprocess, mInputSources);
+ loadProcessingChain(result.parsedConfig->postprocess, mOutputStreams);
+ // Casting from ssize_t to status_t is probably safe, there should not be more than 2^31 errors
+ return result.nbSkippedElement;
+}
+
status_t AudioPolicyEffects::loadAudioEffectConfig(const char *path)
{
cnode *root;
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index 0c74d87..59d5d14 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -155,7 +155,8 @@
audio_stream_type_t streamNameToEnum(const char *name);
// Parse audio_effects.conf
- status_t loadAudioEffectConfig(const char *path);
+ status_t loadAudioEffectConfig(const char *path); // TODO: add legacy in the name
+ status_t loadAudioEffectXmlConfig(); // TODO: remove "Xml" in the name
// Load all effects descriptors in configuration file
status_t loadEffects(cnode *root, Vector <EffectDesc *>& effects);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index f60030d..b7bce55 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -289,13 +289,6 @@
return BAD_VALUE;
}
- if ((attr->source == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) {
- return BAD_VALUE;
- }
- sp<AudioPolicyEffects>audioPolicyEffects;
- status_t status;
- AudioPolicyInterface::input_type_t inputType;
-
bool updatePid = (pid == -1);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!isTrustedCallingUid(callingUid)) {
@@ -313,7 +306,15 @@
pid = callingPid;
}
+ if ((attr->source == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed(pid, uid)) {
+ return BAD_VALUE;
+ }
+
+ sp<AudioPolicyEffects>audioPolicyEffects;
{
+ status_t status;
+ AudioPolicyInterface::input_type_t inputType;
+
Mutex::Autolock _l(mLock);
// the audio_in_acoustics_t parameter is ignored by get_input()
status = mAudioPolicyManager->getInputForAttr(attr, input, session, uid,
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index c4f6367..b417631 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -185,21 +185,21 @@
}
}
-void AudioPolicyService::onRecordingConfigurationUpdate(int event, audio_session_t session,
- audio_source_t source, const audio_config_base_t *clientConfig,
+void AudioPolicyService::onRecordingConfigurationUpdate(int event,
+ const record_client_info_t *clientInfo, const audio_config_base_t *clientConfig,
const audio_config_base_t *deviceConfig, audio_patch_handle_t patchHandle)
{
- mOutputCommandThread->recordingConfigurationUpdateCommand(event, session, source,
+ mOutputCommandThread->recordingConfigurationUpdateCommand(event, clientInfo,
clientConfig, deviceConfig, patchHandle);
}
-void AudioPolicyService::doOnRecordingConfigurationUpdate(int event, audio_session_t session,
- audio_source_t source, const audio_config_base_t *clientConfig,
+void AudioPolicyService::doOnRecordingConfigurationUpdate(int event,
+ const record_client_info_t *clientInfo, const audio_config_base_t *clientConfig,
const audio_config_base_t *deviceConfig, audio_patch_handle_t patchHandle)
{
Mutex::Autolock _l(mNotificationClientsLock);
for (size_t i = 0; i < mNotificationClients.size(); i++) {
- mNotificationClients.valueAt(i)->onRecordingConfigurationUpdate(event, session, source,
+ mNotificationClients.valueAt(i)->onRecordingConfigurationUpdate(event, clientInfo,
clientConfig, deviceConfig, patchHandle);
}
}
@@ -267,12 +267,12 @@
}
void AudioPolicyService::NotificationClient::onRecordingConfigurationUpdate(
- int event, audio_session_t session, audio_source_t source,
+ int event, const record_client_info_t *clientInfo,
const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
audio_patch_handle_t patchHandle)
{
if (mAudioPolicyServiceClient != 0) {
- mAudioPolicyServiceClient->onRecordingConfigurationUpdate(event, session, source,
+ mAudioPolicyServiceClient->onRecordingConfigurationUpdate(event, clientInfo,
clientConfig, deviceConfig, patchHandle);
}
}
@@ -544,8 +544,8 @@
break;
}
mLock.unlock();
- svc->doOnRecordingConfigurationUpdate(data->mEvent, data->mSession,
- data->mSource, &data->mClientConfig, &data->mDeviceConfig,
+ svc->doOnRecordingConfigurationUpdate(data->mEvent, &data->mClientInfo,
+ &data->mClientConfig, &data->mDeviceConfig,
data->mPatchHandle);
mLock.lock();
} break;
@@ -810,7 +810,7 @@
}
void AudioPolicyService::AudioCommandThread::recordingConfigurationUpdateCommand(
- int event, audio_session_t session, audio_source_t source,
+ int event, const record_client_info_t *clientInfo,
const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
audio_patch_handle_t patchHandle)
{
@@ -818,14 +818,13 @@
command->mCommand = RECORDING_CONFIGURATION_UPDATE;
RecordingConfigurationUpdateData *data = new RecordingConfigurationUpdateData();
data->mEvent = event;
- data->mSession = session;
- data->mSource = source;
+ data->mClientInfo = *clientInfo;
data->mClientConfig = *clientConfig;
data->mDeviceConfig = *deviceConfig;
data->mPatchHandle = patchHandle;
command->mParam = data;
- ALOGV("AudioCommandThread() adding recording configuration update event %d, source %d",
- event, source);
+ ALOGV("AudioCommandThread() adding recording configuration update event %d, source %d uid %u",
+ event, clientInfo->source, clientInfo->uid);
sendCommand(command);
}
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 35542f1..38d4b17 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -228,11 +228,11 @@
void onDynamicPolicyMixStateUpdate(const String8& regId, int32_t state);
void doOnDynamicPolicyMixStateUpdate(const String8& regId, int32_t state);
- void onRecordingConfigurationUpdate(int event, audio_session_t session,
- audio_source_t source, const audio_config_base_t *clientConfig,
+ void onRecordingConfigurationUpdate(int event, const record_client_info_t *clientInfo,
+ const audio_config_base_t *clientConfig,
const audio_config_base_t *deviceConfig, audio_patch_handle_t patchHandle);
- void doOnRecordingConfigurationUpdate(int event, audio_session_t session,
- audio_source_t source, const audio_config_base_t *clientConfig,
+ void doOnRecordingConfigurationUpdate(int event, const record_client_info_t *clientInfo,
+ const audio_config_base_t *clientConfig,
const audio_config_base_t *deviceConfig, audio_patch_handle_t patchHandle);
private:
@@ -306,8 +306,8 @@
int delayMs);
void dynamicPolicyMixStateUpdateCommand(const String8& regId, int32_t state);
void recordingConfigurationUpdateCommand(
- int event, audio_session_t session,
- audio_source_t source,
+ int event,
+ const record_client_info_t *clientInfo,
const audio_config_base_t *clientConfig,
const audio_config_base_t *deviceConfig,
audio_patch_handle_t patchHandle);
@@ -404,8 +404,7 @@
class RecordingConfigurationUpdateData : public AudioCommandData {
public:
int mEvent;
- audio_session_t mSession;
- audio_source_t mSource;
+ record_client_info_t mClientInfo;
struct audio_config_base mClientConfig;
struct audio_config_base mDeviceConfig;
audio_patch_handle_t mPatchHandle;
@@ -518,7 +517,7 @@
virtual void onAudioPatchListUpdate();
virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
virtual void onRecordingConfigurationUpdate(int event,
- audio_session_t session, audio_source_t source,
+ const record_client_info_t *clientInfo,
const audio_config_base_t *clientConfig,
const audio_config_base_t *deviceConfig, audio_patch_handle_t patchHandle);
@@ -540,8 +539,7 @@
void onAudioPatchListUpdate();
void onDynamicPolicyMixStateUpdate(const String8& regId, int32_t state);
void onRecordingConfigurationUpdate(
- int event, audio_session_t session,
- audio_source_t source,
+ int event, const record_client_info_t *clientInfo,
const audio_config_base_t *clientConfig,
const audio_config_base_t *deviceConfig,
audio_patch_handle_t patchHandle);
diff --git a/services/camera/OWNERS b/services/camera/OWNERS
new file mode 100644
index 0000000..18acfee
--- /dev/null
+++ b/services/camera/OWNERS
@@ -0,0 +1,6 @@
+cychen@google.com
+epeev@google.com
+etalvala@google.com
+shuzhenwang@google.com
+yinchiayeh@google.com
+zhijunhe@google.com
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index f1cdea3..7ec3ccb 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -77,7 +77,8 @@
android.hardware.camera.common@1.0 \
android.hardware.camera.provider@2.4 \
android.hardware.camera.device@1.0 \
- android.hardware.camera.device@3.2
+ android.hardware.camera.device@3.2 \
+ android.hardware.camera.device@3.3
LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client libfmq
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index a28518e..585d2eb 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -72,6 +72,20 @@
return initializeImpl(manager);
}
+bool Camera2Client::isZslEnabledInStillTemplate() {
+ bool zslEnabled = false;
+ CameraMetadata stillTemplate;
+ status_t res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_STILL_CAPTURE, &stillTemplate);
+ if (res == OK) {
+ camera_metadata_entry_t enableZsl = stillTemplate.find(ANDROID_CONTROL_ENABLE_ZSL);
+ if (enableZsl.count == 1) {
+ zslEnabled = (enableZsl.data.u8[0] == ANDROID_CONTROL_ENABLE_ZSL_TRUE);
+ }
+ }
+
+ return zslEnabled;
+}
+
template<typename TProviderPtr>
status_t Camera2Client::initializeImpl(TProviderPtr providerPtr)
{
@@ -93,6 +107,8 @@
__FUNCTION__, mCameraId, strerror(-res), res);
return NO_INIT;
}
+
+ l.mParameters.isDeviceZslSupported = isZslEnabledInStillTemplate();
}
String8 threadName;
@@ -843,6 +859,12 @@
outputStreams.push(getPreviewStreamId());
+ if (params.isDeviceZslSupported) {
+ // If device ZSL is supported, resume preview buffers that may be paused
+ // during last takePicture().
+ mDevice->dropStreamBuffers(false, getPreviewStreamId());
+ }
+
if (!params.recordingHint) {
if (!restart) {
res = mStreamingProcessor->updatePreviewRequest(params);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 72315d4..5af74eb 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -224,6 +224,8 @@
template<typename TProviderPtr>
status_t initializeImpl(TProviderPtr providerPtr);
+
+ bool isZslEnabledInStillTemplate();
};
}; // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
index 3f4017f..0d2dba1 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
@@ -121,18 +121,17 @@
if (mCallbackStreamId != NO_STREAM) {
// Check if stream parameters have to change
- uint32_t currentWidth, currentHeight, currentFormat;
- res = device->getStreamInfo(mCallbackStreamId,
- ¤tWidth, ¤tHeight, ¤tFormat, 0);
+ CameraDeviceBase::StreamInfo streamInfo;
+ res = device->getStreamInfo(mCallbackStreamId, &streamInfo);
if (res != OK) {
ALOGE("%s: Camera %d: Error querying callback output stream info: "
"%s (%d)", __FUNCTION__, mId,
strerror(-res), res);
return res;
}
- if (currentWidth != (uint32_t)params.previewWidth ||
- currentHeight != (uint32_t)params.previewHeight ||
- currentFormat != (uint32_t)callbackFormat) {
+ if (streamInfo.width != (uint32_t)params.previewWidth ||
+ streamInfo.height != (uint32_t)params.previewHeight ||
+ !streamInfo.matchFormat((uint32_t)callbackFormat)) {
// Since size should only change while preview is not running,
// assuming that all existing use of old callback stream is
// completed.
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index b65f1c7..1ee216f 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -553,6 +553,12 @@
return DONE;
}
+ if (l.mParameters.isDeviceZslSupported) {
+ // If device ZSL is supported, drop all pending preview buffers to reduce the chance of
+ // rendering preview frames newer than the still frame.
+ client->getCameraDevice()->dropStreamBuffers(true, client->getPreviewStreamId());
+ }
+
/**
* Clear the streaming request for still-capture pictures
* (as opposed to i.e. video snapshots)
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index d6d8dde..d8b7af2 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -136,17 +136,16 @@
if (mCaptureStreamId != NO_STREAM) {
// Check if stream parameters have to change
- uint32_t currentWidth, currentHeight;
- res = device->getStreamInfo(mCaptureStreamId,
- ¤tWidth, ¤tHeight, 0, 0);
+ CameraDeviceBase::StreamInfo streamInfo;
+ res = device->getStreamInfo(mCaptureStreamId, &streamInfo);
if (res != OK) {
ALOGE("%s: Camera %d: Error querying capture output stream info: "
"%s (%d)", __FUNCTION__,
mId, strerror(-res), res);
return res;
}
- if (currentWidth != (uint32_t)params.pictureWidth ||
- currentHeight != (uint32_t)params.pictureHeight) {
+ if (streamInfo.width != (uint32_t)params.pictureWidth ||
+ streamInfo.height != (uint32_t)params.pictureHeight) {
ALOGV("%s: Camera %d: Deleting stream %d since the buffer dimensions changed",
__FUNCTION__, mId, mCaptureStreamId);
res = device->deleteStream(mCaptureStreamId);
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index a305bc7..6fb5c21 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -954,7 +954,8 @@
}
}
- if (slowJpegMode || property_get_bool("camera.disable_zsl_mode", false)) {
+ if (isDeviceZslSupported || slowJpegMode ||
+ property_get_bool("camera.disable_zsl_mode", false)) {
ALOGI("Camera %d: Disabling ZSL mode", cameraId);
allowZslMode = false;
} else {
@@ -1997,7 +1998,8 @@
if (previewFpsRange[1] > 1e9/minFrameDurationNs + FPS_MARGIN) {
slowJpegMode = true;
}
- if (slowJpegMode || property_get_bool("camera.disable_zsl_mode", false)) {
+ if (isDeviceZslSupported || slowJpegMode ||
+ property_get_bool("camera.disable_zsl_mode", false)) {
allowZslMode = false;
} else {
allowZslMode = isZslReprocessPresent;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index bea867a..17e3d75 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -175,6 +175,8 @@
bool slowJpegMode;
// Whether ZSL reprocess is supported by the device.
bool isZslReprocessPresent;
+ // Whether the device supports enableZsl.
+ bool isDeviceZslSupported;
// Overall camera state
enum State {
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index d79e430..73dca73 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -161,18 +161,17 @@
if (mPreviewStreamId != NO_STREAM) {
// Check if stream parameters have to change
- uint32_t currentWidth, currentHeight;
- res = device->getStreamInfo(mPreviewStreamId,
- ¤tWidth, ¤tHeight, 0, 0);
+ CameraDeviceBase::StreamInfo streamInfo;
+ res = device->getStreamInfo(mPreviewStreamId, &streamInfo);
if (res != OK) {
ALOGE("%s: Camera %d: Error querying preview stream info: "
"%s (%d)", __FUNCTION__, mId, strerror(-res), res);
return res;
}
- if (currentWidth != (uint32_t)params.previewWidth ||
- currentHeight != (uint32_t)params.previewHeight) {
+ if (streamInfo.width != (uint32_t)params.previewWidth ||
+ streamInfo.height != (uint32_t)params.previewHeight) {
ALOGV("%s: Camera %d: Preview size switch: %d x %d -> %d x %d",
- __FUNCTION__, mId, currentWidth, currentHeight,
+ __FUNCTION__, mId, streamInfo.width, streamInfo.height,
params.previewWidth, params.previewHeight);
res = device->waitUntilDrained();
if (res != OK) {
@@ -312,10 +311,8 @@
return INVALID_OPERATION;
}
- uint32_t currentWidth, currentHeight, currentFormat;
- android_dataspace currentDataSpace;
- res = device->getStreamInfo(mRecordingStreamId,
- ¤tWidth, ¤tHeight, ¤tFormat, ¤tDataSpace);
+ CameraDeviceBase::StreamInfo streamInfo;
+ res = device->getStreamInfo(mRecordingStreamId, &streamInfo);
if (res != OK) {
ALOGE("%s: Camera %d: Error querying recording output stream info: "
"%s (%d)", __FUNCTION__, mId,
@@ -324,10 +321,10 @@
}
if (mRecordingWindow == nullptr ||
- currentWidth != (uint32_t)params.videoWidth ||
- currentHeight != (uint32_t)params.videoHeight ||
- currentFormat != (uint32_t)params.videoFormat ||
- currentDataSpace != params.videoDataSpace) {
+ streamInfo.width != (uint32_t)params.videoWidth ||
+ streamInfo.height != (uint32_t)params.videoHeight ||
+ !streamInfo.matchFormat((uint32_t)params.videoFormat) ||
+ !streamInfo.matchDataSpace(params.videoDataSpace)) {
*needsUpdate = true;
return res;
}
@@ -348,22 +345,18 @@
if (mRecordingStreamId != NO_STREAM) {
// Check if stream parameters have to change
- uint32_t currentWidth, currentHeight;
- uint32_t currentFormat;
- android_dataspace currentDataSpace;
- res = device->getStreamInfo(mRecordingStreamId,
- ¤tWidth, ¤tHeight,
- ¤tFormat, ¤tDataSpace);
+ CameraDeviceBase::StreamInfo streamInfo;
+ res = device->getStreamInfo(mRecordingStreamId, &streamInfo);
if (res != OK) {
ALOGE("%s: Camera %d: Error querying recording output stream info: "
"%s (%d)", __FUNCTION__, mId,
strerror(-res), res);
return res;
}
- if (currentWidth != (uint32_t)params.videoWidth ||
- currentHeight != (uint32_t)params.videoHeight ||
- currentFormat != (uint32_t)params.videoFormat ||
- currentDataSpace != params.videoDataSpace) {
+ if (streamInfo.width != (uint32_t)params.videoWidth ||
+ streamInfo.height != (uint32_t)params.videoHeight ||
+ !streamInfo.matchFormat((uint32_t)params.videoFormat) ||
+ !streamInfo.matchDataSpace(params.videoDataSpace)) {
// TODO: Should wait to be sure previous recording has finished
res = device->deleteStream(mRecordingStreamId);
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 9bc31b9..b0607fb 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -233,17 +233,16 @@
if ((mZslStreamId != NO_STREAM) || (mInputStreamId != NO_STREAM)) {
// Check if stream parameters have to change
- uint32_t currentWidth, currentHeight;
- res = device->getStreamInfo(mZslStreamId,
- ¤tWidth, ¤tHeight, 0, 0);
+ CameraDeviceBase::StreamInfo streamInfo;
+ res = device->getStreamInfo(mZslStreamId, &streamInfo);
if (res != OK) {
ALOGE("%s: Camera %d: Error querying capture output stream info: "
"%s (%d)", __FUNCTION__,
client->getCameraId(), strerror(-res), res);
return res;
}
- if (currentWidth != (uint32_t)params.fastInfo.arrayWidth ||
- currentHeight != (uint32_t)params.fastInfo.arrayHeight) {
+ if (streamInfo.width != (uint32_t)params.fastInfo.arrayWidth ||
+ streamInfo.height != (uint32_t)params.fastInfo.arrayHeight) {
if (mZslStreamId != NO_STREAM) {
ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
"dimensions changed",
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 0429e7f..c03e8a2 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -313,11 +313,13 @@
binder::Status CameraDeviceClient::beginConfigure() {
// TODO: Implement this.
+ ATRACE_CALL();
ALOGV("%s: Not implemented yet.", __FUNCTION__);
return binder::Status::ok();
}
binder::Status CameraDeviceClient::endConfigure(int operatingMode) {
+ ATRACE_CALL();
ALOGV("%s: ending configure (%d input stream, %zu output surfaces)",
__FUNCTION__, mInputStream.configured ? 1 : 0,
mStreamMap.size());
@@ -568,7 +570,7 @@
/*out*/
int* newStreamId) {
int width, height, format, surfaceType;
- int32_t consumerUsage;
+ uint64_t consumerUsage;
android_dataspace dataSpace;
status_t err;
binder::Status res;
@@ -764,24 +766,23 @@
// Query consumer usage bits to set async operation mode for
// GLConsumer using controlledByApp parameter.
bool useAsync = false;
- int32_t consumerUsage;
+ uint64_t consumerUsage = 0;
status_t err;
- if ((err = gbp->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS,
- &consumerUsage)) != OK) {
+ if ((err = gbp->getConsumerUsage(&consumerUsage)) != OK) {
String8 msg = String8::format("Camera %s: Failed to query Surface consumer usage: %s (%d)",
mCameraIdStr.string(), strerror(-err), err);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
- ALOGW("%s: Camera %s with consumer usage flag: 0x%x: Forcing asynchronous mode for stream",
+ ALOGW("%s: Camera %s with consumer usage flag: %" PRIu64 ": Forcing asynchronous mode for stream",
__FUNCTION__, mCameraIdStr.string(), consumerUsage);
useAsync = true;
}
- int32_t disallowedFlags = GraphicBuffer::USAGE_HW_VIDEO_ENCODER |
+ uint64_t disallowedFlags = GraphicBuffer::USAGE_HW_VIDEO_ENCODER |
GRALLOC_USAGE_RENDERSCRIPT;
- int32_t allowedFlags = GraphicBuffer::USAGE_SW_READ_MASK |
+ uint64_t allowedFlags = GraphicBuffer::USAGE_SW_READ_MASK |
GraphicBuffer::USAGE_HW_TEXTURE |
GraphicBuffer::USAGE_HW_COMPOSER;
bool flexibleConsumer = (consumerUsage & disallowedFlags) == 0 &&
@@ -874,7 +875,7 @@
//surface class type. Use usage flag to approximate the comparison.
if (consumerUsage != streamInfo.consumerUsage) {
String8 msg = String8::format(
- "Camera %s:Surface usage flag doesn't match 0x%x vs 0x%x",
+ "Camera %s:Surface usage flag doesn't match %" PRIu64 " vs %" PRIu64 "",
mCameraIdStr.string(), consumerUsage, streamInfo.consumerUsage);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
@@ -1353,7 +1354,7 @@
sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
if (remoteCb != 0) {
- remoteCb->onRepeatingRequestError(lastFrameNumber);
+ remoteCb->onRepeatingRequestError(lastFrameNumber, mStreamingRequestId);
}
Mutex::Autolock idLock(mStreamingRequestIdLock);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index e8fc080..50661cb 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -213,13 +213,13 @@
int height;
int format;
android_dataspace dataSpace;
- int32_t consumerUsage;
+ uint64_t consumerUsage;
bool finalized = false;
OutputStreamInfo() :
width(-1), height(-1), format(-1), dataSpace(HAL_DATASPACE_UNKNOWN),
consumerUsage(0) {}
OutputStreamInfo(int _width, int _height, int _format, android_dataspace _dataSpace,
- int32_t _consumerUsage) :
+ uint64_t _consumerUsage) :
width(_width), height(_height), format(_format),
dataSpace(_dataSpace), consumerUsage(_consumerUsage) {}
};
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index d9059f3..a90050e 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -119,7 +119,7 @@
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
- bool isShared = false, uint32_t consumerUsage = 0) = 0;
+ bool isShared = false, uint64_t consumerUsage = 0) = 0;
/**
* Create an output stream of the requested size, format, rotation and
@@ -132,7 +132,7 @@
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
- bool isShared = false, uint32_t consumerUsage = 0) = 0;
+ bool isShared = false, uint64_t consumerUsage = 0) = 0;
/**
* Create an input stream of width, height, and format.
@@ -142,12 +142,51 @@
virtual status_t createInputStream(uint32_t width, uint32_t height,
int32_t format, /*out*/ int32_t *id) = 0;
+ struct StreamInfo {
+ uint32_t width;
+ uint32_t height;
+
+ uint32_t format;
+ bool formatOverridden;
+ uint32_t originalFormat;
+
+ android_dataspace dataSpace;
+ bool dataSpaceOverridden;
+ android_dataspace originalDataSpace;
+
+ StreamInfo() : width(0), height(0), format(0), formatOverridden(false), originalFormat(0),
+ dataSpace(HAL_DATASPACE_UNKNOWN), dataSpaceOverridden(false),
+ originalDataSpace(HAL_DATASPACE_UNKNOWN) {}
+ /**
+ * Check whether the format matches the current or the original one in case
+ * it got overridden.
+ */
+ bool matchFormat(uint32_t clientFormat) const {
+ if ((formatOverridden && (originalFormat == clientFormat)) ||
+ (format == clientFormat)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Check whether the dataspace matches the current or the original one in case
+ * it got overridden.
+ */
+ bool matchDataSpace(android_dataspace clientDataSpace) const {
+ if ((dataSpaceOverridden && (originalDataSpace == clientDataSpace)) ||
+ (dataSpace == clientDataSpace)) {
+ return true;
+ }
+ return false;
+ }
+
+ };
+
/**
* Get information about a given stream.
*/
- virtual status_t getStreamInfo(int id,
- uint32_t *width, uint32_t *height,
- uint32_t *format, android_dataspace *dataSpace) = 0;
+ virtual status_t getStreamInfo(int id, StreamInfo *streamInfo) = 0;
/**
* Set stream gralloc buffer transform
@@ -310,6 +349,11 @@
virtual status_t setConsumerSurfaces(int streamId,
const std::vector<sp<Surface>>& consumers) = 0;
+ /**
+ * Drop buffers for stream of streamId if dropping is true. If dropping is false, do not
+ * drop buffers for stream of streamId.
+ */
+ virtual status_t dropStreamBuffers(bool /*dropping*/, int /*streamId*/) = 0;
};
}; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 5addaf1..e6a6a21 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -202,12 +202,17 @@
for (auto& provider : mProviders) {
auto deviceInfo = findDeviceInfoLocked(id);
if (deviceInfo != nullptr) {
- provider->mInterface->isSetTorchModeSupported(
+ auto ret = provider->mInterface->isSetTorchModeSupported(
[&support](auto status, bool supported) {
if (status == Status::OK) {
support = supported;
}
});
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error checking torch mode support '%s': %s",
+ __FUNCTION__, provider->mProviderName.c_str(), ret.description().c_str());
+ }
+ break;
}
}
return support;
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
index 469c86c..522d521 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
@@ -29,11 +29,6 @@
CameraHardwareInterface::~CameraHardwareInterface()
{
ALOGI("Destroying camera %s", mName.string());
- if (mDevice) {
- int rc = mDevice->common.close(&mDevice->common);
- if (rc != OK)
- ALOGE("Could not close camera %s: %d", mName.string(), rc);
- }
if (mHidlDevice != nullptr) {
mHidlDevice->close();
mHidlDevice.clear();
@@ -42,12 +37,6 @@
}
status_t CameraHardwareInterface::initialize(sp<CameraProviderManager> manager) {
- if (mDevice) {
- ALOGE("%s: camera hardware interface has been initialized to libhardware path!",
- __FUNCTION__);
- return INVALID_OPERATION;
- }
-
ALOGI("Opening camera %s", mName.string());
status_t ret = manager->openSession(mName.string(), this, &mHidlDevice);
@@ -108,58 +97,78 @@
ALOGE("%s: CameraHeapMemory has FD %d (expect >= 0)", __FUNCTION__, memPoolId);
return 0;
}
+ std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
mHidlMemPoolMap.insert(std::make_pair(memPoolId, mem));
return memPoolId;
}
hardware::Return<void> CameraHardwareInterface::unregisterMemory(uint32_t memId) {
- if (mHidlMemPoolMap.count(memId) == 0) {
- ALOGE("%s: memory pool ID %d not found", __FUNCTION__, memId);
- return hardware::Void();
+ camera_memory_t* mem = nullptr;
+ {
+ std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+ if (mHidlMemPoolMap.count(memId) == 0) {
+ ALOGE("%s: memory pool ID %d not found", __FUNCTION__, memId);
+ return hardware::Void();
+ }
+ mem = mHidlMemPoolMap.at(memId);
+ mHidlMemPoolMap.erase(memId);
}
- camera_memory_t* mem = mHidlMemPoolMap.at(memId);
sPutMemory(mem);
- mHidlMemPoolMap.erase(memId);
return hardware::Void();
}
hardware::Return<void> CameraHardwareInterface::dataCallback(
DataCallbackMsg msgType, uint32_t data, uint32_t bufferIndex,
const hardware::camera::device::V1_0::CameraFrameMetadata& metadata) {
- if (mHidlMemPoolMap.count(data) == 0) {
- ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
- return hardware::Void();
+ camera_memory_t* mem = nullptr;
+ {
+ std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+ if (mHidlMemPoolMap.count(data) == 0) {
+ ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
+ return hardware::Void();
+ }
+ mem = mHidlMemPoolMap.at(data);
}
camera_frame_metadata_t md;
md.number_of_faces = metadata.faces.size();
md.faces = (camera_face_t*) metadata.faces.data();
- sDataCb((int32_t) msgType, mHidlMemPoolMap.at(data), bufferIndex, &md, this);
+ sDataCb((int32_t) msgType, mem, bufferIndex, &md, this);
return hardware::Void();
}
hardware::Return<void> CameraHardwareInterface::dataCallbackTimestamp(
DataCallbackMsg msgType, uint32_t data,
uint32_t bufferIndex, int64_t timestamp) {
- if (mHidlMemPoolMap.count(data) == 0) {
- ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
- return hardware::Void();
+ camera_memory_t* mem = nullptr;
+ {
+ std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+ if (mHidlMemPoolMap.count(data) == 0) {
+ ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
+ return hardware::Void();
+ }
+ mem = mHidlMemPoolMap.at(data);
}
- sDataCbTimestamp(timestamp, (int32_t) msgType, mHidlMemPoolMap.at(data), bufferIndex, this);
+ sDataCbTimestamp(timestamp, (int32_t) msgType, mem, bufferIndex, this);
return hardware::Void();
}
hardware::Return<void> CameraHardwareInterface::handleCallbackTimestamp(
DataCallbackMsg msgType, const hidl_handle& frameData, uint32_t data,
uint32_t bufferIndex, int64_t timestamp) {
- if (mHidlMemPoolMap.count(data) == 0) {
- ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
- return hardware::Void();
+ camera_memory_t* mem = nullptr;
+ {
+ std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+ if (mHidlMemPoolMap.count(data) == 0) {
+ ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
+ return hardware::Void();
+ }
+ mem = mHidlMemPoolMap.at(data);
}
- sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(mHidlMemPoolMap.at(data)->handle));
+ sp<CameraHeapMemory> heapMem(static_cast<CameraHeapMemory *>(mem->handle));
VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
- mem->mBuffers[bufferIndex]->pointer();
+ heapMem->mBuffers[bufferIndex]->pointer();
md->pHandle = const_cast<native_handle_t*>(frameData.getNativeHandle());
- sDataCbTimestamp(timestamp, (int32_t) msgType, mHidlMemPoolMap.at(data), bufferIndex, this);
+ sDataCbTimestamp(timestamp, (int32_t) msgType, mem, bufferIndex, this);
return hardware::Void();
}
@@ -168,27 +177,28 @@
const hardware::hidl_vec<hardware::camera::device::V1_0::HandleTimestampMessage>& messages) {
std::vector<android::HandleTimestampMessage> msgs;
msgs.reserve(messages.size());
+ {
+ std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+ for (const auto& hidl_msg : messages) {
+ if (mHidlMemPoolMap.count(hidl_msg.data) == 0) {
+ ALOGE("%s: memory pool ID %d not found", __FUNCTION__, hidl_msg.data);
+ return hardware::Void();
+ }
+ sp<CameraHeapMemory> mem(
+ static_cast<CameraHeapMemory *>(mHidlMemPoolMap.at(hidl_msg.data)->handle));
- for (const auto& hidl_msg : messages) {
- if (mHidlMemPoolMap.count(hidl_msg.data) == 0) {
- ALOGE("%s: memory pool ID %d not found", __FUNCTION__, hidl_msg.data);
- return hardware::Void();
+ if (hidl_msg.bufferIndex >= mem->mNumBufs) {
+ ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
+ hidl_msg.bufferIndex, mem->mNumBufs);
+ return hardware::Void();
+ }
+ VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
+ mem->mBuffers[hidl_msg.bufferIndex]->pointer();
+ md->pHandle = const_cast<native_handle_t*>(hidl_msg.frameData.getNativeHandle());
+
+ msgs.push_back({hidl_msg.timestamp, mem->mBuffers[hidl_msg.bufferIndex]});
}
- sp<CameraHeapMemory> mem(
- static_cast<CameraHeapMemory *>(mHidlMemPoolMap.at(hidl_msg.data)->handle));
-
- if (hidl_msg.bufferIndex >= mem->mNumBufs) {
- ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
- hidl_msg.bufferIndex, mem->mNumBufs);
- return hardware::Void();
- }
- VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
- mem->mBuffers[hidl_msg.bufferIndex]->pointer();
- md->pHandle = const_cast<native_handle_t*>(hidl_msg.frameData.getNativeHandle());
-
- msgs.push_back({hidl_msg.timestamp, mem->mBuffers[hidl_msg.bufferIndex]});
}
-
mDataCbTimestampBatch((int32_t) msgType, msgs, mCbUser);
return hardware::Void();
}
@@ -372,7 +382,7 @@
ALOGE("%s: preview window is null", __FUNCTION__);
return s;
}
- mPreviewUsage = (int) usage;
+ mPreviewUsage = static_cast<uint64_t> (usage);
int rc = native_window_set_usage(a, mPreviewUsage);
if (rc == OK) {
cleanupCirculatingBuffers();
@@ -444,23 +454,6 @@
}
return CameraProviderManager::mapToStatusT(
mHidlDevice->setPreviewWindow(buf.get() ? this : nullptr));
- } else if (mDevice) {
- if (mDevice->ops->set_preview_window) {
- mPreviewWindow = buf;
- if (buf != nullptr) {
- if (mPreviewScalingMode != NOT_SET) {
- setPreviewScalingMode(mPreviewScalingMode);
- }
- if (mPreviewTransform != NOT_SET) {
- setPreviewTransform(mPreviewTransform);
- }
- }
- mHalPreviewWindow.user = this;
- ALOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p",__FUNCTION__,
- &mHalPreviewWindow, mHalPreviewWindow.user);
- return mDevice->ops->set_preview_window(mDevice,
- buf.get() ? &mHalPreviewWindow.nw : 0);
- }
}
return INVALID_OPERATION;
}
@@ -478,15 +471,6 @@
mCbUser = user;
ALOGV("%s(%s)", __FUNCTION__, mName.string());
-
- if (mDevice && mDevice->ops->set_callbacks) {
- mDevice->ops->set_callbacks(mDevice,
- sNotifyCb,
- sDataCb,
- sDataCbTimestamp,
- sGetMemory,
- this);
- }
}
void CameraHardwareInterface::enableMsgType(int32_t msgType)
@@ -494,8 +478,6 @@
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (CC_LIKELY(mHidlDevice != nullptr)) {
mHidlDevice->enableMsgType(msgType);
- } else if (mDevice && mDevice->ops->enable_msg_type) {
- mDevice->ops->enable_msg_type(mDevice, msgType);
}
}
@@ -504,8 +486,6 @@
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (CC_LIKELY(mHidlDevice != nullptr)) {
mHidlDevice->disableMsgType(msgType);
- } else if (mDevice && mDevice->ops->disable_msg_type) {
- mDevice->ops->disable_msg_type(mDevice, msgType);
}
}
@@ -514,8 +494,6 @@
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (CC_LIKELY(mHidlDevice != nullptr)) {
return mHidlDevice->msgTypeEnabled(msgType);
- } else if (mDevice && mDevice->ops->msg_type_enabled) {
- return mDevice->ops->msg_type_enabled(mDevice, msgType);
}
return false;
}
@@ -526,8 +504,6 @@
if (CC_LIKELY(mHidlDevice != nullptr)) {
return CameraProviderManager::mapToStatusT(
mHidlDevice->startPreview());
- } else if (mDevice && mDevice->ops->start_preview) {
- return mDevice->ops->start_preview(mDevice);
}
return INVALID_OPERATION;
}
@@ -537,8 +513,6 @@
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (CC_LIKELY(mHidlDevice != nullptr)) {
mHidlDevice->stopPreview();
- } else if (mDevice && mDevice->ops->stop_preview) {
- mDevice->ops->stop_preview(mDevice);
}
}
@@ -547,8 +521,6 @@
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (CC_LIKELY(mHidlDevice != nullptr)) {
return mHidlDevice->previewEnabled();
- } else if (mDevice && mDevice->ops->preview_enabled) {
- return mDevice->ops->preview_enabled(mDevice);
}
return false;
}
@@ -559,8 +531,6 @@
if (CC_LIKELY(mHidlDevice != nullptr)) {
return CameraProviderManager::mapToStatusT(
mHidlDevice->storeMetaDataInBuffers(enable));
- } else if (mDevice && mDevice->ops->store_meta_data_in_buffers) {
- return mDevice->ops->store_meta_data_in_buffers(mDevice, enable);
}
return enable ? INVALID_OPERATION: OK;
}
@@ -571,8 +541,6 @@
if (CC_LIKELY(mHidlDevice != nullptr)) {
return CameraProviderManager::mapToStatusT(
mHidlDevice->startRecording());
- } else if (mDevice && mDevice->ops->start_recording) {
- return mDevice->ops->start_recording(mDevice);
}
return INVALID_OPERATION;
}
@@ -585,8 +553,6 @@
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (CC_LIKELY(mHidlDevice != nullptr)) {
mHidlDevice->stopRecording();
- } else if (mDevice && mDevice->ops->stop_recording) {
- mDevice->ops->stop_recording(mDevice);
}
}
@@ -598,8 +564,6 @@
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (CC_LIKELY(mHidlDevice != nullptr)) {
return mHidlDevice->recordingEnabled();
- } else if (mDevice && mDevice->ops->recording_enabled) {
- return mDevice->ops->recording_enabled(mDevice);
}
return false;
}
@@ -624,9 +588,6 @@
} else {
mHidlDevice->releaseRecordingFrame(heapId, bufferIndex);
}
- } else if (mDevice && mDevice->ops->release_recording_frame) {
- void *data = ((uint8_t *)heap->base()) + offset;
- return mDevice->ops->release_recording_frame(mDevice, data);
}
}
@@ -653,9 +614,6 @@
ALOGE("%s only supports VideoNativeHandleMetadata mode", __FUNCTION__);
return;
}
- } else {
- ALOGE("Non HIDL mode do not support %s", __FUNCTION__);
- return;
}
}
@@ -674,8 +632,6 @@
if (CC_LIKELY(mHidlDevice != nullptr)) {
return CameraProviderManager::mapToStatusT(
mHidlDevice->autoFocus());
- } else if (mDevice && mDevice->ops->auto_focus) {
- return mDevice->ops->auto_focus(mDevice);
}
return INVALID_OPERATION;
}
@@ -686,8 +642,6 @@
if (CC_LIKELY(mHidlDevice != nullptr)) {
return CameraProviderManager::mapToStatusT(
mHidlDevice->cancelAutoFocus());
- } else if (mDevice && mDevice->ops->cancel_auto_focus) {
- return mDevice->ops->cancel_auto_focus(mDevice);
}
return INVALID_OPERATION;
}
@@ -698,8 +652,6 @@
if (CC_LIKELY(mHidlDevice != nullptr)) {
return CameraProviderManager::mapToStatusT(
mHidlDevice->takePicture());
- } else if (mDevice && mDevice->ops->take_picture) {
- return mDevice->ops->take_picture(mDevice);
}
return INVALID_OPERATION;
}
@@ -710,8 +662,6 @@
if (CC_LIKELY(mHidlDevice != nullptr)) {
return CameraProviderManager::mapToStatusT(
mHidlDevice->cancelPicture());
- } else if (mDevice && mDevice->ops->cancel_picture) {
- return mDevice->ops->cancel_picture(mDevice);
}
return INVALID_OPERATION;
}
@@ -722,8 +672,6 @@
if (CC_LIKELY(mHidlDevice != nullptr)) {
return CameraProviderManager::mapToStatusT(
mHidlDevice->setParameters(params.flatten().string()));
- } else if (mDevice && mDevice->ops->set_parameters) {
- return mDevice->ops->set_parameters(mDevice, params.flatten().string());
}
return INVALID_OPERATION;
}
@@ -740,14 +688,6 @@
});
String8 tmp(outParam.c_str());
parms.unflatten(tmp);
- } else if (mDevice && mDevice->ops->get_parameters) {
- char *temp = mDevice->ops->get_parameters(mDevice);
- String8 str_parms(temp);
- if (mDevice->ops->put_parameters)
- mDevice->ops->put_parameters(mDevice, temp);
- else
- free(temp);
- parms.unflatten(str_parms);
}
return parms;
}
@@ -758,8 +698,6 @@
if (CC_LIKELY(mHidlDevice != nullptr)) {
return CameraProviderManager::mapToStatusT(
mHidlDevice->sendCommand((CommandType) cmd, arg1, arg2));
- } else if (mDevice && mDevice->ops->send_command) {
- return mDevice->ops->send_command(mDevice, cmd, arg1, arg2);
}
return INVALID_OPERATION;
}
@@ -773,8 +711,6 @@
if (CC_LIKELY(mHidlDevice != nullptr)) {
mHidlDevice->close();
mHidlDevice.clear();
- } else if (mDevice && mDevice->ops->release) {
- mDevice->ops->release(mDevice);
}
}
@@ -790,15 +726,10 @@
Status s = mHidlDevice->dumpState(handle);
native_handle_delete(handle);
return CameraProviderManager::mapToStatusT(s);
- } else if (mDevice && mDevice->ops->dump) {
- return mDevice->ops->dump(mDevice, fd);
}
return OK; // It's fine if the HAL doesn't implement dump()
}
-/**
- * Methods for legacy (non-HIDL) path follows
- */
void CameraHardwareInterface::sNotifyCb(int32_t msg_type, int32_t ext1,
int32_t ext2, void *user)
{
@@ -868,177 +799,4 @@
mem->decStrong(mem);
}
-ANativeWindow* CameraHardwareInterface::sToAnw(void *user)
-{
- CameraHardwareInterface *object =
- reinterpret_cast<CameraHardwareInterface *>(user);
- return object->mPreviewWindow.get();
-}
-#define anw(n) sToAnw(((struct camera_preview_window *)(n))->user)
-#define hwi(n) reinterpret_cast<CameraHardwareInterface *>(\
- ((struct camera_preview_window *)(n))->user)
-
-int CameraHardwareInterface::sDequeueBuffer(struct preview_stream_ops* w,
- buffer_handle_t** buffer, int *stride)
-{
- int rc;
- ANativeWindow *a = anw(w);
- ANativeWindowBuffer* anb;
- rc = native_window_dequeue_buffer_and_wait(a, &anb);
- if (rc == OK) {
- *buffer = &anb->handle;
- *stride = anb->stride;
- }
- return rc;
-}
-
-#ifndef container_of
-#define container_of(ptr, type, member) ({ \
- const __typeof__(((type *) 0)->member) *__mptr = (ptr); \
- (type *) ((char *) __mptr - (char *)(&((type *)0)->member)); })
-#endif
-
-int CameraHardwareInterface::sLockBuffer(struct preview_stream_ops* w,
- buffer_handle_t* /*buffer*/)
-{
- ANativeWindow *a = anw(w);
- (void)a;
- return 0;
-}
-
-int CameraHardwareInterface::sEnqueueBuffer(struct preview_stream_ops* w,
- buffer_handle_t* buffer)
-{
- ANativeWindow *a = anw(w);
- return a->queueBuffer(a,
- container_of(buffer, ANativeWindowBuffer, handle), -1);
-}
-
-int CameraHardwareInterface::sCancelBuffer(struct preview_stream_ops* w,
- buffer_handle_t* buffer)
-{
- ANativeWindow *a = anw(w);
- return a->cancelBuffer(a,
- container_of(buffer, ANativeWindowBuffer, handle), -1);
-}
-
-int CameraHardwareInterface::sSetBufferCount(struct preview_stream_ops* w, int count)
-{
- ANativeWindow *a = anw(w);
-
- if (a != nullptr) {
- // Workaround for b/27039775
- // Previously, setting the buffer count would reset the buffer
- // queue's flag that allows for all buffers to be dequeued on the
- // producer side, instead of just the producer's declared max count,
- // if no filled buffers have yet been queued by the producer. This
- // reset no longer happens, but some HALs depend on this behavior,
- // so it needs to be maintained for HAL backwards compatibility.
- // Simulate the prior behavior by disconnecting/reconnecting to the
- // window and setting the values again. This has the drawback of
- // actually causing memory reallocation, which may not have happened
- // in the past.
- CameraHardwareInterface *hw = hwi(w);
- native_window_api_disconnect(a, NATIVE_WINDOW_API_CAMERA);
- native_window_api_connect(a, NATIVE_WINDOW_API_CAMERA);
- if (hw->mPreviewScalingMode != NOT_SET) {
- native_window_set_scaling_mode(a, hw->mPreviewScalingMode);
- }
- if (hw->mPreviewTransform != NOT_SET) {
- native_window_set_buffers_transform(a, hw->mPreviewTransform);
- }
- if (hw->mPreviewWidth != NOT_SET) {
- native_window_set_buffers_dimensions(a,
- hw->mPreviewWidth, hw->mPreviewHeight);
- native_window_set_buffers_format(a, hw->mPreviewFormat);
- }
- if (hw->mPreviewUsage != 0) {
- native_window_set_usage(a, hw->mPreviewUsage);
- }
- if (hw->mPreviewSwapInterval != NOT_SET) {
- a->setSwapInterval(a, hw->mPreviewSwapInterval);
- }
- if (hw->mPreviewCrop.left != NOT_SET) {
- native_window_set_crop(a, &(hw->mPreviewCrop));
- }
- }
-
- return native_window_set_buffer_count(a, count);
-}
-
-int CameraHardwareInterface::sSetBuffersGeometry(struct preview_stream_ops* w,
- int width, int height, int format)
-{
- int rc;
- ANativeWindow *a = anw(w);
- CameraHardwareInterface *hw = hwi(w);
- hw->mPreviewWidth = width;
- hw->mPreviewHeight = height;
- hw->mPreviewFormat = format;
- rc = native_window_set_buffers_dimensions(a, width, height);
- if (rc == OK) {
- rc = native_window_set_buffers_format(a, format);
- }
- return rc;
-}
-
-int CameraHardwareInterface::sSetCrop(struct preview_stream_ops *w,
- int left, int top, int right, int bottom)
-{
- ANativeWindow *a = anw(w);
- CameraHardwareInterface *hw = hwi(w);
- hw->mPreviewCrop.left = left;
- hw->mPreviewCrop.top = top;
- hw->mPreviewCrop.right = right;
- hw->mPreviewCrop.bottom = bottom;
- return native_window_set_crop(a, &(hw->mPreviewCrop));
-}
-
-int CameraHardwareInterface::sSetTimestamp(struct preview_stream_ops *w,
- int64_t timestamp) {
- ANativeWindow *a = anw(w);
- return native_window_set_buffers_timestamp(a, timestamp);
-}
-
-int CameraHardwareInterface::sSetUsage(struct preview_stream_ops* w, int usage)
-{
- ANativeWindow *a = anw(w);
- CameraHardwareInterface *hw = hwi(w);
- hw->mPreviewUsage = usage;
- return native_window_set_usage(a, usage);
-}
-
-int CameraHardwareInterface::sSetSwapInterval(struct preview_stream_ops *w, int interval)
-{
- ANativeWindow *a = anw(w);
- CameraHardwareInterface *hw = hwi(w);
- hw->mPreviewSwapInterval = interval;
- return a->setSwapInterval(a, interval);
-}
-
-int CameraHardwareInterface::sGetMinUndequeuedBufferCount(
- const struct preview_stream_ops *w,
- int *count)
-{
- ANativeWindow *a = anw(w);
- return a->query(a, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, count);
-}
-
-void CameraHardwareInterface::initHalPreviewWindow()
-{
- mHalPreviewWindow.nw.cancel_buffer = sCancelBuffer;
- mHalPreviewWindow.nw.lock_buffer = sLockBuffer;
- mHalPreviewWindow.nw.dequeue_buffer = sDequeueBuffer;
- mHalPreviewWindow.nw.enqueue_buffer = sEnqueueBuffer;
- mHalPreviewWindow.nw.set_buffer_count = sSetBufferCount;
- mHalPreviewWindow.nw.set_buffers_geometry = sSetBuffersGeometry;
- mHalPreviewWindow.nw.set_crop = sSetCrop;
- mHalPreviewWindow.nw.set_timestamp = sSetTimestamp;
- mHalPreviewWindow.nw.set_usage = sSetUsage;
- mHalPreviewWindow.nw.set_swap_interval = sSetSwapInterval;
-
- mHalPreviewWindow.nw.get_min_undequeued_buffer_count =
- sGetMinUndequeuedBufferCount;
-}
-
}; // namespace android
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 1c38d00..e519b04 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -90,7 +90,6 @@
public:
explicit CameraHardwareInterface(const char *name):
- mDevice(nullptr),
mHidlDevice(nullptr),
mName(name),
mPreviewScalingMode(NOT_SET),
@@ -299,7 +298,6 @@
status_t dump(int fd, const Vector<String16>& /*args*/) const;
private:
- camera_device_t *mDevice;
sp<hardware::camera::device::V1_0::ICameraDevice> mHidlDevice;
String8 mName;
@@ -369,41 +367,6 @@
static void sPutMemory(camera_memory_t *data);
- static ANativeWindow *sToAnw(void *user);
-
- static int sDequeueBuffer(struct preview_stream_ops* w,
- buffer_handle_t** buffer, int *stride);
-
- static int sLockBuffer(struct preview_stream_ops* w,
- buffer_handle_t* /*buffer*/);
-
- static int sEnqueueBuffer(struct preview_stream_ops* w,
- buffer_handle_t* buffer);
-
- static int sCancelBuffer(struct preview_stream_ops* w,
- buffer_handle_t* buffer);
-
- static int sSetBufferCount(struct preview_stream_ops* w, int count);
-
- static int sSetBuffersGeometry(struct preview_stream_ops* w,
- int width, int height, int format);
-
- static int sSetCrop(struct preview_stream_ops *w,
- int left, int top, int right, int bottom);
-
- static int sSetTimestamp(struct preview_stream_ops *w,
- int64_t timestamp);
-
- static int sSetUsage(struct preview_stream_ops* w, int usage);
-
- static int sSetSwapInterval(struct preview_stream_ops *w, int interval);
-
- static int sGetMinUndequeuedBufferCount(
- const struct preview_stream_ops *w,
- int *count);
-
- void initHalPreviewWindow();
-
std::pair<bool, uint64_t> getBufferId(ANativeWindowBuffer* anb);
void cleanupCirculatingBuffers();
@@ -459,13 +422,6 @@
sp<ANativeWindow> mPreviewWindow;
- struct camera_preview_window {
- struct preview_stream_ops nw;
- void *user;
- };
-
- struct camera_preview_window mHalPreviewWindow;
-
notify_callback mNotifyCb;
data_callback mDataCb;
data_callback_timestamp mDataCbTimestamp;
@@ -479,7 +435,7 @@
int mPreviewWidth;
int mPreviewHeight;
int mPreviewFormat;
- int mPreviewUsage;
+ uint64_t mPreviewUsage;
int mPreviewSwapInterval;
android_native_rect_t mPreviewCrop;
@@ -523,6 +479,7 @@
uint64_t mNextBufferId = 1;
static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+ std::mutex mHidlMemPoolMapLock; // protecting mHidlMemPoolMap
std::unordered_map<int, camera_memory_t*> mHidlMemPoolMap;
};
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 69b1d7d..a980cde 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -154,6 +154,15 @@
resultQueueRet.description().c_str());
return DEAD_OBJECT;
}
+ IF_ALOGV() {
+ session->interfaceChain([](
+ ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+ ALOGV("Session interface chain:");
+ for (auto iface : interfaceChain) {
+ ALOGV(" %s", iface.c_str());
+ }
+ });
+ }
mInterface = new HalInterface(session, queue);
std::string providerType;
@@ -407,7 +416,7 @@
}
BufferUsageFlags Camera3Device::mapToConsumerUsage(
- uint32_t usage) {
+ uint64_t usage) {
return usage;
}
@@ -460,12 +469,17 @@
return static_cast<uint32_t>(pixelFormat);
}
-uint32_t Camera3Device::mapConsumerToFrameworkUsage(
+android_dataspace Camera3Device::mapToFrameworkDataspace(
+ DataspaceFlags dataSpace) {
+ return static_cast<android_dataspace>(dataSpace);
+}
+
+uint64_t Camera3Device::mapConsumerToFrameworkUsage(
BufferUsageFlags usage) {
return usage;
}
-uint32_t Camera3Device::mapProducerToFrameworkUsage(
+uint64_t Camera3Device::mapProducerToFrameworkUsage(
BufferUsageFlags usage) {
return usage;
}
@@ -1208,7 +1222,7 @@
status_t Camera3Device::createStream(sp<Surface> consumer,
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
- int streamSetId, bool isShared, uint32_t consumerUsage) {
+ int streamSetId, bool isShared, uint64_t consumerUsage) {
ATRACE_CALL();
if (consumer == nullptr) {
@@ -1226,13 +1240,13 @@
status_t Camera3Device::createStream(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
- int streamSetId, bool isShared, uint32_t consumerUsage) {
+ int streamSetId, bool isShared, uint64_t consumerUsage) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
Mutex::Autolock l(mLock);
ALOGV("Camera %s: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d"
- " consumer usage 0x%x, isShared %d", mId.string(), mNextStreamId, width, height, format,
+ " consumer usage %" PRIu64 ", isShared %d", mId.string(), mNextStreamId, width, height, format,
dataSpace, rotation, consumerUsage, isShared);
status_t res;
@@ -1345,10 +1359,11 @@
return OK;
}
-status_t Camera3Device::getStreamInfo(int id,
- uint32_t *width, uint32_t *height,
- uint32_t *format, android_dataspace *dataSpace) {
+status_t Camera3Device::getStreamInfo(int id, StreamInfo *streamInfo) {
ATRACE_CALL();
+ if (nullptr == streamInfo) {
+ return BAD_VALUE;
+ }
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
@@ -1375,10 +1390,14 @@
return idx;
}
- if (width) *width = mOutputStreams[idx]->getWidth();
- if (height) *height = mOutputStreams[idx]->getHeight();
- if (format) *format = mOutputStreams[idx]->getFormat();
- if (dataSpace) *dataSpace = mOutputStreams[idx]->getDataSpace();
+ streamInfo->width = mOutputStreams[idx]->getWidth();
+ streamInfo->height = mOutputStreams[idx]->getHeight();
+ streamInfo->format = mOutputStreams[idx]->getFormat();
+ streamInfo->dataSpace = mOutputStreams[idx]->getDataSpace();
+ streamInfo->formatOverridden = mOutputStreams[idx]->isFormatOverridden();
+ streamInfo->originalFormat = mOutputStreams[idx]->getOriginalFormat();
+ streamInfo->dataSpaceOverridden = mOutputStreams[idx]->isDataSpaceOverridden();
+ streamInfo->originalDataSpace = mOutputStreams[idx]->getOriginalDataSpace();
return OK;
}
@@ -1478,6 +1497,7 @@
status_t Camera3Device::getInputBufferProducer(
sp<IGraphicBufferProducer> *producer) {
+ ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
@@ -1691,6 +1711,7 @@
}
status_t Camera3Device::waitForNextFrame(nsecs_t timeout) {
+ ATRACE_CALL();
status_t res;
Mutex::Autolock l(mOutputLock);
@@ -1884,6 +1905,7 @@
*/
void Camera3Device::notifyStatus(bool idle) {
+ ATRACE_CALL();
{
// Need mLock to safely update state and synchronize to current
// state of methods in flight.
@@ -1955,6 +1977,20 @@
return OK;
}
+status_t Camera3Device::dropStreamBuffers(bool dropping, int streamId) {
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ int idx = mOutputStreams.indexOfKey(streamId);
+ if (idx == NAME_NOT_FOUND) {
+ ALOGE("%s: Stream %d is not found.", __FUNCTION__, streamId);
+ return BAD_VALUE;
+ }
+
+ sp<Camera3OutputStreamInterface> stream = mOutputStreams.editValueAt(idx);
+ return stream->dropBuffers(dropping);
+}
+
/**
* Camera3Device private methods
*/
@@ -2317,6 +2353,7 @@
}
void Camera3Device::setErrorState(const char *fmt, ...) {
+ ATRACE_CALL();
Mutex::Autolock l(mLock);
va_list args;
va_start(args, fmt);
@@ -2327,6 +2364,7 @@
}
void Camera3Device::setErrorStateV(const char *fmt, va_list args) {
+ ATRACE_CALL();
Mutex::Autolock l(mLock);
setErrorStateLockedV(fmt, args);
}
@@ -2411,6 +2449,7 @@
}
void Camera3Device::removeInFlightMapEntryLocked(int idx) {
+ ATRACE_CALL();
nsecs_t duration = mInFlightMap.valueAt(idx).maxExpectedDuration;
mInFlightMap.removeItemsAt(idx, 1);
@@ -2433,25 +2472,6 @@
nsecs_t sensorTimestamp = request.sensorTimestamp;
nsecs_t shutterTimestamp = request.shutterTimestamp;
- bool skipResultMetadata = false;
- if (request.requestStatus != OK) {
- switch (request.requestStatus) {
- case CAMERA3_MSG_ERROR_DEVICE:
- case CAMERA3_MSG_ERROR_REQUEST:
- case CAMERA3_MSG_ERROR_RESULT:
- skipResultMetadata = true;
- break;
- case CAMERA3_MSG_ERROR_BUFFER:
- //Result metadata should return in this case.
- skipResultMetadata = false;
- break;
- default:
- SET_ERR("Unknown error message: %d", request.requestStatus);
- skipResultMetadata = false;
- break;
- }
- }
-
// Check if it's okay to remove the request from InFlightMap:
// In the case of a successful request:
// all input and output buffers, all result metadata, shutter callback
@@ -2459,7 +2479,7 @@
// In the case of a unsuccessful request:
// all input and output buffers arrived.
if (request.numBuffersLeft == 0 &&
- (skipResultMetadata ||
+ (request.skipResultMetadata ||
(request.haveResultMetadata && shutterTimestamp != 0))) {
ATRACE_ASYNC_END("frame capture", frameNumber);
@@ -2495,6 +2515,7 @@
}
void Camera3Device::flushInflightRequests() {
+ ATRACE_CALL();
{ // First return buffers cached in mInFlightMap
Mutex::Autolock l(mInFlightLock);
for (size_t idx = 0; idx < mInFlightMap.size(); idx++) {
@@ -2621,6 +2642,7 @@
void Camera3Device::sendPartialCaptureResult(const camera_metadata_t * partialResult,
const CaptureResultExtras &resultExtras, uint32_t frameNumber) {
+ ATRACE_CALL();
Mutex::Autolock l(mOutputLock);
CaptureResult captureResult;
@@ -2636,6 +2658,7 @@
CameraMetadata &collectedPartialResult,
uint32_t frameNumber,
bool reprocess) {
+ ATRACE_CALL();
if (pendingMetadata.isEmpty())
return;
@@ -2884,7 +2907,7 @@
void Camera3Device::notifyError(const camera3_error_msg_t &msg,
sp<NotificationListener> listener) {
-
+ ATRACE_CALL();
// Map camera HAL error codes to ICameraDeviceCallback error codes
// Index into this with the HAL error code
static const int32_t halErrorMap[CAMERA3_MSG_NUM_ERRORS] = {
@@ -2932,6 +2955,11 @@
InFlightRequest &r = mInFlightMap.editValueAt(idx);
r.requestStatus = msg.error_code;
resultExtras = r.resultExtras;
+ if (hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT == errorCode
+ || hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST ==
+ errorCode) {
+ r.skipResultMetadata = true;
+ }
if (hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT ==
errorCode) {
// In case of missing result check whether the buffers
@@ -2962,6 +2990,7 @@
void Camera3Device::notifyShutter(const camera3_shutter_msg_t &msg,
sp<NotificationListener> listener) {
+ ATRACE_CALL();
ssize_t idx;
// Set timestamp for the request in the in-flight tracking
@@ -3048,24 +3077,20 @@
Camera3Device::HalInterface::HalInterface(
sp<ICameraDeviceSession> &session,
std::shared_ptr<RequestMetadataQueue> queue) :
- mHal3Device(nullptr),
mHidlSession(session),
mRequestMetadataQueue(queue) {}
-Camera3Device::HalInterface::HalInterface() :
- mHal3Device(nullptr) {}
+Camera3Device::HalInterface::HalInterface() {}
Camera3Device::HalInterface::HalInterface(const HalInterface& other) :
- mHal3Device(other.mHal3Device),
mHidlSession(other.mHidlSession),
mRequestMetadataQueue(other.mRequestMetadataQueue) {}
bool Camera3Device::HalInterface::valid() {
- return (mHal3Device != nullptr) || (mHidlSession != nullptr);
+ return (mHidlSession != nullptr);
}
void Camera3Device::HalInterface::clear() {
- mHal3Device = nullptr;
mHidlSession.clear();
}
@@ -3080,72 +3105,60 @@
if (!valid()) return INVALID_OPERATION;
status_t res = OK;
- if (mHal3Device != nullptr) {
- const camera_metadata *r;
- r = mHal3Device->ops->construct_default_request_settings(
- mHal3Device, templateId);
- if (r == nullptr) return BAD_VALUE;
- *requestTemplate = clone_camera_metadata(r);
- if (requestTemplate == nullptr) {
- ALOGE("%s: Unable to clone camera metadata received from HAL",
- __FUNCTION__);
- return INVALID_OPERATION;
- }
- } else {
- common::V1_0::Status status;
- RequestTemplate id;
- switch (templateId) {
- case CAMERA3_TEMPLATE_PREVIEW:
- id = RequestTemplate::PREVIEW;
- break;
- case CAMERA3_TEMPLATE_STILL_CAPTURE:
- id = RequestTemplate::STILL_CAPTURE;
- break;
- case CAMERA3_TEMPLATE_VIDEO_RECORD:
- id = RequestTemplate::VIDEO_RECORD;
- break;
- case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
- id = RequestTemplate::VIDEO_SNAPSHOT;
- break;
- case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
- id = RequestTemplate::ZERO_SHUTTER_LAG;
- break;
- case CAMERA3_TEMPLATE_MANUAL:
- id = RequestTemplate::MANUAL;
- break;
- default:
- // Unknown template ID
- return BAD_VALUE;
- }
- auto err = mHidlSession->constructDefaultRequestSettings(id,
- [&status, &requestTemplate]
- (common::V1_0::Status s, const device::V3_2::CameraMetadata& request) {
- status = s;
- if (status == common::V1_0::Status::OK) {
- const camera_metadata *r =
- reinterpret_cast<const camera_metadata_t*>(request.data());
- size_t expectedSize = request.size();
- int ret = validate_camera_metadata_structure(r, &expectedSize);
- if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
- *requestTemplate = clone_camera_metadata(r);
- if (*requestTemplate == nullptr) {
- ALOGE("%s: Unable to clone camera metadata received from HAL",
- __FUNCTION__);
- status = common::V1_0::Status::INTERNAL_ERROR;
- }
- } else {
- ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ common::V1_0::Status status;
+ RequestTemplate id;
+ switch (templateId) {
+ case CAMERA3_TEMPLATE_PREVIEW:
+ id = RequestTemplate::PREVIEW;
+ break;
+ case CAMERA3_TEMPLATE_STILL_CAPTURE:
+ id = RequestTemplate::STILL_CAPTURE;
+ break;
+ case CAMERA3_TEMPLATE_VIDEO_RECORD:
+ id = RequestTemplate::VIDEO_RECORD;
+ break;
+ case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
+ id = RequestTemplate::VIDEO_SNAPSHOT;
+ break;
+ case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
+ id = RequestTemplate::ZERO_SHUTTER_LAG;
+ break;
+ case CAMERA3_TEMPLATE_MANUAL:
+ id = RequestTemplate::MANUAL;
+ break;
+ default:
+ // Unknown template ID
+ return BAD_VALUE;
+ }
+ auto err = mHidlSession->constructDefaultRequestSettings(id,
+ [&status, &requestTemplate]
+ (common::V1_0::Status s, const device::V3_2::CameraMetadata& request) {
+ status = s;
+ if (status == common::V1_0::Status::OK) {
+ const camera_metadata *r =
+ reinterpret_cast<const camera_metadata_t*>(request.data());
+ size_t expectedSize = request.size();
+ int ret = validate_camera_metadata_structure(r, &expectedSize);
+ if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ *requestTemplate = clone_camera_metadata(r);
+ if (*requestTemplate == nullptr) {
+ ALOGE("%s: Unable to clone camera metadata received from HAL",
+ __FUNCTION__);
status = common::V1_0::Status::INTERNAL_ERROR;
}
+ } else {
+ ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ status = common::V1_0::Status::INTERNAL_ERROR;
}
- });
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- res = DEAD_OBJECT;
- } else {
- res = CameraProviderManager::mapToStatusT(status);
- }
+ }
+ });
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ res = DEAD_OBJECT;
+ } else {
+ res = CameraProviderManager::mapToStatusT(status);
}
+
return res;
}
@@ -3154,145 +3167,191 @@
if (!valid()) return INVALID_OPERATION;
status_t res = OK;
- if (mHal3Device != nullptr) {
- res = mHal3Device->ops->configure_streams(mHal3Device, config);
+ // Convert stream config to HIDL
+ std::set<int> activeStreams;
+ StreamConfiguration requestedConfiguration;
+ requestedConfiguration.streams.resize(config->num_streams);
+ for (size_t i = 0; i < config->num_streams; i++) {
+ Stream &dst = requestedConfiguration.streams[i];
+ camera3_stream_t *src = config->streams[i];
+
+ Camera3Stream* cam3stream = Camera3Stream::cast(src);
+ cam3stream->setBufferFreedListener(this);
+ int streamId = cam3stream->getId();
+ StreamType streamType;
+ switch (src->stream_type) {
+ case CAMERA3_STREAM_OUTPUT:
+ streamType = StreamType::OUTPUT;
+ break;
+ case CAMERA3_STREAM_INPUT:
+ streamType = StreamType::INPUT;
+ break;
+ default:
+ ALOGE("%s: Stream %d: Unsupported stream type %d",
+ __FUNCTION__, streamId, config->streams[i]->stream_type);
+ return BAD_VALUE;
+ }
+ dst.id = streamId;
+ dst.streamType = streamType;
+ dst.width = src->width;
+ dst.height = src->height;
+ dst.format = mapToPixelFormat(src->format);
+ dst.usage = mapToConsumerUsage(cam3stream->getUsage());
+ dst.dataSpace = mapToHidlDataspace(src->data_space);
+ dst.rotation = mapToStreamRotation((camera3_stream_rotation_t) src->rotation);
+
+ activeStreams.insert(streamId);
+ // Create Buffer ID map if necessary
+ if (mBufferIdMaps.count(streamId) == 0) {
+ mBufferIdMaps.emplace(streamId, BufferIdMap{});
+ }
+ }
+ // remove BufferIdMap for deleted streams
+ for(auto it = mBufferIdMaps.begin(); it != mBufferIdMaps.end();) {
+ int streamId = it->first;
+ bool active = activeStreams.count(streamId) > 0;
+ if (!active) {
+ it = mBufferIdMaps.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ res = mapToStreamConfigurationMode(
+ (camera3_stream_configuration_mode_t) config->operation_mode,
+ /*out*/ &requestedConfiguration.operationMode);
+ if (res != OK) {
+ return res;
+ }
+
+ // Invoke configureStreams
+
+ device::V3_3::HalStreamConfiguration finalConfiguration;
+ common::V1_0::Status status;
+
+ // See if we have v3.3 HAL
+ sp<device::V3_3::ICameraDeviceSession> hidlSession_3_3;
+ auto castResult = device::V3_3::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult.isOk()) {
+ hidlSession_3_3 = castResult;
} else {
- // Convert stream config to HIDL
- std::set<int> activeStreams;
- StreamConfiguration requestedConfiguration;
- requestedConfiguration.streams.resize(config->num_streams);
- for (size_t i = 0; i < config->num_streams; i++) {
- Stream &dst = requestedConfiguration.streams[i];
- camera3_stream_t *src = config->streams[i];
-
- Camera3Stream* cam3stream = Camera3Stream::cast(src);
- cam3stream->setBufferFreedListener(this);
- int streamId = cam3stream->getId();
- StreamType streamType;
- switch (src->stream_type) {
- case CAMERA3_STREAM_OUTPUT:
- streamType = StreamType::OUTPUT;
- break;
- case CAMERA3_STREAM_INPUT:
- streamType = StreamType::INPUT;
- break;
- default:
- ALOGE("%s: Stream %d: Unsupported stream type %d",
- __FUNCTION__, streamId, config->streams[i]->stream_type);
- return BAD_VALUE;
- }
- dst.id = streamId;
- dst.streamType = streamType;
- dst.width = src->width;
- dst.height = src->height;
- dst.format = mapToPixelFormat(src->format);
- dst.usage = mapToConsumerUsage(src->usage);
- dst.dataSpace = mapToHidlDataspace(src->data_space);
- dst.rotation = mapToStreamRotation((camera3_stream_rotation_t) src->rotation);
-
- activeStreams.insert(streamId);
- // Create Buffer ID map if necessary
- if (mBufferIdMaps.count(streamId) == 0) {
- mBufferIdMaps.emplace(streamId, BufferIdMap{});
- }
+ ALOGE("%s: Transaction error when casting ICameraDeviceSession: %s", __FUNCTION__,
+ castResult.description().c_str());
+ }
+ if (hidlSession_3_3 != nullptr) {
+ // We do; use v3.3 for the call
+ ALOGV("%s: v3.3 device found", __FUNCTION__);
+ auto err = hidlSession_3_3->configureStreams_3_3(requestedConfiguration,
+ [&status, &finalConfiguration]
+ (common::V1_0::Status s, const device::V3_3::HalStreamConfiguration& halConfiguration) {
+ finalConfiguration = halConfiguration;
+ status = s;
+ });
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return DEAD_OBJECT;
}
- // remove BufferIdMap for deleted streams
- for(auto it = mBufferIdMaps.begin(); it != mBufferIdMaps.end();) {
- int streamId = it->first;
- bool active = activeStreams.count(streamId) > 0;
- if (!active) {
- it = mBufferIdMaps.erase(it);
- } else {
- ++it;
- }
- }
-
- res = mapToStreamConfigurationMode(
- (camera3_stream_configuration_mode_t) config->operation_mode,
- /*out*/ &requestedConfiguration.operationMode);
- if (res != OK) {
- return res;
- }
-
- // Invoke configureStreams
-
- HalStreamConfiguration finalConfiguration;
- common::V1_0::Status status;
+ } else {
+ // We don't; use v3.2 call and construct a v3.3 HalStreamConfiguration
+ ALOGV("%s: v3.2 device found", __FUNCTION__);
+ HalStreamConfiguration finalConfiguration_3_2;
auto err = mHidlSession->configureStreams(requestedConfiguration,
- [&status, &finalConfiguration]
+ [&status, &finalConfiguration_3_2]
(common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
- finalConfiguration = halConfiguration;
+ finalConfiguration_3_2 = halConfiguration;
status = s;
});
if (!err.isOk()) {
ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
return DEAD_OBJECT;
}
+ finalConfiguration.streams.resize(finalConfiguration_3_2.streams.size());
+ for (size_t i = 0; i < finalConfiguration_3_2.streams.size(); i++) {
+ finalConfiguration.streams[i].v3_2 = finalConfiguration_3_2.streams[i];
+ finalConfiguration.streams[i].overrideDataSpace =
+ requestedConfiguration.streams[i].dataSpace;
+ }
+ }
- if (status != common::V1_0::Status::OK ) {
- return CameraProviderManager::mapToStatusT(status);
+ if (status != common::V1_0::Status::OK ) {
+ return CameraProviderManager::mapToStatusT(status);
+ }
+
+ // And convert output stream configuration from HIDL
+
+ for (size_t i = 0; i < config->num_streams; i++) {
+ camera3_stream_t *dst = config->streams[i];
+ int streamId = Camera3Stream::cast(dst)->getId();
+
+ // Start scan at i, with the assumption that the stream order matches
+ size_t realIdx = i;
+ bool found = false;
+ for (size_t idx = 0; idx < finalConfiguration.streams.size(); idx++) {
+ if (finalConfiguration.streams[realIdx].v3_2.id == streamId) {
+ found = true;
+ break;
+ }
+ realIdx = (realIdx >= finalConfiguration.streams.size()) ? 0 : realIdx + 1;
+ }
+ if (!found) {
+ ALOGE("%s: Stream %d not found in stream configuration response from HAL",
+ __FUNCTION__, streamId);
+ return INVALID_OPERATION;
+ }
+ device::V3_3::HalStream &src = finalConfiguration.streams[realIdx];
+
+ Camera3Stream* dstStream = Camera3Stream::cast(dst);
+ dstStream->setFormatOverride(false);
+ dstStream->setDataSpaceOverride(false);
+ int overrideFormat = mapToFrameworkFormat(src.v3_2.overrideFormat);
+ android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
+
+ if (dst->format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ if (dst->format != overrideFormat) {
+ ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__,
+ streamId, dst->format);
+ }
+ if (dst->data_space != overrideDataSpace) {
+ ALOGE("%s: Stream %d: DataSpace override not allowed for format 0x%x", __FUNCTION__,
+ streamId, dst->format);
+ }
+ } else {
+ dstStream->setFormatOverride((dst->format != overrideFormat) ? true : false);
+ dstStream->setDataSpaceOverride((dst->data_space != overrideDataSpace) ? true : false);
+
+ // Override allowed with IMPLEMENTATION_DEFINED
+ dst->format = overrideFormat;
+ dst->data_space = overrideDataSpace;
}
- // And convert output stream configuration from HIDL
-
- for (size_t i = 0; i < config->num_streams; i++) {
- camera3_stream_t *dst = config->streams[i];
- int streamId = Camera3Stream::cast(dst)->getId();
-
- // Start scan at i, with the assumption that the stream order matches
- size_t realIdx = i;
- bool found = false;
- for (size_t idx = 0; idx < finalConfiguration.streams.size(); idx++) {
- if (finalConfiguration.streams[realIdx].id == streamId) {
- found = true;
- break;
- }
- realIdx = (realIdx >= finalConfiguration.streams.size()) ? 0 : realIdx + 1;
- }
- if (!found) {
- ALOGE("%s: Stream %d not found in stream configuration response from HAL",
+ if (dst->stream_type == CAMERA3_STREAM_INPUT) {
+ if (src.v3_2.producerUsage != 0) {
+ ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
__FUNCTION__, streamId);
return INVALID_OPERATION;
}
- HalStream &src = finalConfiguration.streams[realIdx];
-
- int overrideFormat = mapToFrameworkFormat(src.overrideFormat);
- if (dst->format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
- if (dst->format != overrideFormat) {
- ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__,
- streamId, dst->format);
- }
- } else {
- // Override allowed with IMPLEMENTATION_DEFINED
- dst->format = overrideFormat;
+ dstStream->setUsage(
+ mapConsumerToFrameworkUsage(src.v3_2.consumerUsage));
+ } else {
+ // OUTPUT
+ if (src.v3_2.consumerUsage != 0) {
+ ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
+ __FUNCTION__, streamId);
+ return INVALID_OPERATION;
}
-
- if (dst->stream_type == CAMERA3_STREAM_INPUT) {
- if (src.producerUsage != 0) {
- ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
- __FUNCTION__, streamId);
- return INVALID_OPERATION;
- }
- dst->usage = mapConsumerToFrameworkUsage(src.consumerUsage);
- } else {
- // OUTPUT
- if (src.consumerUsage != 0) {
- ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
- __FUNCTION__, streamId);
- return INVALID_OPERATION;
- }
- dst->usage = mapProducerToFrameworkUsage(src.producerUsage);
- }
- dst->max_buffers = src.maxBuffers;
+ dstStream->setUsage(
+ mapProducerToFrameworkUsage(src.v3_2.producerUsage));
}
+ dst->max_buffers = src.v3_2.maxBuffers;
}
+
return res;
}
void Camera3Device::HalInterface::wrapAsHidlRequest(camera3_capture_request_t* request,
/*out*/device::V3_2::CaptureRequest* captureRequest,
/*out*/std::vector<native_handle_t*>* handlesCreated) {
-
+ ATRACE_CALL();
if (captureRequest == nullptr || handlesCreated == nullptr) {
ALOGE("%s: captureRequest (%p) and handlesCreated (%p) must not be null",
__FUNCTION__, captureRequest, handlesCreated);
@@ -3441,14 +3500,11 @@
if (!valid()) return INVALID_OPERATION;
status_t res = OK;
- if (mHal3Device != nullptr) {
- res = mHal3Device->ops->process_capture_request(mHal3Device, request);
- } else {
- uint32_t numRequestProcessed = 0;
- std::vector<camera3_capture_request_t*> requests(1);
- requests[0] = request;
- res = processBatchCaptureRequests(requests, &numRequestProcessed);
- }
+ uint32_t numRequestProcessed = 0;
+ std::vector<camera3_capture_request_t*> requests(1);
+ requests[0] = request;
+ res = processBatchCaptureRequests(requests, &numRequestProcessed);
+
return res;
}
@@ -3457,31 +3513,24 @@
if (!valid()) return INVALID_OPERATION;
status_t res = OK;
- if (mHal3Device != nullptr) {
- res = mHal3Device->ops->flush(mHal3Device);
+ auto err = mHidlSession->flush();
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ res = DEAD_OBJECT;
} else {
- auto err = mHidlSession->flush();
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- res = DEAD_OBJECT;
- } else {
- res = CameraProviderManager::mapToStatusT(err);
- }
+ res = CameraProviderManager::mapToStatusT(err);
}
+
return res;
}
-status_t Camera3Device::HalInterface::dump(int fd) {
+status_t Camera3Device::HalInterface::dump(int /*fd*/) {
ATRACE_NAME("CameraHal::dump");
if (!valid()) return INVALID_OPERATION;
- status_t res = OK;
- if (mHal3Device != nullptr) {
- mHal3Device->ops->dump(mHal3Device, fd);
- } else {
- // Handled by CameraProviderManager::dump
- }
- return res;
+ // Handled by CameraProviderManager::dump
+
+ return OK;
}
status_t Camera3Device::HalInterface::close() {
@@ -3489,15 +3538,12 @@
if (!valid()) return INVALID_OPERATION;
status_t res = OK;
- if (mHal3Device != nullptr) {
- mHal3Device->common.close(&mHal3Device->common);
- } else {
- auto err = mHidlSession->close();
- // Interface will be dead shortly anyway, so don't log errors
- if (!err.isOk()) {
- res = DEAD_OBJECT;
- }
+ auto err = mHidlSession->close();
+ // Interface will be dead shortly anyway, so don't log errors
+ if (!err.isOk()) {
+ res = DEAD_OBJECT;
}
+
return res;
}
@@ -3614,11 +3660,13 @@
void Camera3Device::RequestThread::setNotificationListener(
wp<NotificationListener> listener) {
+ ATRACE_CALL();
Mutex::Autolock l(mRequestLock);
mListener = listener;
}
void Camera3Device::RequestThread::configurationComplete(bool isConstrainedHighSpeed) {
+ ATRACE_CALL();
Mutex::Autolock l(mRequestLock);
mReconfigured = true;
// Prepare video stream for high speed recording.
@@ -3629,6 +3677,7 @@
List<sp<CaptureRequest> > &requests,
/*out*/
int64_t *lastFrameNumber) {
+ ATRACE_CALL();
Mutex::Autolock l(mRequestLock);
for (List<sp<CaptureRequest> >::iterator it = requests.begin(); it != requests.end();
++it) {
@@ -3651,7 +3700,7 @@
status_t Camera3Device::RequestThread::queueTrigger(
RequestTrigger trigger[],
size_t count) {
-
+ ATRACE_CALL();
Mutex::Autolock l(mTriggerMutex);
status_t ret;
@@ -3708,6 +3757,7 @@
const RequestList &requests,
/*out*/
int64_t *lastFrameNumber) {
+ ATRACE_CALL();
Mutex::Autolock l(mRequestLock);
if (lastFrameNumber != NULL) {
*lastFrameNumber = mRepeatingLastFrameNumber;
@@ -3734,6 +3784,7 @@
}
status_t Camera3Device::RequestThread::clearRepeatingRequests(/*out*/int64_t *lastFrameNumber) {
+ ATRACE_CALL();
Mutex::Autolock l(mRequestLock);
return clearRepeatingRequestsLocked(lastFrameNumber);
@@ -3750,6 +3801,7 @@
status_t Camera3Device::RequestThread::clear(
/*out*/int64_t *lastFrameNumber) {
+ ATRACE_CALL();
Mutex::Autolock l(mRequestLock);
ALOGV("RequestThread::%s:", __FUNCTION__);
@@ -3805,6 +3857,7 @@
}
void Camera3Device::RequestThread::setPaused(bool paused) {
+ ATRACE_CALL();
Mutex::Autolock l(mPauseLock);
mDoPause = paused;
mDoPauseSignal.signal();
@@ -3812,6 +3865,7 @@
status_t Camera3Device::RequestThread::waitUntilRequestProcessed(
int32_t requestId, nsecs_t timeout) {
+ ATRACE_CALL();
Mutex::Autolock l(mLatestRequestMutex);
status_t res;
while (mLatestRequestId != requestId) {
@@ -3838,6 +3892,7 @@
}
void Camera3Device::RequestThread::checkAndStopRepeatingRequest() {
+ ATRACE_CALL();
bool surfaceAbandoned = false;
int64_t lastFrameNumber = 0;
sp<NotificationListener> listener;
@@ -3866,6 +3921,7 @@
}
bool Camera3Device::RequestThread::sendRequestsBatch() {
+ ATRACE_CALL();
status_t res;
size_t batchSize = mNextRequests.size();
std::vector<camera3_capture_request_t*> requests(batchSize);
@@ -4261,6 +4317,7 @@
}
CameraMetadata Camera3Device::RequestThread::getLatestRequest() const {
+ ATRACE_CALL();
Mutex::Autolock al(mLatestRequestMutex);
ALOGV("RequestThread::%s", __FUNCTION__);
@@ -4270,6 +4327,7 @@
bool Camera3Device::RequestThread::isStreamPending(
sp<Camera3StreamInterface>& stream) {
+ ATRACE_CALL();
Mutex::Autolock l(mRequestLock);
for (const auto& nextRequest : mNextRequests) {
@@ -4299,6 +4357,7 @@
}
nsecs_t Camera3Device::getExpectedInFlightDuration() {
+ ATRACE_CALL();
Mutex::Autolock al(mInFlightLock);
return mExpectedInflightDuration > kMinInflightDuration ?
mExpectedInflightDuration : kMinInflightDuration;
@@ -4370,6 +4429,7 @@
}
void Camera3Device::RequestThread::waitForNextRequestBatch() {
+ ATRACE_CALL();
// Optimized a bit for the simple steady-state case (single repeating
// request), to avoid putting that request in the queue temporarily.
Mutex::Autolock l(mRequestLock);
@@ -4519,6 +4579,7 @@
}
bool Camera3Device::RequestThread::waitIfPaused() {
+ ATRACE_CALL();
status_t res;
Mutex::Autolock l(mPauseLock);
while (mDoPause) {
@@ -4543,6 +4604,7 @@
}
void Camera3Device::RequestThread::unpauseForNewRequests() {
+ ATRACE_CALL();
// With work to do, mark thread as unpaused.
// If paused by request (setPaused), don't resume, to avoid
// extra signaling/waiting overhead to waitUntilPaused
@@ -4574,7 +4636,7 @@
status_t Camera3Device::RequestThread::insertTriggers(
const sp<CaptureRequest> &request) {
-
+ ATRACE_CALL();
Mutex::Autolock al(mTriggerMutex);
sp<Camera3Device> parent = mParent.promote();
@@ -4663,6 +4725,7 @@
status_t Camera3Device::RequestThread::removeTriggers(
const sp<CaptureRequest> &request) {
+ ATRACE_CALL();
Mutex::Autolock al(mTriggerMutex);
CameraMetadata &metadata = request->mSettings;
@@ -4779,6 +4842,7 @@
}
status_t Camera3Device::PreparerThread::prepare(int maxCount, sp<Camera3StreamInterface>& stream) {
+ ATRACE_CALL();
status_t res;
Mutex::Autolock l(mLock);
@@ -4822,6 +4886,7 @@
}
status_t Camera3Device::PreparerThread::clear() {
+ ATRACE_CALL();
Mutex::Autolock l(mLock);
for (const auto& stream : mPendingStreams) {
@@ -4834,6 +4899,7 @@
}
void Camera3Device::PreparerThread::setNotificationListener(wp<NotificationListener> listener) {
+ ATRACE_CALL();
Mutex::Autolock l(mLock);
mListener = listener;
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index d700e03..081af19 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -30,6 +30,7 @@
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
#include <android/hardware/camera/device/3.2/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.2/ICameraDeviceCallback.h>
#include <fmq/MessageQueue.h>
#include <hardware/camera3.h>
@@ -117,20 +118,18 @@
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
- bool isShared = false, uint32_t consumerUsage = 0) override;
+ bool isShared = false, uint64_t consumerUsage = 0) override;
status_t createStream(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
- bool isShared = false, uint32_t consumerUsage = 0) override;
+ bool isShared = false, uint64_t consumerUsage = 0) override;
status_t createInputStream(
uint32_t width, uint32_t height, int format,
int *id) override;
- status_t getStreamInfo(int id,
- uint32_t *width, uint32_t *height,
- uint32_t *format, android_dataspace *dataSpace) override;
+ status_t getStreamInfo(int id, StreamInfo *streamInfo) override;
status_t setStreamTransform(int id, int transform) override;
status_t deleteStream(int id) override;
@@ -179,6 +178,12 @@
*/
status_t setConsumerSurfaces(int streamId, const std::vector<sp<Surface>>& consumers) override;
+ /**
+ * Drop buffers for stream of streamId if dropping is true. If dropping is false, do not
+ * drop buffers for stream of streamId.
+ */
+ status_t dropStreamBuffers(bool dropping, int streamId) override;
+
private:
// internal typedefs
@@ -271,7 +276,6 @@
void getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out);
private:
- camera3_device_t *mHal3Device;
sp<hardware::camera::device::V3_2::ICameraDeviceSession> mHidlSession;
std::shared_ptr<RequestMetadataQueue> mRequestMetadataQueue;
@@ -590,7 +594,7 @@
static hardware::graphics::common::V1_0::PixelFormat mapToPixelFormat(int frameworkFormat);
static hardware::camera::device::V3_2::DataspaceFlags mapToHidlDataspace(
android_dataspace dataSpace);
- static hardware::camera::device::V3_2::BufferUsageFlags mapToConsumerUsage(uint32_t usage);
+ static hardware::camera::device::V3_2::BufferUsageFlags mapToConsumerUsage(uint64_t usage);
static hardware::camera::device::V3_2::StreamRotation mapToStreamRotation(
camera3_stream_rotation_t rotation);
// Returns a negative error code if the passed-in operation mode is not valid.
@@ -598,9 +602,11 @@
/*out*/ hardware::camera::device::V3_2::StreamConfigurationMode *mode);
static camera3_buffer_status_t mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status);
static int mapToFrameworkFormat(hardware::graphics::common::V1_0::PixelFormat pixelFormat);
- static uint32_t mapConsumerToFrameworkUsage(
+ static android_dataspace mapToFrameworkDataspace(
+ hardware::camera::device::V3_2::DataspaceFlags);
+ static uint64_t mapConsumerToFrameworkUsage(
hardware::camera::device::V3_2::BufferUsageFlags usage);
- static uint32_t mapProducerToFrameworkUsage(
+ static uint64_t mapProducerToFrameworkUsage(
hardware::camera::device::V3_2::BufferUsageFlags usage);
struct RequestTrigger {
@@ -886,6 +892,11 @@
// For auto-exposure modes, equal to 1/(lower end of target FPS range)
nsecs_t maxExpectedDuration;
+ // Whether the result metadata for this request is to be skipped. The
+ // result metadata should be skipped in the case of
+ // REQUEST/RESULT error.
+ bool skipResultMetadata;
+
// Default constructor needed by KeyedVector
InFlightRequest() :
shutterTimestamp(0),
@@ -895,7 +906,8 @@
numBuffersLeft(0),
hasInputBuffer(false),
hasCallback(true),
- maxExpectedDuration(kDefaultExpectedDuration) {
+ maxExpectedDuration(kDefaultExpectedDuration),
+ skipResultMetadata(false) {
}
InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput,
@@ -908,7 +920,8 @@
resultExtras(extras),
hasInputBuffer(hasInput),
hasCallback(hasAppCallback),
- maxExpectedDuration(maxDuration) {
+ maxExpectedDuration(maxDuration),
+ skipResultMetadata(false) {
}
};
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index 9c951b7..84fb890 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -95,7 +95,7 @@
return OK;
}
-status_t Camera3DummyStream::getEndpointUsage(uint32_t *usage) const {
+status_t Camera3DummyStream::getEndpointUsage(uint64_t *usage) const {
*usage = DUMMY_USAGE;
return OK;
}
@@ -108,6 +108,10 @@
return false;
}
+status_t Camera3DummyStream::dropBuffers(bool /*dropping*/) {
+ return OK;
+}
+
status_t Camera3DummyStream::setConsumers(const std::vector<sp<Surface>>& /*consumers*/) {
ALOGE("%s: Stream %d: Dummy stream doesn't support set consumer surface!",
__FUNCTION__, mId);
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index 35a6a18..9710765 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -57,6 +57,12 @@
virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd);
/**
+ * Drop buffers for stream of streamId if dropping is true. If dropping is false, do not
+ * drop buffers for stream of streamId.
+ */
+ virtual status_t dropBuffers(bool /*dropping*/) override;
+
+ /**
* Return if this output stream is for video encoding.
*/
bool isVideoStream() const;
@@ -94,7 +100,7 @@
static const int DUMMY_FORMAT = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
static const android_dataspace DUMMY_DATASPACE = HAL_DATASPACE_UNKNOWN;
static const camera3_stream_rotation_t DUMMY_ROTATION = CAMERA3_STREAM_ROTATION_0;
- static const uint32_t DUMMY_USAGE = GRALLOC_USAGE_HW_COMPOSER;
+ static const uint64_t DUMMY_USAGE = GRALLOC_USAGE_HW_COMPOSER;
/**
* Internal Camera3Stream interface
@@ -107,7 +113,7 @@
virtual status_t configureQueueLocked();
- virtual status_t getEndpointUsage(uint32_t *usage) const;
+ virtual status_t getEndpointUsage(uint64_t *usage) const;
}; // class Camera3DummyStream
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index 7ad2300..a52422d 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -69,7 +69,7 @@
(void) args;
String8 lines;
- uint32_t consumerUsage = 0;
+ uint64_t consumerUsage = 0;
status_t res = getEndpointUsage(&consumerUsage);
if (res != OK) consumerUsage = 0;
@@ -78,8 +78,8 @@
camera3_stream::width, camera3_stream::height,
camera3_stream::format, camera3_stream::data_space);
lines.appendFormat(" Max size: %zu\n", mMaxSize);
- lines.appendFormat(" Combined usage: %d, max HAL buffers: %d\n",
- camera3_stream::usage | consumerUsage, camera3_stream::max_buffers);
+ lines.appendFormat(" Combined usage: %" PRIu64 ", max HAL buffers: %d\n",
+ mUsage | consumerUsage, camera3_stream::max_buffers);
lines.appendFormat(" Frames produced: %d, last timestamp: %" PRId64 " ns\n",
mFrameCount, mLastTimestamp);
lines.appendFormat(" Total buffers: %zu, currently dequeued: %zu\n",
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index 35dda39..2376058 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -85,7 +85,7 @@
virtual size_t getHandoutInputBufferCountLocked();
- virtual status_t getEndpointUsage(uint32_t *usage) const = 0;
+ virtual status_t getEndpointUsage(uint64_t *usage) const = 0;
status_t getBufferPreconditionCheckLocked() const;
status_t returnBufferPreconditionCheckLocked() const;
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index ff2dcef..2cb1ea7 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -258,7 +258,7 @@
camera3_stream::max_buffers : minBufs;
// TODO: somehow set the total buffer count when producer connects?
- mConsumer = new BufferItemConsumer(consumer, camera3_stream::usage,
+ mConsumer = new BufferItemConsumer(consumer, mUsage,
mTotalBufferCount);
mConsumer->setName(String8::format("Camera3-InputStream-%d", mId));
@@ -284,7 +284,7 @@
return OK;
}
-status_t Camera3InputStream::getEndpointUsage(uint32_t *usage) const {
+status_t Camera3InputStream::getEndpointUsage(uint64_t *usage) const {
// Per HAL3 spec, input streams have 0 for their initial usage field.
*usage = 0;
return OK;
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h
index 8f5b431..81226f8 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.h
@@ -76,7 +76,7 @@
virtual status_t configureQueueLocked();
- virtual status_t getEndpointUsage(uint32_t *usage) const;
+ virtual status_t getEndpointUsage(uint64_t *usage) const;
/**
* BufferItemConsumer::BufferFreedListener interface
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index b02cd6a..8460c34 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -44,6 +44,7 @@
mUseBufferManager(false),
mTimestampOffset(timestampOffset),
mConsumerUsage(0),
+ mDropBuffers(false),
mDequeueBufferLatency(kDequeueLatencyBinSize) {
if (mConsumer == NULL) {
@@ -70,6 +71,7 @@
mUseBufferManager(false),
mTimestampOffset(timestampOffset),
mConsumerUsage(0),
+ mDropBuffers(false),
mDequeueBufferLatency(kDequeueLatencyBinSize) {
if (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW_OPAQUE) {
@@ -90,7 +92,7 @@
Camera3OutputStream::Camera3OutputStream(int id,
uint32_t width, uint32_t height, int format,
- uint32_t consumerUsage, android_dataspace dataSpace,
+ uint64_t consumerUsage, android_dataspace dataSpace,
camera3_stream_rotation_t rotation, nsecs_t timestampOffset, int setId) :
Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height,
/*maxSize*/0, format, dataSpace, rotation, setId),
@@ -100,6 +102,7 @@
mUseBufferManager(false),
mTimestampOffset(timestampOffset),
mConsumerUsage(consumerUsage),
+ mDropBuffers(false),
mDequeueBufferLatency(kDequeueLatencyBinSize) {
// Deferred consumer only support preview surface format now.
if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
@@ -111,7 +114,8 @@
// Sanity check for the consumer usage flag.
if ((consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) == 0 &&
(consumerUsage & GraphicBuffer::USAGE_HW_COMPOSER) == 0) {
- ALOGE("%s: Deferred consumer usage flag is illegal (0x%x)!", __FUNCTION__, consumerUsage);
+ ALOGE("%s: Deferred consumer usage flag is illegal %" PRIu64 "!",
+ __FUNCTION__, consumerUsage);
mState = STATE_ERROR;
}
@@ -127,7 +131,7 @@
int format,
android_dataspace dataSpace,
camera3_stream_rotation_t rotation,
- uint32_t consumerUsage, nsecs_t timestampOffset,
+ uint64_t consumerUsage, nsecs_t timestampOffset,
int setId) :
Camera3IOStreamBase(id, type, width, height,
/*maxSize*/0,
@@ -138,6 +142,7 @@
mUseBufferManager(false),
mTimestampOffset(timestampOffset),
mConsumerUsage(consumerUsage),
+ mDropBuffers(false),
mDequeueBufferLatency(kDequeueLatencyBinSize) {
if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
@@ -226,9 +231,14 @@
/**
* Return buffer back to ANativeWindow
*/
- if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) {
+ if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR || mDropBuffers) {
// Cancel buffer
- ALOGW("A frame is dropped for stream %d", mId);
+ if (mDropBuffers) {
+ ALOGV("%s: Dropping a frame for stream %d.", __FUNCTION__, mId);
+ } else {
+ ALOGW("%s: A frame is dropped for stream %d due to buffer error.", __FUNCTION__, mId);
+ }
+
res = currentConsumer->cancelBuffer(currentConsumer.get(),
anwBuffer,
anwReleaseFence);
@@ -365,10 +375,10 @@
mConsumerName = mConsumer->getConsumerName();
- res = native_window_set_usage(mConsumer.get(), camera3_stream::usage);
+ res = native_window_set_usage(mConsumer.get(), mUsage);
if (res != OK) {
- ALOGE("%s: Unable to configure usage %08x for stream %d",
- __FUNCTION__, camera3_stream::usage, mId);
+ ALOGE("%s: Unable to configure usage %" PRIu64 " for stream %d",
+ __FUNCTION__, mUsage, mId);
return res;
}
@@ -461,11 +471,11 @@
* HAL3.2 devices may not support the dynamic buffer registeration.
*/
if (mBufferManager != 0 && mSetId > CAMERA3_STREAM_SET_ID_INVALID) {
- uint32_t consumerUsage = 0;
+ uint64_t consumerUsage = 0;
getEndpointUsage(&consumerUsage);
StreamInfo streamInfo(
getId(), getStreamSetId(), getWidth(), getHeight(), getFormat(), getDataSpace(),
- camera3_stream::usage | consumerUsage, mTotalBufferCount,
+ mUsage | consumerUsage, mTotalBufferCount,
/*isConfigured*/true);
wp<Camera3OutputStream> weakThis(this);
res = mBufferManager->registerStream(weakThis,
@@ -628,7 +638,7 @@
return OK;
}
-status_t Camera3OutputStream::getEndpointUsage(uint32_t *usage) const {
+status_t Camera3OutputStream::getEndpointUsage(uint64_t *usage) const {
status_t res;
@@ -643,14 +653,12 @@
return res;
}
-status_t Camera3OutputStream::getEndpointUsageForSurface(uint32_t *usage,
+status_t Camera3OutputStream::getEndpointUsageForSurface(uint64_t *usage,
const sp<Surface>& surface) const {
status_t res;
- int32_t u = 0;
+ uint64_t u = 0;
- res = static_cast<ANativeWindow*>(surface.get())->query(surface.get(),
- NATIVE_WINDOW_CONSUMER_USAGE_BITS, &u);
-
+ res = native_window_get_consumer_usage(static_cast<ANativeWindow*>(surface.get()), &u);
// If an opaque output stream's endpoint is ImageReader, add
// GRALLOC_USAGE_HW_CAMERA_ZSL to the usage so HAL knows it will be used
// for the ZSL use case.
@@ -670,7 +678,7 @@
}
bool Camera3OutputStream::isVideoStream() const {
- uint32_t usage = 0;
+ uint64_t usage = 0;
status_t res = getEndpointUsage(&usage);
if (res != OK) {
ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res);
@@ -778,6 +786,12 @@
return res;
}
+status_t Camera3OutputStream::dropBuffers(bool dropping) {
+ Mutex::Autolock l(mLock);
+ mDropBuffers = dropping;
+ return OK;
+}
+
status_t Camera3OutputStream::notifyBufferReleased(ANativeWindowBuffer* /*anwBuffer*/) {
return OK;
}
@@ -813,7 +827,7 @@
}
bool Camera3OutputStream::isConsumedByHWComposer() const {
- uint32_t usage = 0;
+ uint64_t usage = 0;
status_t res = getEndpointUsage(&usage);
if (res != OK) {
ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res);
@@ -824,7 +838,7 @@
}
bool Camera3OutputStream::isConsumedByHWTexture() const {
- uint32_t usage = 0;
+ uint64_t usage = 0;
status_t res = getEndpointUsage(&usage);
if (res != OK) {
ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 97aa7d4..4865be7 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -44,7 +44,7 @@
uint32_t height;
uint32_t format;
android_dataspace dataSpace;
- uint32_t combinedUsage;
+ uint64_t combinedUsage;
size_t totalBufferCount;
bool isConfigured;
explicit StreamInfo(int id = CAMERA3_STREAM_ID_INVALID,
@@ -53,7 +53,7 @@
uint32_t h = 0,
uint32_t fmt = 0,
android_dataspace ds = HAL_DATASPACE_UNKNOWN,
- uint32_t usage = 0,
+ uint64_t usage = 0,
size_t bufferCount = 0,
bool configured = false) :
streamId(id),
@@ -101,7 +101,7 @@
* stream set id needs to be set to support buffer sharing between multiple streams.
*/
Camera3OutputStream(int id, uint32_t width, uint32_t height, int format,
- uint32_t consumerUsage, android_dataspace dataSpace,
+ uint64_t consumerUsage, android_dataspace dataSpace,
camera3_stream_rotation_t rotation, nsecs_t timestampOffset,
int setId = CAMERA3_STREAM_SET_ID_INVALID);
@@ -166,6 +166,11 @@
virtual status_t notifyBufferReleased(ANativeWindowBuffer *anwBuffer);
/**
+ * Drop buffers if dropping is true. If dropping is false, do not drop buffers.
+ */
+ virtual status_t dropBuffers(bool dropping) override;
+
+ /**
* Set the graphic buffer manager to get/return the stream buffers.
*
* It is only legal to call this method when stream is in STATE_CONSTRUCTED state.
@@ -176,7 +181,7 @@
Camera3OutputStream(int id, camera3_stream_type_t type,
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera3_stream_rotation_t rotation,
- uint32_t consumerUsage = 0, nsecs_t timestampOffset = 0,
+ uint64_t consumerUsage = 0, nsecs_t timestampOffset = 0,
int setId = CAMERA3_STREAM_SET_ID_INVALID);
/**
@@ -191,14 +196,14 @@
virtual status_t disconnectLocked();
- status_t getEndpointUsageForSurface(uint32_t *usage,
+ status_t getEndpointUsageForSurface(uint64_t *usage,
const sp<Surface>& surface) const;
status_t configureConsumerQueueLocked();
// Consumer as the output of camera HAL
sp<Surface> mConsumer;
- uint32_t getPresetConsumerUsage() const { return mConsumerUsage; }
+ uint64_t getPresetConsumerUsage() const { return mConsumerUsage; }
static const nsecs_t kDequeueBufferTimeout = 1000000000; // 1 sec
@@ -245,7 +250,10 @@
* Consumer end point usage flag set by the constructor for the deferred
* consumer case.
*/
- uint32_t mConsumerUsage;
+ uint64_t mConsumerUsage;
+
+ // Whether to drop valid buffers.
+ bool mDropBuffers;
/**
* Internal Camera3Stream interface
@@ -262,7 +270,7 @@
virtual status_t configureQueueLocked();
- virtual status_t getEndpointUsage(uint32_t *usage) const;
+ virtual status_t getEndpointUsage(uint64_t *usage) const;
/**
* Private methods
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index 8107dd0..1719d74 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -59,6 +59,11 @@
*
*/
virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd) = 0;
+
+ /**
+ * Drop buffers if dropping is true. If dropping is false, do not drop buffers.
+ */
+ virtual status_t dropBuffers(bool /*dropping*/) = 0;
};
} // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 2ae5660..5051711 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -23,7 +23,7 @@
Camera3SharedOutputStream::Camera3SharedOutputStream(int id,
const std::vector<sp<Surface>>& surfaces,
uint32_t width, uint32_t height, int format,
- uint32_t consumerUsage, android_dataspace dataSpace,
+ uint64_t consumerUsage, android_dataspace dataSpace,
camera3_stream_rotation_t rotation,
nsecs_t timestampOffset, int setId) :
Camera3OutputStream(id, CAMERA3_STREAM_OUTPUT, width, height,
@@ -41,7 +41,7 @@
mStreamSplitter = new Camera3StreamSplitter();
- uint32_t usage;
+ uint64_t usage;
getEndpointUsage(&usage);
res = mStreamSplitter->connect(mSurfaces, usage, camera3_stream::max_buffers, &mConsumer);
@@ -191,10 +191,10 @@
return res;
}
-status_t Camera3SharedOutputStream::getEndpointUsage(uint32_t *usage) const {
+status_t Camera3SharedOutputStream::getEndpointUsage(uint64_t *usage) const {
status_t res = OK;
- uint32_t u = 0;
+ uint64_t u = 0;
if (mConsumer == nullptr) {
// Called before shared buffer queue is constructed.
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index 7be0940..22bb2fc 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -34,7 +34,7 @@
*/
Camera3SharedOutputStream(int id, const std::vector<sp<Surface>>& surfaces,
uint32_t width, uint32_t height, int format,
- uint32_t consumerUsage, android_dataspace dataSpace,
+ uint64_t consumerUsage, android_dataspace dataSpace,
camera3_stream_rotation_t rotation, nsecs_t timestampOffset,
int setId = CAMERA3_STREAM_SET_ID_INVALID);
@@ -74,7 +74,7 @@
virtual status_t disconnectLocked();
- virtual status_t getEndpointUsage(uint32_t *usage) const;
+ virtual status_t getEndpointUsage(uint64_t *usage) const;
}; // class Camera3SharedOutputStream
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 9e6ac79..fbe8f4f 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -56,12 +56,15 @@
mState(STATE_CONSTRUCTED),
mStatusId(StatusTracker::NO_STATUS_ID),
mStreamUnpreparable(true),
+ mUsage(0),
mOldUsage(0),
mOldMaxBuffers(0),
mPrepared(false),
mPreparedBufferIdx(0),
mLastMaxCount(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX),
- mBufferLimitLatency(kBufferLimitLatencyBinSize) {
+ mBufferLimitLatency(kBufferLimitLatencyBinSize),
+ mFormatOverridden(false),
+ mOriginalFormat(-1) {
camera3_stream::stream_type = type;
camera3_stream::width = width;
@@ -69,7 +72,6 @@
camera3_stream::format = format;
camera3_stream::data_space = dataSpace;
camera3_stream::rotation = rotation;
- camera3_stream::usage = 0;
camera3_stream::max_buffers = 0;
camera3_stream::priv = NULL;
@@ -104,6 +106,40 @@
return camera3_stream::data_space;
}
+uint64_t Camera3Stream::getUsage() const {
+ return mUsage;
+}
+
+void Camera3Stream::setUsage(uint64_t usage) {
+ mUsage = usage;
+}
+
+void Camera3Stream::setFormatOverride(bool formatOverridden) {
+ mFormatOverridden = formatOverridden;
+ if (formatOverridden) mOriginalFormat = camera3_stream::format;
+}
+
+bool Camera3Stream::isFormatOverridden() const {
+ return mFormatOverridden;
+}
+
+int Camera3Stream::getOriginalFormat() const {
+ return mOriginalFormat;
+}
+
+void Camera3Stream::setDataSpaceOverride(bool dataSpaceOverridden) {
+ mDataSpaceOverridden = dataSpaceOverridden;
+ if (dataSpaceOverridden) mOriginalDataSpace = camera3_stream::data_space;
+}
+
+bool Camera3Stream::isDataSpaceOverridden() const {
+ return mDataSpaceOverridden;
+}
+
+android_dataspace Camera3Stream::getOriginalDataSpace() const {
+ return mOriginalDataSpace;
+}
+
camera3_stream* Camera3Stream::startConfiguration() {
ATRACE_CALL();
Mutex::Autolock l(mLock);
@@ -133,10 +169,10 @@
return NULL;
}
- mOldUsage = camera3_stream::usage;
+ mOldUsage = mUsage;
mOldMaxBuffers = camera3_stream::max_buffers;
- res = getEndpointUsage(&(camera3_stream::usage));
+ res = getEndpointUsage(&mUsage);
if (res != OK) {
ALOGE("%s: Cannot query consumer endpoint usage!",
__FUNCTION__);
@@ -197,7 +233,7 @@
// Check if the stream configuration is unchanged, and skip reallocation if
// so. As documented in hardware/camera3.h:configure_streams().
if (mState == STATE_IN_RECONFIG &&
- mOldUsage == camera3_stream::usage &&
+ mOldUsage == mUsage &&
mOldMaxBuffers == camera3_stream::max_buffers) {
mState = STATE_CONFIGURED;
return OK;
@@ -243,7 +279,7 @@
return INVALID_OPERATION;
}
- camera3_stream::usage = mOldUsage;
+ mUsage = mOldUsage;
camera3_stream::max_buffers = mOldMaxBuffers;
mState = (mState == STATE_IN_RECONFIG) ? STATE_CONFIGURED : STATE_CONSTRUCTED;
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 44fe6b6..6e7912e 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -144,6 +144,14 @@
uint32_t getHeight() const;
int getFormat() const;
android_dataspace getDataSpace() const;
+ uint64_t getUsage() const;
+ void setUsage(uint64_t usage);
+ void setFormatOverride(bool formatOverriden);
+ bool isFormatOverridden() const;
+ int getOriginalFormat() const;
+ void setDataSpaceOverride(bool dataSpaceOverriden);
+ bool isDataSpaceOverridden() const;
+ android_dataspace getOriginalDataSpace() const;
camera3_stream* asHalStream() override {
return this;
@@ -459,7 +467,7 @@
// Get the usage flags for the other endpoint, or return
// INVALID_OPERATION if they cannot be obtained.
- virtual status_t getEndpointUsage(uint32_t *usage) const = 0;
+ virtual status_t getEndpointUsage(uint64_t *usage) const = 0;
// Return whether the buffer is in the list of outstanding buffers.
bool isOutstandingBuffer(const camera3_stream_buffer& buffer) const;
@@ -473,8 +481,10 @@
// prepareNextBuffer called on it.
bool mStreamUnpreparable;
+ uint64_t mUsage;
+
private:
- uint32_t mOldUsage;
+ uint64_t mOldUsage;
uint32_t mOldMaxBuffers;
Condition mOutputBufferReturnedSignal;
Condition mInputBufferReturnedSignal;
@@ -510,6 +520,15 @@
// max_buffers.
static const int32_t kBufferLimitLatencyBinSize = 33; //in ms
CameraLatencyHistogram mBufferLimitLatency;
+
+ //Keep track of original format in case it gets overridden
+ bool mFormatOverridden;
+ int mOriginalFormat;
+
+ //Keep track of original dataSpace in case it gets overridden
+ bool mDataSpaceOverridden;
+ android_dataspace mOriginalDataSpace;
+
}; // class Camera3Stream
}; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 0544a1b..cc9bf8e 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -71,6 +71,12 @@
virtual uint32_t getHeight() const = 0;
virtual int getFormat() const = 0;
virtual android_dataspace getDataSpace() const = 0;
+ virtual void setFormatOverride(bool formatOverriden) = 0;
+ virtual bool isFormatOverridden() const = 0;
+ virtual int getOriginalFormat() const = 0;
+ virtual void setDataSpaceOverride(bool dataSpaceOverriden) = 0;
+ virtual bool isDataSpaceOverridden() const = 0;
+ virtual android_dataspace getOriginalDataSpace() const = 0;
/**
* Get a HAL3 handle for the stream, without starting stream configuration.
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 869e93a..a0a50c2 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -39,7 +39,7 @@
namespace android {
status_t Camera3StreamSplitter::connect(const std::vector<sp<Surface> >& surfaces,
- uint32_t consumerUsage, size_t halMaxBuffers, sp<Surface>* consumer) {
+ uint64_t consumerUsage, size_t halMaxBuffers, sp<Surface>* consumer) {
ATRACE_CALL();
if (consumer == nullptr) {
SP_LOGE("%s: consumer pointer is NULL", __FUNCTION__);
@@ -195,10 +195,8 @@
// Set dequeueBuffer/attachBuffer timeout if the consumer is not hw composer or hw texture.
// We need skip these cases as timeout will disable the non-blocking (async) mode.
- int32_t usage = 0;
- static_cast<ANativeWindow*>(outputQueue.get())->query(
- outputQueue.get(),
- NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage);
+ uint64_t usage = 0;
+ res = native_window_get_consumer_usage(static_cast<ANativeWindow*>(outputQueue.get()), &usage);
if (!(usage & (GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE))) {
outputQueue->setDequeueTimeout(kDequeueBufferTimeout);
}
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index cc623e0..3b8839e 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -52,7 +52,7 @@
// Connect to the stream splitter by creating buffer queue and connecting it
// with output surfaces.
status_t connect(const std::vector<sp<Surface> >& surfaces,
- uint32_t consumerUsage, size_t halMaxBuffers,
+ uint64_t consumerUsage, size_t halMaxBuffers,
sp<Surface>* consumer);
// addOutput adds an output BufferQueue to the splitter. The splitter
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index 3d54460..ee018c3 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -38,7 +38,7 @@
namespace android {
RingBufferConsumer::RingBufferConsumer(const sp<IGraphicBufferConsumer>& consumer,
- uint32_t consumerUsage,
+ uint64_t consumerUsage,
int bufferCount) :
ConsumerBase(consumer),
mBufferCount(bufferCount),
@@ -368,7 +368,7 @@
return mConsumer->setDefaultBufferFormat(defaultFormat);
}
-status_t RingBufferConsumer::setConsumerUsage(uint32_t usage) {
+status_t RingBufferConsumer::setConsumerUsage(uint64_t usage) {
Mutex::Autolock _l(mMutex);
return mConsumer->setConsumerUsageBits(usage);
}
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.h b/services/camera/libcameraservice/gui/RingBufferConsumer.h
index 2bafe4a..b737469 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.h
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.h
@@ -60,7 +60,7 @@
// the consumer usage flags passed to the graphics allocator. The
// bufferCount parameter specifies how many buffers can be pinned for user
// access at the same time.
- RingBufferConsumer(const sp<IGraphicBufferConsumer>& consumer, uint32_t consumerUsage,
+ RingBufferConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
int bufferCount);
virtual ~RingBufferConsumer();
@@ -80,7 +80,7 @@
// setConsumerUsage allows the BufferQueue consumer usage to be
// set at a later time after construction.
- status_t setConsumerUsage(uint32_t usage);
+ status_t setConsumerUsage(uint64_t usage);
// Buffer info, minus the graphics buffer/slot itself.
struct BufferInfo {
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 876c685..c7f9270 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -29,12 +29,15 @@
#include <unistd.h>
#include <string.h>
+#include <pwd.h>
#include <cutils/atomic.h>
#include <cutils/properties.h> // for property_get
#include <utils/misc.h>
+#include <android/content/pm/IPackageManagerNative.h>
+
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryHeapBase.h>
@@ -80,27 +83,26 @@
namespace android {
+ using namespace android::base;
+ using namespace android::content::pm;
+
// summarized records
-// up to 48 sets, each covering an hour -- at least 2 days of coverage
+// up to 36 sets, each covering an hour -- so at least 1.5 days
// (will be longer if there are hours without any media action)
static const nsecs_t kNewSetIntervalNs = 3600*(1000*1000*1000ll);
-static const int kMaxRecordSets = 48;
-// individual records kept in memory
-static const int kMaxRecords = 100;
+static const int kMaxRecordSets = 36;
+// individual records kept in memory: age or count
+// age: <= 36 hours (1.5 days)
+// count: hard limit of # records
+// (0 for either of these disables that threshold)
+static const nsecs_t kMaxRecordAgeNs = 36 * 3600 * (1000*1000*1000ll);
+static const int kMaxRecords = 0;
static const char *kServiceName = "media.metrics";
-
-//using android::status_t;
-//using android::OK;
-//using android::BAD_VALUE;
-//using android::NOT_ENOUGH_DATA;
-//using android::Parcel;
-
-
void MediaAnalyticsService::instantiate() {
defaultServiceManager()->addService(
String16(kServiceName), new MediaAnalyticsService());
@@ -110,6 +112,7 @@
MediaAnalyticsService::SummarizerSet::SummarizerSet() {
mSummarizers = new List<MetricsSummarizer *>();
}
+
MediaAnalyticsService::SummarizerSet::~SummarizerSet() {
// empty the list
List<MetricsSummarizer *> *l = mSummarizers;
@@ -153,8 +156,10 @@
MediaAnalyticsService::MediaAnalyticsService()
: mMaxRecords(kMaxRecords),
+ mMaxRecordAgeNs(kMaxRecordAgeNs),
mMaxRecordSets(kMaxRecordSets),
- mNewSetInterval(kNewSetIntervalNs) {
+ mNewSetInterval(kNewSetIntervalNs),
+ mDumpProto(MediaAnalyticsItem::PROTO_V0) {
ALOGD("MediaAnalyticsService created");
// clear our queues
@@ -167,6 +172,8 @@
mItemsSubmitted = 0;
mItemsFinalized = 0;
mItemsDiscarded = 0;
+ mItemsDiscardedExpire = 0;
+ mItemsDiscardedCount = 0;
mLastSessionID = 0;
// recover any persistency we set up
@@ -177,8 +184,23 @@
ALOGD("MediaAnalyticsService destroyed");
// clean out mOpen and mFinalized
+ while (mOpen->size() > 0) {
+ MediaAnalyticsItem * oitem = *(mOpen->begin());
+ mOpen->erase(mOpen->begin());
+ delete oitem;
+ mItemsDiscarded++;
+ mItemsDiscardedCount++;
+ }
delete mOpen;
mOpen = NULL;
+
+ while (mFinalized->size() > 0) {
+ MediaAnalyticsItem * oitem = *(mFinalized->begin());
+ mFinalized->erase(mFinalized->begin());
+ delete oitem;
+ mItemsDiscarded++;
+ mItemsDiscardedCount++;
+ }
delete mFinalized;
mFinalized = NULL;
@@ -200,6 +222,8 @@
// we control these, generally not trusting user input
nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+ // round nsecs to seconds
+ now = ((now + 500000000) / 1000000000) * 1000000000;
item->setTimestamp(now);
int pid = IPCThreadState::self()->getCallingPid();
int uid = IPCThreadState::self()->getCallingUid();
@@ -212,13 +236,15 @@
//
bool isTrusted = false;
+ ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
+
switch (uid) {
case AID_MEDIA:
case AID_MEDIA_CODEC:
case AID_MEDIA_EX:
case AID_MEDIA_DRM:
// trusted source, only override default values
- isTrusted = true;
+ isTrusted = true;
if (uid_given == (-1)) {
item->setUid(uid);
}
@@ -234,6 +260,22 @@
}
+ // Overwrite package name and version if the caller was untrusted.
+ if (!isTrusted) {
+ setPkgInfo(item, item->getUid(), true, true);
+ } else if (item->getPkgName().empty()) {
+ // empty, so fill out both parts
+ setPkgInfo(item, item->getUid(), true, true);
+ } else {
+ // trusted, provided a package, do nothing
+ }
+
+ ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
+ "sanitized pkg version: %d",
+ uid_given, item->getUid(),
+ item->getPkgName().c_str(),
+ item->getPkgVersionCode());
+
mItemsSubmitted++;
// validate the record; we discard if we don't like it
@@ -316,6 +358,7 @@
return id;
}
+
status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 512;
@@ -333,22 +376,41 @@
}
// crack any parameters
- bool clear = false;
- bool summary = false;
- nsecs_t ts_since = 0;
String16 summaryOption("-summary");
+ bool summary = false;
+ String16 protoOption("-proto");
String16 clearOption("-clear");
+ bool clear = false;
String16 sinceOption("-since");
+ nsecs_t ts_since = 0;
String16 helpOption("-help");
String16 onlyOption("-only");
- const char *only = NULL;
+ AString only;
int n = args.size();
+
for (int i = 0; i < n; i++) {
String8 myarg(args[i]);
if (args[i] == clearOption) {
clear = true;
} else if (args[i] == summaryOption) {
summary = true;
+ } else if (args[i] == protoOption) {
+ i++;
+ if (i < n) {
+ String8 value(args[i]);
+ int proto = MediaAnalyticsItem::PROTO_V0; // default to original
+ char *endp;
+ const char *p = value.string();
+ proto = strtol(p, &endp, 10);
+ if (endp != p || *endp == '\0') {
+ if (proto < MediaAnalyticsItem::PROTO_FIRST) {
+ proto = MediaAnalyticsItem::PROTO_FIRST;
+ } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
+ proto = MediaAnalyticsItem::PROTO_LAST;
+ }
+ mDumpProto = proto;
+ }
+ }
} else if (args[i] == sinceOption) {
i++;
if (i < n) {
@@ -368,18 +430,12 @@
i++;
if (i < n) {
String8 value(args[i]);
- const char *p = value.string();
- char *q = strdup(p);
- if (q != NULL) {
- if (only != NULL) {
- free((void*)only);
- }
- only = q;
- }
+ only = value.string();
}
} else if (args[i] == helpOption) {
result.append("Recognized parameters:\n");
result.append("-help this help message\n");
+ result.append("-proto X dump using protocol X (defaults to 1)");
result.append("-summary show summary info\n");
result.append("-clear clears out saved records\n");
result.append("-only X process records for component X\n");
@@ -398,11 +454,11 @@
dumpHeaders(result, ts_since);
- // only want 1, to avoid confusing folks that parse the output
+ // want exactly 1, to avoid confusing folks that parse the output
if (summary) {
- dumpSummaries(result, ts_since, only);
+ dumpSummaries(result, ts_since, only.c_str());
} else {
- dumpRecent(result, ts_since, only);
+ dumpRecent(result, ts_since, only.c_str());
}
@@ -428,6 +484,9 @@
const size_t SIZE = 512;
char buffer[SIZE];
+ snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
+ result.append(buffer);
+
int enabled = MediaAnalyticsItem::isEnabled();
if (enabled) {
snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
@@ -437,10 +496,14 @@
result.append(buffer);
snprintf(buffer, SIZE,
- "Since Boot: Submissions: %" PRId64
- " Finalizations: %" PRId64
- " Discarded: %" PRId64 "\n",
- mItemsSubmitted, mItemsFinalized, mItemsDiscarded);
+ "Since Boot: Submissions: %8" PRId64
+ " Finalizations: %8" PRId64 "\n",
+ mItemsSubmitted, mItemsFinalized);
+ result.append(buffer);
+ snprintf(buffer, SIZE,
+ "Records Discarded: %8" PRId64
+ " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
+ mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
result.append(buffer);
snprintf(buffer, SIZE,
"Summary Sets Discarded: %" PRId64 "\n", mSetsDiscarded);
@@ -462,6 +525,10 @@
snprintf(buffer, SIZE, "\nSummarized Metrics:\n");
result.append(buffer);
+ if (only != NULL && *only == '\0') {
+ only = NULL;
+ }
+
// have each of the distillers dump records
if (mSummarizerSets != NULL) {
List<SummarizerSet *>::iterator itSet = mSummarizerSets->begin();
@@ -488,6 +555,10 @@
const size_t SIZE = 512;
char buffer[SIZE];
+ if (only != NULL && *only == '\0') {
+ only = NULL;
+ }
+
// show the recently recorded records
snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
result.append(buffer);
@@ -524,7 +595,7 @@
ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
continue;
}
- AString entry = (*it)->toString();
+ AString entry = (*it)->toString(mDumpProto);
result.appendFormat("%5d: %s\n", slot, entry.c_str());
slot++;
}
@@ -549,13 +620,32 @@
l->push_back(item);
}
- // keep removing old records the front until we're in-bounds
+ // keep removing old records the front until we're in-bounds (count)
if (mMaxRecords > 0) {
while (l->size() > (size_t) mMaxRecords) {
MediaAnalyticsItem * oitem = *(l->begin());
l->erase(l->begin());
delete oitem;
mItemsDiscarded++;
+ mItemsDiscardedCount++;
+ }
+ }
+
+ // keep removing old records the front until we're in-bounds (count)
+ if (mMaxRecordAgeNs > 0) {
+ nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+ while (l->size() > 0) {
+ MediaAnalyticsItem * oitem = *(l->begin());
+ nsecs_t when = oitem->getTimestamp();
+ // careful about timejumps too
+ if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
+ // this (and the rest) are recent enough to keep
+ break;
+ }
+ l->erase(l->begin());
+ delete oitem;
+ mItemsDiscarded++;
+ mItemsDiscardedExpire++;
}
}
}
@@ -563,11 +653,6 @@
// are they alike enough that nitem can be folded into oitem?
static bool compatibleItems(MediaAnalyticsItem * oitem, MediaAnalyticsItem * nitem) {
- if (0) {
- ALOGD("Compare: o %s n %s",
- oitem->toString().c_str(), nitem->toString().c_str());
- }
-
// general safety
if (nitem->getUid() != oitem->getUid()) {
return false;
@@ -718,4 +803,155 @@
}
+// how long we hold package info before we re-fetch it
+#define PKG_EXPIRATION_NS (30*60*1000000000ll) // 30 minutes, in nsecs
+
+// give me the package name, perhaps going to find it
+void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion) {
+ ALOGV("asking for packagename to go with uid=%d", uid);
+
+ if (!setName && !setVersion) {
+ // setting nothing? strange
+ return;
+ }
+
+ nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+ struct UidToPkgMap mapping;
+ mapping.uid = (-1);
+
+ ssize_t i = mPkgMappings.indexOfKey(uid);
+ if (i >= 0) {
+ mapping = mPkgMappings.valueAt(i);
+ ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
+ uid, mapping.expiration, now);
+ if (mapping.expiration < now) {
+ // purge our current entry and re-query
+ ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
+ mPkgMappings.removeItemsAt(i, 1);
+ // could cheat and use a goto back to the top of the routine.
+ // a good compiler should recognize the local tail recursion...
+ return setPkgInfo(item, uid, setName, setVersion);
+ }
+ } else {
+ AString pkg;
+ std::string installer = "";
+ int32_t versionCode = 0;
+
+ struct passwd *pw = getpwuid(uid);
+ if (pw) {
+ pkg = pw->pw_name;
+ }
+
+ // find the proper value -- should we cache this binder??
+
+ sp<IBinder> binder = NULL;
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm == NULL) {
+ ALOGE("defaultServiceManager failed");
+ } else {
+ binder = sm->getService(String16("package_native"));
+ if (binder == NULL) {
+ ALOGE("getService package_native failed");
+ }
+ }
+
+ if (binder != NULL) {
+ sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
+ binder::Status status;
+
+ std::vector<int> uids;
+ std::vector<std::string> names;
+
+ uids.push_back(uid);
+
+ status = package_mgr->getNamesForUids(uids, &names);
+ if (!status.isOk()) {
+ ALOGE("package_native::getNamesForUids failed: %s",
+ status.exceptionMessage().c_str());
+ } else {
+ if (!names[0].empty()) {
+ pkg = names[0].c_str();
+ }
+ }
+
+ // strip any leading "shared:" strings that came back
+ if (pkg.startsWith("shared:")) {
+ pkg.erase(0, 7);
+ }
+
+ // determine how pkg was installed and the versionCode
+ //
+ if (pkg.empty()) {
+ // no name for us to manage
+ } else if (strchr(pkg.c_str(), '.') == NULL) {
+ // not of form 'com.whatever...'; assume internal and ok
+ } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
+ // android.* packages are assumed fine
+ } else {
+ String16 pkgName16(pkg.c_str());
+ status = package_mgr->getInstallerForPackage(pkgName16, &installer);
+ if (!status.isOk()) {
+ ALOGE("package_native::getInstallerForPackage failed: %s",
+ status.exceptionMessage().c_str());
+ }
+
+ // skip if we didn't get an installer
+ if (status.isOk()) {
+ status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
+ if (!status.isOk()) {
+ ALOGE("package_native::getVersionCodeForPackage failed: %s",
+ status.exceptionMessage().c_str());
+ }
+ }
+
+
+ ALOGV("package '%s' installed by '%s' versioncode %d / %08x",
+ pkg.c_str(), installer.c_str(), versionCode, versionCode);
+
+ if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
+ // from play store, we keep info
+ } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
+ // some google source, we keep info
+ } else if (strcmp(installer.c_str(), "preload") == 0) {
+ // preloads, we keep the info
+ } else if (installer.c_str()[0] == '\0') {
+ // sideload (no installer); do not report
+ pkg = "";
+ versionCode = 0;
+ } else {
+ // unknown installer; do not report
+ pkg = "";
+ versionCode = 0;
+ }
+ }
+ }
+
+ // add it to the map, to save a subsequent lookup
+ if (!pkg.empty()) {
+ Mutex::Autolock _l(mLock_mappings);
+ ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
+ ssize_t i = mPkgMappings.indexOfKey(uid);
+ if (i < 0) {
+ mapping.uid = uid;
+ mapping.pkg = pkg;
+ mapping.installer = installer.c_str();
+ mapping.versionCode = versionCode;
+ mapping.expiration = now + PKG_EXPIRATION_NS;
+ ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
+
+ mPkgMappings.add(uid, mapping);
+ }
+ }
+ }
+
+ if (mapping.uid != (uid_t)(-1)) {
+ if (setName) {
+ item->setPkgName(mapping.pkg);
+ }
+ if (setVersion) {
+ item->setPkgVersionCode(mapping.versionCode);
+ }
+ }
+}
+
} // namespace android
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index 6685967..52e4631 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -54,16 +54,22 @@
int64_t mItemsSubmitted;
int64_t mItemsFinalized;
int64_t mItemsDiscarded;
+ int64_t mItemsDiscardedExpire;
+ int64_t mItemsDiscardedCount;
int64_t mSetsDiscarded;
MediaAnalyticsItem::SessionID_t mLastSessionID;
// partitioned a bit so we don't over serialize
mutable Mutex mLock;
mutable Mutex mLock_ids;
+ mutable Mutex mLock_mappings;
- // the most we hold in memory
- // up to this many in each queue (open, finalized)
+ // limit how many records we'll retain
+ // by count (in each queue (open, finalized))
int32_t mMaxRecords;
+ // by time (none older than this long agan
+ nsecs_t mMaxRecordAgeNs;
+ //
// # of sets of summaries
int32_t mMaxRecordSets;
// nsecs until we start a new record set
@@ -118,6 +124,7 @@
void deleteItem(List<MediaAnalyticsItem *> *, MediaAnalyticsItem *);
// support for generating output
+ int mDumpProto;
String8 dumpQueue(List<MediaAnalyticsItem*> *);
String8 dumpQueue(List<MediaAnalyticsItem*> *, nsecs_t, const char *only);
@@ -125,6 +132,18 @@
void dumpSummaries(String8 &result, nsecs_t ts_since, const char * only);
void dumpRecent(String8 &result, nsecs_t ts_since, const char * only);
+ // mapping uids to package names
+ struct UidToPkgMap {
+ uid_t uid;
+ AString pkg;
+ AString installer;
+ int32_t versionCode;
+ nsecs_t expiration;
+ };
+
+ KeyedVector<uid_t,struct UidToPkgMap> mPkgMappings;
+ void setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion);
+
};
// ----------------------------------------------------------------------------
diff --git a/services/mediaanalytics/MetricsSummarizer.cpp b/services/mediaanalytics/MetricsSummarizer.cpp
index 3477f1f..93fe0ec 100644
--- a/services/mediaanalytics/MetricsSummarizer.cpp
+++ b/services/mediaanalytics/MetricsSummarizer.cpp
@@ -141,23 +141,23 @@
List<MediaAnalyticsItem *>::iterator it = mSummaries->begin();
for (; it != mSummaries->end(); it++) {
bool good = sameAttributes((*it), item, getIgnorables());
- ALOGV("Match against %s says %d",
- (*it)->toString().c_str(), good);
+ ALOGV("Match against %s says %d", (*it)->toString().c_str(), good);
if (good)
break;
}
if (it == mSummaries->end()) {
ALOGV("save new record");
- item = item->dup();
- if (item == NULL) {
+ MediaAnalyticsItem *nitem = item->dup();
+ if (nitem == NULL) {
ALOGE("unable to save MediaMetrics record");
}
- sortProps(item);
- item->setInt32("count",1);
- mSummaries->push_back(item);
+ sortProps(nitem);
+ nitem->setInt32("aggregated",1);
+ mergeRecord(*nitem, *item);
+ mSummaries->push_back(nitem);
} else {
ALOGV("increment existing record");
- (*it)->addInt32("count",1);
+ (*it)->addInt32("aggregated",1);
mergeRecord(*(*it), *item);
}
}
@@ -168,6 +168,71 @@
return;
}
+// keep some stats for things: sums, counts, standard deviation
+// the integer version -- all of these pieces are in 64 bits
+void MetricsSummarizer::minMaxVar64(MediaAnalyticsItem &summation, const char *key, int64_t value) {
+ if (key == NULL)
+ return;
+ int len = strlen(key) + 32;
+ char *tmpKey = (char *)malloc(len);
+
+ if (tmpKey == NULL) {
+ return;
+ }
+
+ // N - count of samples
+ snprintf(tmpKey, len, "%s.n", key);
+ summation.addInt64(tmpKey, 1);
+
+ // zero - count of samples that are zero
+ if (value == 0) {
+ snprintf(tmpKey, len, "%s.zero", key);
+ int64_t zero = 0;
+ (void) summation.getInt64(tmpKey,&zero);
+ zero++;
+ summation.setInt64(tmpKey, zero);
+ }
+
+ // min
+ snprintf(tmpKey, len, "%s.min", key);
+ int64_t min = value;
+ if (summation.getInt64(tmpKey,&min)) {
+ if (min > value) {
+ summation.setInt64(tmpKey, value);
+ }
+ } else {
+ summation.setInt64(tmpKey, value);
+ }
+
+ // max
+ snprintf(tmpKey, len, "%s.max", key);
+ int64_t max = value;
+ if (summation.getInt64(tmpKey,&max)) {
+ if (max < value) {
+ summation.setInt64(tmpKey, value);
+ }
+ } else {
+ summation.setInt64(tmpKey, value);
+ }
+
+ // components for mean, stddev;
+ // stddev = sqrt(1/4*(sumx2 - (2*sumx*sumx/n) + ((sumx/n)^2)))
+ // sum x
+ snprintf(tmpKey, len, "%s.sumX", key);
+ summation.addInt64(tmpKey, value);
+ // sum x^2
+ snprintf(tmpKey, len, "%s.sumX2", key);
+ summation.addInt64(tmpKey, value*value);
+
+
+ // last thing we do -- remove the base key from the summation
+ // record so we won't get confused about it having both individual
+ // and summary information in there.
+ summation.removeProp(key);
+
+ free(tmpKey);
+}
+
//
// Comparators
@@ -186,20 +251,23 @@
ALOGV("MetricsSummarizer::sameAttributes(): summ %s", summ->toString().c_str());
ALOGV("MetricsSummarizer::sameAttributes(): single %s", single->toString().c_str());
+ // keep different sources/users separate
+ if (single->mUid != summ->mUid) {
+ return false;
+ }
+
// this can be made better.
for(size_t i=0;i<single->mPropCount;i++) {
MediaAnalyticsItem::Prop *prop1 = &(single->mProps[i]);
const char *attrName = prop1->mName;
- ALOGV("compare on attr '%s'", attrName);
// is it something we should ignore
if (ignorable != NULL) {
const char **ig = ignorable;
- while (*ig) {
+ for (;*ig; ig++) {
if (strcmp(*ig, attrName) == 0) {
break;
}
- ig++;
}
if (*ig) {
ALOGV("we don't mind that it has attr '%s'", attrName);
@@ -218,29 +286,42 @@
}
switch (prop1->mType) {
case MediaAnalyticsItem::kTypeInt32:
- if (prop1->u.int32Value != prop2->u.int32Value)
+ if (prop1->u.int32Value != prop2->u.int32Value) {
+ ALOGV("mismatch values");
return false;
+ }
break;
case MediaAnalyticsItem::kTypeInt64:
- if (prop1->u.int64Value != prop2->u.int64Value)
+ if (prop1->u.int64Value != prop2->u.int64Value) {
+ ALOGV("mismatch values");
return false;
+ }
break;
case MediaAnalyticsItem::kTypeDouble:
// XXX: watch out for floating point comparisons!
- if (prop1->u.doubleValue != prop2->u.doubleValue)
+ if (prop1->u.doubleValue != prop2->u.doubleValue) {
+ ALOGV("mismatch values");
return false;
+ }
break;
case MediaAnalyticsItem::kTypeCString:
- if (strcmp(prop1->u.CStringValue, prop2->u.CStringValue) != 0)
+ if (strcmp(prop1->u.CStringValue, prop2->u.CStringValue) != 0) {
+ ALOGV("mismatch values");
return false;
+ }
break;
case MediaAnalyticsItem::kTypeRate:
- if (prop1->u.rate.count != prop2->u.rate.count)
+ if (prop1->u.rate.count != prop2->u.rate.count) {
+ ALOGV("mismatch values");
return false;
- if (prop1->u.rate.duration != prop2->u.rate.duration)
+ }
+ if (prop1->u.rate.duration != prop2->u.rate.duration) {
+ ALOGV("mismatch values");
return false;
+ }
break;
default:
+ ALOGV("mismatch values in default type");
return false;
}
}
@@ -248,15 +329,6 @@
return true;
}
-bool MetricsSummarizer::sameAttributesId(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignorable) {
-
- // verify same user
- if (summ->mPid != single->mPid)
- return false;
-
- // and finally do the more expensive validation of the attributes
- return sameAttributes(summ, single, ignorable);
-}
int MetricsSummarizer::PropSorter(const void *a, const void *b) {
MediaAnalyticsItem::Prop *ai = (MediaAnalyticsItem::Prop *)a;
@@ -267,14 +339,8 @@
// we sort in the summaries so that it looks pretty in the dumpsys
void MetricsSummarizer::sortProps(MediaAnalyticsItem *item) {
if (item->mPropCount != 0) {
- if (DEBUG_SORT) {
- ALOGD("sortProps(pre): %s", item->toString().c_str());
- }
qsort(item->mProps, item->mPropCount,
sizeof(MediaAnalyticsItem::Prop), MetricsSummarizer::PropSorter);
- if (DEBUG_SORT) {
- ALOGD("sortProps(pst): %s", item->toString().c_str());
- }
}
}
diff --git a/services/mediaanalytics/MetricsSummarizer.h b/services/mediaanalytics/MetricsSummarizer.h
index 0b64eac..a9f0786 100644
--- a/services/mediaanalytics/MetricsSummarizer.h
+++ b/services/mediaanalytics/MetricsSummarizer.h
@@ -59,10 +59,9 @@
// various comparators
// "do these records have same attributes and values in those attrs"
- // ditto, but watch for "error" fields
bool sameAttributes(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignoreables);
- // attributes + from the same app/userid
- bool sameAttributesId(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignoreables);
+
+ void minMaxVar64(MediaAnalyticsItem &summ, const char *key, int64_t value);
static int PropSorter(const void *a, const void *b);
void sortProps(MediaAnalyticsItem *item);
diff --git a/services/mediaanalytics/MetricsSummarizerCodec.cpp b/services/mediaanalytics/MetricsSummarizerCodec.cpp
index 8c74782..6af3c9a 100644
--- a/services/mediaanalytics/MetricsSummarizerCodec.cpp
+++ b/services/mediaanalytics/MetricsSummarizerCodec.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "MetricsSummarizerCodec"
#include <utils/Log.h>
+#include <stdint.h>
+#include <inttypes.h>
#include <utils/threads.h>
#include <utils/Errors.h>
@@ -40,5 +42,4 @@
ALOGV("MetricsSummarizerCodec::MetricsSummarizerCodec");
}
-
} // namespace android
diff --git a/services/mediaanalytics/MetricsSummarizerPlayer.cpp b/services/mediaanalytics/MetricsSummarizerPlayer.cpp
index 5162059..f882cb9 100644
--- a/services/mediaanalytics/MetricsSummarizerPlayer.cpp
+++ b/services/mediaanalytics/MetricsSummarizerPlayer.cpp
@@ -51,37 +51,43 @@
setIgnorables(player_ignorable);
}
+// NB: this is also called for the first time -- so summation == item
+// Not sure if we need a flag for that or not.
+// In this particular mergeRecord() code -- we're' ok for this.
void MetricsSummarizerPlayer::mergeRecord(MediaAnalyticsItem &summation, MediaAnalyticsItem &item) {
ALOGV("MetricsSummarizerPlayer::mergeRecord()");
- //
- // we sum time & frames.
- // be careful about our special "-1" values that indicate 'unknown'
- // treat those as 0 [basically, not summing them into the totals].
+
int64_t duration = 0;
if (item.getInt64("android.media.mediaplayer.durationMs", &duration)) {
ALOGV("found durationMs of %" PRId64, duration);
- summation.addInt64("android.media.mediaplayer.durationMs",duration);
+ minMaxVar64(summation, "android.media.mediaplayer.durationMs", duration);
}
+
int64_t playing = 0;
- if (item.getInt64("android.media.mediaplayer.playingMs", &playing))
+ if (item.getInt64("android.media.mediaplayer.playingMs", &playing)) {
ALOGV("found playingMs of %" PRId64, playing);
- if (playing >= 0) {
- summation.addInt64("android.media.mediaplayer.playingMs",playing);
- }
+ }
+ if (playing >= 0) {
+ minMaxVar64(summation,"android.media.mediaplayer.playingMs",playing);
+ }
+
int64_t frames = 0;
- if (item.getInt64("android.media.mediaplayer.frames", &frames))
+ if (item.getInt64("android.media.mediaplayer.frames", &frames)) {
ALOGV("found framess of %" PRId64, frames);
- if (frames >= 0) {
- summation.addInt64("android.media.mediaplayer.frames",frames);
- }
+ }
+ if (frames >= 0) {
+ minMaxVar64(summation,"android.media.mediaplayer.frames",frames);
+ }
+
int64_t dropped = 0;
- if (item.getInt64("android.media.mediaplayer.dropped", &dropped))
+ if (item.getInt64("android.media.mediaplayer.dropped", &dropped)) {
ALOGV("found dropped of %" PRId64, dropped);
- if (dropped >= 0) {
- summation.addInt64("android.media.mediaplayer.dropped",dropped);
- }
+ }
+ if (dropped >= 0) {
+ minMaxVar64(summation,"android.media.mediaplayer.dropped",dropped);
+ }
}
} // namespace android
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index 6997b5a..faeb0a7 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -9,13 +9,8 @@
libgui \
libutils \
liblog \
- libstagefright_omx
-LOCAL_C_INCLUDES := \
- frameworks/av/include \
- frameworks/av/media/libstagefright \
- frameworks/av/media/libstagefright/include \
- frameworks/native/include \
- frameworks/native/include/media/openmax
+ libstagefright_omx \
+ libstagefright_xmlparser
LOCAL_MODULE:= libmediacodecservice
LOCAL_VENDOR_MODULE := true
LOCAL_32_BIT_ONLY := true
@@ -38,15 +33,10 @@
libhwbinder \
libhidltransport \
libstagefright_omx \
+ libstagefright_xmlparser \
android.hardware.media.omx@1.0 \
android.hidl.memory@1.0
-LOCAL_C_INCLUDES := \
- frameworks/av/include \
- frameworks/av/media/libstagefright \
- frameworks/av/media/libstagefright/include \
- frameworks/native/include \
- frameworks/native/include/media/openmax
LOCAL_MODULE := android.hardware.media.omx@1.0-service
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_VENDOR_MODULE := true
diff --git a/services/mediacodec/MediaCodecService.cpp b/services/mediacodec/MediaCodecService.cpp
index fc1e5d9..6b510c6 100644
--- a/services/mediacodec/MediaCodecService.cpp
+++ b/services/mediacodec/MediaCodecService.cpp
@@ -24,15 +24,25 @@
sp<IOMX> MediaCodecService::getOMX() {
- Mutex::Autolock autoLock(mLock);
+ Mutex::Autolock autoLock(mOMXLock);
if (mOMX.get() == NULL) {
- mOMX = new OMX;
+ mOMX = new OMX();
}
return mOMX;
}
+sp<IOMXStore> MediaCodecService::getOMXStore() {
+
+ Mutex::Autolock autoLock(mOMXStoreLock);
+
+ if (mOMXStore.get() == NULL) {
+ mOMXStore = new OMXStore();
+ }
+
+ return mOMXStore;
+}
status_t MediaCodecService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags)
diff --git a/services/mediacodec/MediaCodecService.h b/services/mediacodec/MediaCodecService.h
index d64debb..9301135 100644
--- a/services/mediacodec/MediaCodecService.h
+++ b/services/mediacodec/MediaCodecService.h
@@ -19,11 +19,13 @@
#include <binder/BinderService.h>
#include <media/IMediaCodecService.h>
-#include <include/OMX.h>
+#include <media/stagefright/omx/OMX.h>
+#include <media/stagefright/omx/OMXStore.h>
namespace android {
-class MediaCodecService : public BinderService<MediaCodecService>, public BnMediaCodecService
+class MediaCodecService : public BinderService<MediaCodecService>,
+ public BnMediaCodecService
{
friend class BinderService<MediaCodecService>; // for MediaCodecService()
public:
@@ -31,16 +33,20 @@
virtual ~MediaCodecService() { }
virtual void onFirstRef() { }
- static const char* getServiceName() { return "media.codec"; }
+ static const char* getServiceName() { return "media.codec"; }
- virtual sp<IOMX> getOMX();
+ virtual sp<IOMX> getOMX();
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags);
+ virtual sp<IOMXStore> getOMXStore();
+
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags);
private:
- Mutex mLock;
- sp<IOMX> mOMX;
+ Mutex mOMXLock;
+ sp<IOMX> mOMX;
+ Mutex mOMXStoreLock;
+ sp<IOMXStore> mOMXStore;
};
} // namespace android
diff --git a/services/mediacodec/OWNERS b/services/mediacodec/OWNERS
new file mode 100644
index 0000000..c716cce
--- /dev/null
+++ b/services/mediacodec/OWNERS
@@ -0,0 +1,2 @@
+jeffv@google.com
+marcone@google.com
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index c59944a..79d6da5 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -32,8 +32,8 @@
#include "minijail.h"
#include <hidl/HidlTransportSupport.h>
-#include <omx/1.0/Omx.h>
-#include <omx/1.0/OmxStore.h>
+#include <media/stagefright/omx/1.0/Omx.h>
+#include <media/stagefright/omx/1.0/OmxStore.h>
using namespace android;
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
index 6b30db6..2daa829 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -17,7 +17,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- MediaCasService.cpp \
MediaDrmService.cpp \
main_mediadrmserver.cpp
diff --git a/services/mediadrm/FactoryLoader.h b/services/mediadrm/FactoryLoader.h
deleted file mode 100644
index d7f1118..0000000
--- a/services/mediadrm/FactoryLoader.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (C) 2017 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 MEDIA_CAS_LOADER_H_
-#define MEDIA_CAS_LOADER_H_
-
-#include <dirent.h>
-#include <dlfcn.h>
-#include <media/SharedLibrary.h>
-#include <utils/KeyedVector.h>
-#include <utils/Mutex.h>
-
-namespace android {
-using namespace std;
-using namespace media;
-using namespace MediaCas;
-
-template <class T>
-class FactoryLoader {
-public:
- FactoryLoader(const char *name) :
- mFactory(NULL), mCreateFactoryFuncName(name) {}
-
- virtual ~FactoryLoader() { closeFactory(); }
-
- bool findFactoryForScheme(
- int32_t CA_system_id,
- sp<SharedLibrary> *library = NULL,
- T** factory = NULL);
-
- bool enumeratePlugins(vector<ParcelableCasPluginDescriptor>* results);
-
-private:
- typedef T*(*CreateFactoryFunc)();
-
- Mutex mMapLock;
- T* mFactory;
- const char *mCreateFactoryFuncName;
- sp<SharedLibrary> mLibrary;
- KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
- KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
-
- bool loadFactoryForSchemeFromPath(
- const String8 &path,
- int32_t CA_system_id,
- sp<SharedLibrary> *library,
- T** factory);
-
- bool queryPluginsFromPath(
- const String8 &path,
- vector<ParcelableCasPluginDescriptor>* results);
-
- bool openFactory(const String8 &path);
- void closeFactory();
-};
-
-template <class T>
-bool FactoryLoader<T>::findFactoryForScheme(
- int32_t CA_system_id, sp<SharedLibrary> *library, T** factory) {
- if (library != NULL) {
- library->clear();
- }
- if (factory != NULL) {
- *factory = NULL;
- }
-
- Mutex::Autolock autoLock(mMapLock);
-
- // first check cache
- ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
- if (index >= 0) {
- return loadFactoryForSchemeFromPath(
- mCASystemIdToLibraryPathMap[index],
- CA_system_id, library, factory);
- }
-
- // no luck, have to search
- String8 dirPath("/system/lib/mediacas");
- DIR* pDir = opendir(dirPath.string());
-
- if (pDir == NULL) {
- ALOGE("Failed to open plugin directory %s", dirPath.string());
- return false;
- }
-
- struct dirent* pEntry;
- while ((pEntry = readdir(pDir))) {
- String8 pluginPath = dirPath + "/" + pEntry->d_name;
- if (pluginPath.getPathExtension() == ".so") {
- if (loadFactoryForSchemeFromPath(
- pluginPath, CA_system_id, library, factory)) {
- mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
- closedir(pDir);
-
- return true;
- }
- }
- }
-
- closedir(pDir);
-
- ALOGE("Failed to find plugin");
- return false;
-}
-
-template <class T>
-bool FactoryLoader<T>::enumeratePlugins(
- vector<ParcelableCasPluginDescriptor>* results) {
- ALOGI("enumeratePlugins");
-
- results->clear();
-
- String8 dirPath("/system/lib/mediacas");
- DIR* pDir = opendir(dirPath.string());
-
- if (pDir == NULL) {
- ALOGE("Failed to open plugin directory %s", dirPath.string());
- return false;
- }
-
- Mutex::Autolock autoLock(mMapLock);
-
- struct dirent* pEntry;
- while ((pEntry = readdir(pDir))) {
- String8 pluginPath = dirPath + "/" + pEntry->d_name;
- if (pluginPath.getPathExtension() == ".so") {
- queryPluginsFromPath(pluginPath, results);
- }
- }
- return true;
-}
-
-template <class T>
-bool FactoryLoader<T>::loadFactoryForSchemeFromPath(
- const String8 &path, int32_t CA_system_id,
- sp<SharedLibrary> *library, T** factory) {
- closeFactory();
-
- if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
- closeFactory();
- return false;
- }
-
- if (library != NULL) {
- *library = mLibrary;
- }
- if (factory != NULL) {
- *factory = mFactory;
- }
- return true;
-}
-
-template <class T>
-bool FactoryLoader<T>::queryPluginsFromPath(
- const String8 &path, vector<ParcelableCasPluginDescriptor>* results) {
- closeFactory();
-
- vector<CasPluginDescriptor> descriptors;
- if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
- closeFactory();
- return false;
- }
-
- for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
- results->push_back(ParcelableCasPluginDescriptor(
- it->CA_system_id, it->name));
- }
- return true;
-}
-
-template <class T>
-bool FactoryLoader<T>::openFactory(const String8 &path) {
- // get strong pointer to open shared library
- ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
- if (index >= 0) {
- mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
- } else {
- index = mLibraryPathToOpenLibraryMap.add(path, NULL);
- }
-
- if (!mLibrary.get()) {
- mLibrary = new SharedLibrary(path);
- if (!*mLibrary) {
- return false;
- }
-
- mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
- }
-
- CreateFactoryFunc createFactory =
- (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
- if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
- return false;
- }
- return true;
-}
-
-template <class T>
-void FactoryLoader<T>::closeFactory() {
- delete mFactory;
- mFactory = NULL;
- mLibrary.clear();
-}
-
-} // namespace android
-
-#endif // MEDIA_CAS_LOADER_H_
diff --git a/services/mediadrm/MediaCasService.cpp b/services/mediadrm/MediaCasService.cpp
deleted file mode 100644
index c111283..0000000
--- a/services/mediadrm/MediaCasService.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2017 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 "MediaCasService"
-
-#include <binder/IServiceManager.h>
-#include <media/cas/CasAPI.h>
-#include <media/cas/DescramblerAPI.h>
-#include <media/CasImpl.h>
-#include <media/DescramblerImpl.h>
-#include <utils/Log.h>
-#include <utils/List.h>
-#include "MediaCasService.h"
-#include <android/media/ICasListener.h>
-
-namespace android {
-
-//static
-void MediaCasService::instantiate() {
- defaultServiceManager()->addService(
- String16("media.cas"), new MediaCasService());
-}
-
-MediaCasService::MediaCasService() :
- mCasLoader(new FactoryLoader<CasFactory>("createCasFactory")),
- mDescramblerLoader(new FactoryLoader<DescramblerFactory>(
- "createDescramblerFactory")) {
-}
-
-MediaCasService::~MediaCasService() {
- delete mCasLoader;
- delete mDescramblerLoader;
-}
-
-Status MediaCasService::enumeratePlugins(
- vector<ParcelableCasPluginDescriptor>* results) {
- ALOGV("enumeratePlugins");
-
- mCasLoader->enumeratePlugins(results);
-
- return Status::ok();
-}
-
-Status MediaCasService::isSystemIdSupported(
- int32_t CA_system_id, bool* result) {
- ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
-
- *result = mCasLoader->findFactoryForScheme(CA_system_id);
-
- return Status::ok();
-}
-
-Status MediaCasService::createPlugin(
- int32_t CA_system_id,
- const sp<ICasListener> &listener,
- sp<ICas>* result) {
- ALOGV("createPlugin: CA_system_id=%d", CA_system_id);
-
- result->clear();
-
- CasFactory *factory;
- sp<SharedLibrary> library;
- if (mCasLoader->findFactoryForScheme(CA_system_id, &library, &factory)) {
- CasPlugin *plugin = NULL;
- sp<CasImpl> casImpl = new CasImpl(listener);
- if (factory->createPlugin(CA_system_id, (uint64_t)casImpl.get(),
- &CasImpl::OnEvent, &plugin) == OK && plugin != NULL) {
- casImpl->init(library, plugin);
- *result = casImpl;
- }
- }
-
- return Status::ok();
-}
-
-Status MediaCasService::isDescramblerSupported(
- int32_t CA_system_id, bool* result) {
- ALOGV("isDescramblerSupported: CA_system_id=%d", CA_system_id);
-
- *result = mDescramblerLoader->findFactoryForScheme(CA_system_id);
-
- return Status::ok();
-}
-
-Status MediaCasService::createDescrambler(
- int32_t CA_system_id, sp<IDescrambler>* result) {
- ALOGV("createDescrambler: CA_system_id=%d", CA_system_id);
-
- result->clear();
-
- DescramblerFactory *factory;
- sp<SharedLibrary> library;
- if (mDescramblerLoader->findFactoryForScheme(
- CA_system_id, &library, &factory)) {
- DescramblerPlugin *plugin = NULL;
- if (factory->createPlugin(CA_system_id, &plugin) == OK
- && plugin != NULL) {
- *result = new DescramblerImpl(library, plugin);
- }
- }
-
- return Status::ok();
-}
-
-} // namespace android
diff --git a/services/mediadrm/MediaCasService.h b/services/mediadrm/MediaCasService.h
deleted file mode 100644
index cb828f2..0000000
--- a/services/mediadrm/MediaCasService.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2017 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 MEDIA_CAS_SERVICE_H_
-#define MEDIA_CAS_SERVICE_H_
-
-#include <android/media/BnMediaCasService.h>
-
-#include "FactoryLoader.h"
-
-namespace android {
-using binder::Status;
-struct CasFactory;
-struct DescramblerFactory;
-
-class MediaCasService : public BnMediaCasService {
-public:
- static void instantiate();
-
- virtual Status enumeratePlugins(
- vector<ParcelableCasPluginDescriptor>* results) override;
-
- virtual Status isSystemIdSupported(
- int32_t CA_system_id, bool* result) override;
-
- virtual Status createPlugin(
- int32_t CA_system_id,
- const sp<ICasListener> &listener,
- sp<ICas>* result) override;
-
- virtual Status isDescramblerSupported(
- int32_t CA_system_id, bool* result) override;
-
- virtual Status createDescrambler(
- int32_t CA_system_id, sp<IDescrambler>* result) override;
-
-private:
- FactoryLoader<CasFactory> *mCasLoader;
- FactoryLoader<DescramblerFactory> *mDescramblerLoader;
-
- MediaCasService();
- virtual ~MediaCasService();
-};
-
-} // namespace android
-
-#endif // MEDIA_CAS_SERVICE_H_
diff --git a/services/mediadrm/OWNERS b/services/mediadrm/OWNERS
new file mode 100644
index 0000000..6d3b533
--- /dev/null
+++ b/services/mediadrm/OWNERS
@@ -0,0 +1,2 @@
+jtinker@google.com
+marcone@google.com
diff --git a/services/mediadrm/main_mediadrmserver.cpp b/services/mediadrm/main_mediadrmserver.cpp
index b685ae0..b767b8c 100644
--- a/services/mediadrm/main_mediadrmserver.cpp
+++ b/services/mediadrm/main_mediadrmserver.cpp
@@ -27,7 +27,6 @@
#include <cutils/properties.h>
#include <utils/Log.h>
#include "MediaDrmService.h"
-#include "MediaCasService.h"
using namespace android;
@@ -39,7 +38,6 @@
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
MediaDrmService::instantiate();
- MediaCasService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
diff --git a/services/mediaextractor/OWNERS b/services/mediaextractor/OWNERS
new file mode 100644
index 0000000..c716cce
--- /dev/null
+++ b/services/mediaextractor/OWNERS
@@ -0,0 +1,2 @@
+jeffv@google.com
+marcone@google.com
diff --git a/services/medialog/OWNERS b/services/medialog/OWNERS
new file mode 100644
index 0000000..fb8b8ee
--- /dev/null
+++ b/services/medialog/OWNERS
@@ -0,0 +1,3 @@
+elaurent@google.com
+gkasten@android.com
+hunga@google.com
diff --git a/services/mediaresourcemanager/OWNERS b/services/mediaresourcemanager/OWNERS
new file mode 100644
index 0000000..82abf8f
--- /dev/null
+++ b/services/mediaresourcemanager/OWNERS
@@ -0,0 +1 @@
+dwkang@google.com
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index ec2f5b9..f996f74 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -26,6 +26,10 @@
#include <utility/AAudioUtilities.h>
#include "AAudioEndpointManager.h"
+#include "AAudioServiceEndpointShared.h"
+#include "AAudioServiceEndpointMMAP.h"
+#include "AAudioServiceEndpointCapture.h"
+#include "AAudioServiceEndpointPlay.h"
using namespace android;
using namespace aaudio;
@@ -34,159 +38,237 @@
AAudioEndpointManager::AAudioEndpointManager()
: Singleton<AAudioEndpointManager>()
- , mInputs()
- , mOutputs() {
+ , mSharedStreams()
+ , mExclusiveStreams() {
}
std::string AAudioEndpointManager::dump() const {
std::stringstream result;
- const bool isLocked = AAudio_tryUntilTrue(
- [this]()->bool { return mLock.try_lock(); } /* f */,
- 50 /* times */,
- 20 /* sleepMs */);
- if (!isLocked) {
- result << "EndpointManager may be deadlocked\n";
- }
+ int index = 0;
result << "AAudioEndpointManager:" << "\n";
- size_t inputs = mInputs.size();
- result << "Input Endpoints: " << inputs << "\n";
- for (const auto &input : mInputs) {
- result << " Input: " << input->dump() << "\n";
+
+ const bool isSharedLocked = AAudio_tryUntilTrue(
+ [this]()->bool { return mSharedLock.try_lock(); } /* f */,
+ 50 /* times */,
+ 20 /* sleepMs */);
+ if (!isSharedLocked) {
+ result << "AAudioEndpointManager Shared may be deadlocked\n";
}
- size_t outputs = mOutputs.size();
- result << "Output Endpoints: " << outputs << "\n";
- for (const auto &output : mOutputs) {
- result << " Output: " << output->dump() << "\n";
+ {
+ const bool isExclusiveLocked = AAudio_tryUntilTrue(
+ [this]() -> bool { return mExclusiveLock.try_lock(); } /* f */,
+ 50 /* times */,
+ 20 /* sleepMs */);
+ if (!isExclusiveLocked) {
+ result << "AAudioEndpointManager Exclusive may be deadlocked\n";
+ }
+
+ result << "Exclusive MMAP Endpoints: " << mExclusiveStreams.size() << "\n";
+ index = 0;
+ for (const auto &output : mExclusiveStreams) {
+ result << " #" << index++ << ":";
+ result << output->dump() << "\n";
+ }
+
+ if (isExclusiveLocked) {
+ mExclusiveLock.unlock();
+ }
}
- if (isLocked) {
- mLock.unlock();
+ result << "Shared Endpoints: " << mSharedStreams.size() << "\n";
+ index = 0;
+ for (const auto &input : mSharedStreams) {
+ result << " #" << index++ << ":";
+ result << input->dump() << "\n";
+ }
+
+ if (isSharedLocked) {
+ mSharedLock.unlock();
}
return result.str();
}
-AAudioServiceEndpoint *AAudioEndpointManager::openEndpoint(AAudioService &audioService,
- const AAudioStreamConfiguration& configuration, aaudio_direction_t direction) {
- AAudioServiceEndpoint *endpoint = nullptr;
- AAudioServiceEndpointCapture *capture = nullptr;
- AAudioServiceEndpointPlay *player = nullptr;
- std::lock_guard<std::mutex> lock(mLock);
+
+// Try to find an existing endpoint.
+sp<AAudioServiceEndpoint> AAudioEndpointManager::findExclusiveEndpoint_l(
+ const AAudioStreamConfiguration &configuration) {
+ sp<AAudioServiceEndpoint> endpoint;
+ for (const auto ep : mExclusiveStreams) {
+ if (ep->matches(configuration)) {
+ endpoint = ep;
+ break;
+ }
+ }
+
+ ALOGV("AAudioEndpointManager.findExclusiveEndpoint_l(), found %p for device = %d",
+ endpoint.get(), configuration.getDeviceId());
+ return endpoint;
+}
+
+// Try to find an existing endpoint.
+sp<AAudioServiceEndpointShared> AAudioEndpointManager::findSharedEndpoint_l(
+ const AAudioStreamConfiguration &configuration) {
+ sp<AAudioServiceEndpointShared> endpoint;
+ for (const auto ep : mSharedStreams) {
+ if (ep->matches(configuration)) {
+ endpoint = ep;
+ break;
+ }
+ }
+
+ ALOGV("AAudioEndpointManager.findSharedEndpoint_l(), found %p for device = %d",
+ endpoint.get(), configuration.getDeviceId());
+ return endpoint;
+}
+
+sp<AAudioServiceEndpoint> AAudioEndpointManager::openEndpoint(AAudioService &audioService,
+ const aaudio::AAudioStreamRequest &request,
+ aaudio_sharing_mode_t sharingMode) {
+ if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) {
+ return openExclusiveEndpoint(audioService, request);
+ } else {
+ return openSharedEndpoint(audioService, request);
+ }
+}
+
+sp<AAudioServiceEndpoint> AAudioEndpointManager::openExclusiveEndpoint(
+ AAudioService &aaudioService __unused,
+ const aaudio::AAudioStreamRequest &request) {
+
+ std::lock_guard<std::mutex> lock(mExclusiveLock);
+
+ const AAudioStreamConfiguration &configuration = request.getConstantConfiguration();
// Try to find an existing endpoint.
+ sp<AAudioServiceEndpoint> endpoint = findExclusiveEndpoint_l(configuration);
+ // If we find an existing one then this one cannot be exclusive.
+ if (endpoint.get() != nullptr) {
+ ALOGE("AAudioEndpointManager.openExclusiveEndpoint() already in use");
+ // Already open so do not allow a second stream.
+ return nullptr;
+ } else {
+ sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP();
+ ALOGE("AAudioEndpointManager.openEndpoint(),created MMAP %p", endpointMMap.get());
+ endpoint = endpointMMap;
-
- switch (direction) {
- case AAUDIO_DIRECTION_INPUT:
- for (AAudioServiceEndpoint *ep : mInputs) {
- if (ep->matches(configuration)) {
- endpoint = ep;
- break;
- }
- }
- break;
- case AAUDIO_DIRECTION_OUTPUT:
- for (AAudioServiceEndpoint *ep : mOutputs) {
- if (ep->matches(configuration)) {
- endpoint = ep;
- break;
- }
- }
- break;
- default:
- assert(false); // There are only two possible directions.
- break;
- }
- ALOGD("AAudioEndpointManager::openEndpoint(), found %p for device = %d, dir = %d",
- endpoint, configuration.getDeviceId(), (int)direction);
-
- // If we can't find an existing one then open a new one.
- if (endpoint == nullptr) {
- // we must call openStream with audioserver identity
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- switch(direction) {
- case AAUDIO_DIRECTION_INPUT:
- capture = new AAudioServiceEndpointCapture(audioService);
- endpoint = capture;
- break;
- case AAUDIO_DIRECTION_OUTPUT:
- player = new AAudioServiceEndpointPlay(audioService);
- endpoint = player;
- break;
- default:
- break;
+ aaudio_result_t result = endpoint->open(request);
+ if (result != AAUDIO_OK) {
+ ALOGE("AAudioEndpointManager.openEndpoint(), open failed");
+ endpoint.clear();
+ } else {
+ mExclusiveStreams.push_back(endpointMMap);
}
- if (endpoint != nullptr) {
- aaudio_result_t result = endpoint->open(configuration);
- if (result != AAUDIO_OK) {
- ALOGE("AAudioEndpointManager::findEndpoint(), open failed");
- delete endpoint;
- endpoint = nullptr;
- } else {
- switch(direction) {
- case AAUDIO_DIRECTION_INPUT:
- mInputs.push_back(capture);
- break;
- case AAUDIO_DIRECTION_OUTPUT:
- mOutputs.push_back(player);
- break;
- default:
- break;
- }
- }
- }
- ALOGD("AAudioEndpointManager::openEndpoint(), created %p for device = %d, dir = %d",
- endpoint, configuration.getDeviceId(), (int)direction);
- IPCThreadState::self()->restoreCallingIdentity(token);
+ ALOGD("AAudioEndpointManager.openEndpoint(), created %p for device = %d",
+ endpoint.get(), configuration.getDeviceId());
}
- if (endpoint != nullptr) {
- ALOGD("AAudioEndpointManager::openEndpoint(), sampleRate = %d, framesPerBurst = %d",
- endpoint->getSampleRate(), endpoint->getFramesPerBurst());
+ if (endpoint.get() != nullptr) {
// Increment the reference count under this lock.
- endpoint->setReferenceCount(endpoint->getReferenceCount() + 1);
+ endpoint->setOpenCount(endpoint->getOpenCount() + 1);
}
return endpoint;
}
-void AAudioEndpointManager::closeEndpoint(AAudioServiceEndpoint *serviceEndpoint) {
- std::lock_guard<std::mutex> lock(mLock);
- if (serviceEndpoint == nullptr) {
- return;
- }
+sp<AAudioServiceEndpoint> AAudioEndpointManager::openSharedEndpoint(
+ AAudioService &aaudioService,
+ const aaudio::AAudioStreamRequest &request) {
- // Decrement the reference count under this lock.
- int32_t newRefCount = serviceEndpoint->getReferenceCount() - 1;
- serviceEndpoint->setReferenceCount(newRefCount);
- ALOGD("AAudioEndpointManager::closeEndpoint(%p) newRefCount = %d",
- serviceEndpoint, newRefCount);
+ std::lock_guard<std::mutex> lock(mSharedLock);
- // If no longer in use then close and delete it.
- if (newRefCount <= 0) {
- aaudio_direction_t direction = serviceEndpoint->getDirection();
- // Track endpoints based on requested deviceId because UNSPECIFIED
- // can change to a specific device after opening.
- int32_t deviceId = serviceEndpoint->getRequestedDeviceId();
+ const AAudioStreamConfiguration &configuration = request.getConstantConfiguration();
+ aaudio_direction_t direction = configuration.getDirection();
+ // Try to find an existing endpoint.
+ sp<AAudioServiceEndpointShared> endpoint = findSharedEndpoint_l(configuration);
+
+ // If we can't find an existing one then open a new one.
+ if (endpoint.get() == nullptr) {
+ // we must call openStream with audioserver identity
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
switch (direction) {
case AAUDIO_DIRECTION_INPUT:
- mInputs.erase(
- std::remove(mInputs.begin(), mInputs.end(), serviceEndpoint), mInputs.end());
+ endpoint = new AAudioServiceEndpointCapture(aaudioService);
break;
case AAUDIO_DIRECTION_OUTPUT:
- mOutputs.erase(
- std::remove(mOutputs.begin(), mOutputs.end(), serviceEndpoint), mOutputs.end());
+ endpoint = new AAudioServiceEndpointPlay(aaudioService);
break;
default:
break;
}
+ if (endpoint.get() != nullptr) {
+ aaudio_result_t result = endpoint->open(request);
+ if (result != AAUDIO_OK) {
+ ALOGE("AAudioEndpointManager.openEndpoint(), open failed");
+ endpoint.clear();
+ } else {
+ mSharedStreams.push_back(endpoint);
+ }
+ }
+ ALOGD("AAudioEndpointManager.openSharedEndpoint(), created %p for device = %d, dir = %d",
+ endpoint.get(), configuration.getDeviceId(), (int)direction);
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ }
+
+ if (endpoint.get() != nullptr) {
+ // Increment the reference count under this lock.
+ endpoint->setOpenCount(endpoint->getOpenCount() + 1);
+ }
+ return endpoint;
+}
+
+void AAudioEndpointManager::closeEndpoint(sp<AAudioServiceEndpoint>serviceEndpoint) {
+ if (serviceEndpoint->getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
+ return closeExclusiveEndpoint(serviceEndpoint);
+ } else {
+ return closeSharedEndpoint(serviceEndpoint);
+ }
+}
+
+void AAudioEndpointManager::closeExclusiveEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint) {
+ if (serviceEndpoint.get() == nullptr) {
+ return;
+ }
+
+ // Decrement the reference count under this lock.
+ std::lock_guard<std::mutex> lock(mExclusiveLock);
+ int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
+ serviceEndpoint->setOpenCount(newRefCount);
+
+ // If no longer in use then close and delete it.
+ if (newRefCount <= 0) {
+ mExclusiveStreams.erase(
+ std::remove(mExclusiveStreams.begin(), mExclusiveStreams.end(), serviceEndpoint),
+ mExclusiveStreams.end());
+
serviceEndpoint->close();
- ALOGD("AAudioEndpointManager::closeEndpoint() delete %p for device %d, dir = %d",
- serviceEndpoint, deviceId, (int)direction);
- delete serviceEndpoint;
+ ALOGD("AAudioEndpointManager::closeExclusiveEndpoint() %p for device %d",
+ serviceEndpoint.get(), serviceEndpoint->getDeviceId());
+ }
+}
+
+void AAudioEndpointManager::closeSharedEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint) {
+ if (serviceEndpoint.get() == nullptr) {
+ return;
+ }
+
+ // Decrement the reference count under this lock.
+ std::lock_guard<std::mutex> lock(mSharedLock);
+ int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
+ serviceEndpoint->setOpenCount(newRefCount);
+
+ // If no longer in use then close and delete it.
+ if (newRefCount <= 0) {
+ mSharedStreams.erase(
+ std::remove(mSharedStreams.begin(), mSharedStreams.end(), serviceEndpoint),
+ mSharedStreams.end());
+
+ serviceEndpoint->close();
+ ALOGD("AAudioEndpointManager::closeSharedEndpoint() %p for device %d",
+ serviceEndpoint.get(), serviceEndpoint->getDeviceId());
}
}
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index 2511b2f..32c8454 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -24,11 +24,12 @@
#include "binding/AAudioServiceMessage.h"
#include "AAudioServiceEndpoint.h"
#include "AAudioServiceEndpointCapture.h"
+#include "AAudioServiceEndpointMMAP.h"
#include "AAudioServiceEndpointPlay.h"
namespace aaudio {
-class AAudioEndpointManager : public android::Singleton<AAudioEndpointManager>{
+class AAudioEndpointManager : public android::Singleton<AAudioEndpointManager> {
public:
AAudioEndpointManager();
~AAudioEndpointManager() = default;
@@ -49,22 +50,42 @@
* Find a service endpoint for the given deviceId and direction.
* If an endpoint does not already exist then try to create one.
*
- * @param deviceId
- * @param direction
- * @return endpoint or nullptr
+ * @param audioService
+ * @param request
+ * @param sharingMode
+ * @return endpoint or null
*/
- AAudioServiceEndpoint *openEndpoint(android::AAudioService &audioService,
- const AAudioStreamConfiguration& configuration,
- aaudio_direction_t direction);
+ android::sp<AAudioServiceEndpoint> openEndpoint(android::AAudioService &audioService,
+ const aaudio::AAudioStreamRequest &request,
+ aaudio_sharing_mode_t sharingMode);
- void closeEndpoint(AAudioServiceEndpoint *serviceEndpoint);
+ void closeEndpoint(android::sp<AAudioServiceEndpoint> serviceEndpoint);
private:
+ android::sp<AAudioServiceEndpoint> openExclusiveEndpoint(android::AAudioService &aaudioService,
+ const aaudio::AAudioStreamRequest &request);
- mutable std::mutex mLock;
+ android::sp<AAudioServiceEndpoint> openSharedEndpoint(android::AAudioService &aaudioService,
+ const aaudio::AAudioStreamRequest &request);
- std::vector<AAudioServiceEndpointCapture *> mInputs;
- std::vector<AAudioServiceEndpointPlay *> mOutputs;
+ android::sp<AAudioServiceEndpoint> findExclusiveEndpoint_l(
+ const AAudioStreamConfiguration& configuration);
+
+ android::sp<AAudioServiceEndpointShared> findSharedEndpoint_l(
+ const AAudioStreamConfiguration& configuration);
+
+ void closeExclusiveEndpoint(android::sp<AAudioServiceEndpoint> serviceEndpoint);
+ void closeSharedEndpoint(android::sp<AAudioServiceEndpoint> serviceEndpoint);
+
+ // Use separate locks because opening a Shared endpoint requires opening an Exclusive one.
+ // That could cause a recursive lock.
+ // Lock mSharedLock before mExclusiveLock.
+ // it is OK to only lock mExclusiveLock.
+ mutable std::mutex mSharedLock;
+ std::vector<android::sp<AAudioServiceEndpointShared>> mSharedStreams;
+
+ mutable std::mutex mExclusiveLock;
+ std::vector<android::sp<AAudioServiceEndpointMMAP>> mExclusiveStreams;
};
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 3992719..5a3488d 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -18,9 +18,9 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <iomanip>
+#include <iostream>
#include <sstream>
-//#include <time.h>
-//#include <pthread.h>
#include <aaudio/AAudio.h>
#include <mediautils/SchedulingPolicyService.h>
@@ -35,18 +35,13 @@
#include "AAudioServiceStreamMMAP.h"
#include "binding/IAAudioService.h"
#include "ServiceUtilities.h"
-#include "utility/HandleTracker.h"
using namespace android;
using namespace aaudio;
#define MAX_STREAMS_PER_PROCESS 8
-typedef enum
-{
- AAUDIO_HANDLE_TYPE_STREAM
-} aaudio_service_handle_type_t;
-static_assert(AAUDIO_HANDLE_TYPE_STREAM < HANDLE_TRACKER_MAX_TYPES, "Too many handle types.");
+using android::AAudioService;
android::AAudioService::AAudioService()
: BnAAudioService() {
@@ -70,7 +65,8 @@
result = ss.str();
ALOGW("%s", result.c_str());
} else {
- result = mHandleTracker.dump()
+ result = "------------ AAudio Service ------------\n"
+ + mStreamTracker.dump()
+ AAudioClientTracker::getInstance().dump()
+ AAudioEndpointManager::getInstance().dump();
}
@@ -114,23 +110,20 @@
mAudioClient.clientUid == IPCThreadState::self()->getCallingUid()) {
inService = request.isInService();
}
- serviceStream = new AAudioServiceStreamMMAP(mAudioClient, inService);
- result = serviceStream->open(request, configurationOutput);
+ serviceStream = new AAudioServiceStreamMMAP(*this, inService);
+ result = serviceStream->open(request);
if (result != AAUDIO_OK) {
- // fall back to using a shared stream
+ // Clear it so we can possibly fall back to using a shared stream.
ALOGW("AAudioService::openStream(), could not open in EXCLUSIVE mode");
serviceStream.clear();
- } else {
- configurationOutput.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
}
}
// if SHARED requested or if EXCLUSIVE failed
if (sharingMode == AAUDIO_SHARING_MODE_SHARED
- || (serviceStream == nullptr && !sharingModeMatchRequired)) {
+ || (serviceStream.get() == nullptr && !sharingModeMatchRequired)) {
serviceStream = new AAudioServiceStreamShared(*this);
- result = serviceStream->open(request, configurationOutput);
- configurationOutput.setSharingMode(AAUDIO_SHARING_MODE_SHARED);
+ result = serviceStream->open(request);
}
if (result != AAUDIO_OK) {
@@ -139,17 +132,12 @@
result, AAudio_convertResultToText(result));
return result;
} else {
- aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream.get());
- if (handle < 0) {
- ALOGE("AAudioService::openStream(): handle table full");
- serviceStream->close();
- serviceStream.clear();
- } else {
- ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
- serviceStream->setHandle(handle);
- pid_t pid = request.getProcessId();
- AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
- }
+ aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
+ ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
+ serviceStream->setHandle(handle);
+ pid_t pid = request.getProcessId();
+ AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
+ configurationOutput.copyFrom(*serviceStream);
return handle;
}
}
@@ -157,30 +145,32 @@
aaudio_result_t AAudioService::closeStream(aaudio_handle_t streamHandle) {
// Check permission and ownership first.
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
- if (serviceStream == nullptr) {
- ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
+ if (serviceStream.get() == nullptr) {
+ ALOGE("AAudioService::closeStream(0x%0x), illegal stream handle", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);
// Remove handle from tracker so that we cannot look up the raw address any more.
- serviceStream = (AAudioServiceStreamBase *)
- mHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM,
- streamHandle);
- if (serviceStream != nullptr) {
+ // removeStreamByHandle() uses a lock so that if there are two simultaneous closes
+ // then only one will get the pointer and do the close.
+ serviceStream = mStreamTracker.removeStreamByHandle(streamHandle);
+ if (serviceStream.get() != nullptr) {
serviceStream->close();
pid_t pid = serviceStream->getOwnerProcessId();
AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
return AAUDIO_OK;
+ } else {
+ ALOGW("AAudioService::closeStream(0x%0x) being handled by another thread", streamHandle);
+ return AAUDIO_ERROR_INVALID_HANDLE;
}
- return AAUDIO_ERROR_INVALID_HANDLE;
}
-AAudioServiceStreamBase *AAudioService::convertHandleToServiceStream(
- aaudio_handle_t streamHandle) const {
- AAudioServiceStreamBase *serviceStream = (AAudioServiceStreamBase *)
- mHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM, (aaudio_handle_t)streamHandle);
- if (serviceStream != nullptr) {
+
+sp<AAudioServiceStreamBase> AAudioService::convertHandleToServiceStream(
+ aaudio_handle_t streamHandle) {
+ sp<AAudioServiceStreamBase> serviceStream = mStreamTracker.getStreamByHandle(streamHandle);
+ if (serviceStream.get() != nullptr) {
// Only allow owner or the aaudio service to access the stream.
const uid_t callingUserId = IPCThreadState::self()->getCallingUid();
const uid_t ownerUserId = serviceStream->getOwnerUserId();
@@ -200,30 +190,30 @@
aaudio_result_t AAudioService::getStreamDescription(
aaudio_handle_t streamHandle,
aaudio::AudioEndpointParcelable &parcelable) {
- AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- if (serviceStream == nullptr) {
+ sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ if (serviceStream.get() == nullptr) {
ALOGE("AAudioService::getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
+
aaudio_result_t result = serviceStream->getDescription(parcelable);
// parcelable.dump();
return result;
}
aaudio_result_t AAudioService::startStream(aaudio_handle_t streamHandle) {
- AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- if (serviceStream == nullptr) {
+ sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ if (serviceStream.get() == nullptr) {
ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
- aaudio_result_t result = serviceStream->start();
- return result;
+ return serviceStream->start();
}
aaudio_result_t AAudioService::pauseStream(aaudio_handle_t streamHandle) {
- AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- if (serviceStream == nullptr) {
+ sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ if (serviceStream.get() == nullptr) {
ALOGE("AAudioService::pauseStream(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
@@ -232,9 +222,9 @@
}
aaudio_result_t AAudioService::stopStream(aaudio_handle_t streamHandle) {
- AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- if (serviceStream == nullptr) {
- ALOGE("AAudioService::pauseStream(), illegal stream handle = 0x%0x", streamHandle);
+ sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ if (serviceStream.get() == nullptr) {
+ ALOGE("AAudioService::stopStream(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
aaudio_result_t result = serviceStream->stop();
@@ -242,8 +232,8 @@
}
aaudio_result_t AAudioService::flushStream(aaudio_handle_t streamHandle) {
- AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- if (serviceStream == nullptr) {
+ sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ if (serviceStream.get() == nullptr) {
ALOGE("AAudioService::flushStream(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
@@ -253,8 +243,8 @@
aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle,
pid_t clientThreadId,
int64_t periodNanoseconds) {
- AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- if (serviceStream == nullptr) {
+ sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ if (serviceStream.get() == nullptr) {
ALOGE("AAudioService::registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
@@ -278,8 +268,8 @@
aaudio_result_t AAudioService::unregisterAudioThread(aaudio_handle_t streamHandle,
pid_t clientThreadId) {
- AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- if (serviceStream == nullptr) {
+ sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ if (serviceStream.get() == nullptr) {
ALOGE("AAudioService::unregisterAudioThread(), illegal stream handle = 0x%0x",
streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
@@ -295,8 +285,8 @@
aaudio_result_t AAudioService::startClient(aaudio_handle_t streamHandle,
const android::AudioClient& client,
audio_port_handle_t *clientHandle) {
- AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- if (serviceStream == nullptr) {
+ sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ if (serviceStream.get() == nullptr) {
ALOGE("AAudioService::startClient(), illegal stream handle = 0x%0x",
streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
@@ -306,8 +296,8 @@
aaudio_result_t AAudioService::stopClient(aaudio_handle_t streamHandle,
audio_port_handle_t clientHandle) {
- AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
- if (serviceStream == nullptr) {
+ sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ if (serviceStream.get() == nullptr) {
ALOGE("AAudioService::stopClient(), illegal stream handle = 0x%0x",
streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index 8421efc..eef0824 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -24,11 +24,13 @@
#include <media/AudioClient.h>
#include <aaudio/AAudio.h>
-#include "utility/HandleTracker.h"
-#include "binding/IAAudioService.h"
+
+#include "binding/AAudioCommon.h"
#include "binding/AAudioServiceInterface.h"
+#include "binding/IAAudioService.h"
#include "AAudioServiceStreamBase.h"
+#include "AAudioStreamTracker.h"
namespace android {
@@ -49,45 +51,53 @@
virtual void registerClient(const sp<IAAudioClient>& client);
- virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
- aaudio::AAudioStreamConfiguration &configurationOutput);
+ aaudio::aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+ aaudio::AAudioStreamConfiguration &configurationOutput)
+ override;
- virtual aaudio_result_t closeStream(aaudio_handle_t streamHandle);
+ aaudio_result_t closeStream(aaudio::aaudio_handle_t streamHandle) override;
- virtual aaudio_result_t getStreamDescription(
- aaudio_handle_t streamHandle,
- aaudio::AudioEndpointParcelable &parcelable);
+ aaudio_result_t getStreamDescription(
+ aaudio::aaudio_handle_t streamHandle,
+ aaudio::AudioEndpointParcelable &parcelable) override;
- virtual aaudio_result_t startStream(aaudio_handle_t streamHandle);
+ aaudio_result_t startStream(aaudio::aaudio_handle_t streamHandle) override;
- virtual aaudio_result_t pauseStream(aaudio_handle_t streamHandle);
+ aaudio_result_t pauseStream(aaudio::aaudio_handle_t streamHandle) override;
- virtual aaudio_result_t stopStream(aaudio_handle_t streamHandle);
+ aaudio_result_t stopStream(aaudio::aaudio_handle_t streamHandle) override;
- virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle);
+ aaudio_result_t flushStream(aaudio::aaudio_handle_t streamHandle) override;
- virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+ aaudio_result_t registerAudioThread(aaudio::aaudio_handle_t streamHandle,
pid_t tid,
- int64_t periodNanoseconds) ;
+ int64_t periodNanoseconds) override;
- virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
- pid_t tid);
+ aaudio_result_t unregisterAudioThread(aaudio::aaudio_handle_t streamHandle,
+ pid_t tid) override;
- virtual aaudio_result_t startClient(aaudio_handle_t streamHandle,
+ aaudio_result_t startClient(aaudio::aaudio_handle_t streamHandle,
const android::AudioClient& client,
- audio_port_handle_t *clientHandle);
+ audio_port_handle_t *clientHandle) override;
- virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle,
- audio_port_handle_t clientHandle);
+ aaudio_result_t stopClient(aaudio::aaudio_handle_t streamHandle,
+ audio_port_handle_t clientHandle) override;
private:
- aaudio::AAudioServiceStreamBase *convertHandleToServiceStream(aaudio_handle_t streamHandle) const;
+ /**
+ * Lookup stream and then validate access to the stream.
+ * @param streamHandle
+ * @return
+ */
+ sp<aaudio::AAudioServiceStreamBase> convertHandleToServiceStream(
+ aaudio::aaudio_handle_t streamHandle);
- HandleTracker mHandleTracker;
android::AudioClient mAudioClient;
+ aaudio::AAudioStreamTracker mStreamTracker;
+
enum constants {
DEFAULT_AUDIO_PRIORITY = 2
};
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 0f863fe..3095bc9 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -33,17 +33,14 @@
#include "core/AudioStreamBuilder.h"
#include "AAudioServiceEndpoint.h"
#include "AAudioServiceStreamShared.h"
+#include "AAudioServiceEndpointShared.h"
using namespace android; // TODO just import names needed
using namespace aaudio; // TODO just import names needed
-#define MIN_TIMEOUT_NANOS (1000 * AAUDIO_NANOS_PER_MILLISECOND)
-
-// Wait at least this many times longer than the operation should take.
-#define MIN_TIMEOUT_OPERATIONS 4
-
-// This is the maximum size in frames. The effective size can be tuned smaller at runtime.
-#define DEFAULT_BUFFER_CAPACITY (48 * 8)
+AAudioServiceEndpoint::~AAudioServiceEndpoint() {
+ ALOGD("AAudioServiceEndpoint::~AAudioServiceEndpoint() destroying endpoint %p", this);
+}
std::string AAudioServiceEndpoint::dump() const {
std::stringstream result;
@@ -53,19 +50,20 @@
50 /* times */,
20 /* sleepMs */);
if (!isLocked) {
- result << "EndpointManager may be deadlocked\n";
+ result << "AAudioServiceEndpoint may be deadlocked\n";
}
- AudioStreamInternal *stream = mStreamInternal;
- if (stream == nullptr) {
- result << "null stream!" << "\n";
- } else {
- result << "mmap stream: rate = " << stream->getSampleRate() << "\n";
- }
-
+ result << " Direction: " << ((getDirection() == AAUDIO_DIRECTION_OUTPUT)
+ ? "OUTPUT" : "INPUT") << "\n";
+ result << " Sample Rate: " << getSampleRate() << "\n";
+ result << " Frames Per Burst: " << mFramesPerBurst << "\n";
+ result << " Reference Count: " << mOpenCount << "\n";
+ result << " Requested Device Id: " << mRequestedDeviceId << "\n";
+ result << " Device Id: " << getDeviceId() << "\n";
result << " Registered Streams:" << "\n";
- for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
- result << sharedStream->dump();
+ result << AAudioServiceStreamShared::dumpHeader() << "\n";
+ for (const auto stream : mRegisteredStreams) {
+ result << stream->dump() << "\n";
}
if (isLocked) {
@@ -74,110 +72,44 @@
return result.str();
}
-// Set up an EXCLUSIVE MMAP stream that will be shared.
-aaudio_result_t AAudioServiceEndpoint::open(const AAudioStreamConfiguration& configuration) {
- mRequestedDeviceId = configuration.getDeviceId();
- mStreamInternal = getStreamInternal();
-
- AudioStreamBuilder builder;
- builder.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
- // Don't fall back to SHARED because that would cause recursion.
- builder.setSharingModeMatchRequired(true);
- builder.setDeviceId(mRequestedDeviceId);
- builder.setFormat(configuration.getFormat());
- builder.setSampleRate(configuration.getSampleRate());
- builder.setSamplesPerFrame(configuration.getSamplesPerFrame());
- builder.setDirection(getDirection());
- builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY);
-
- return getStreamInternal()->open(builder);
-}
-
-aaudio_result_t AAudioServiceEndpoint::close() {
- return getStreamInternal()->close();
-}
-
-// TODO, maybe use an interface to reduce exposure
-aaudio_result_t AAudioServiceEndpoint::registerStream(sp<AAudioServiceStreamShared>sharedStream) {
- std::lock_guard<std::mutex> lock(mLockStreams);
- mRegisteredStreams.push_back(sharedStream);
- return AAUDIO_OK;
-}
-
-aaudio_result_t AAudioServiceEndpoint::unregisterStream(sp<AAudioServiceStreamShared>sharedStream) {
- std::lock_guard<std::mutex> lock(mLockStreams);
- mRegisteredStreams.erase(std::remove(mRegisteredStreams.begin(), mRegisteredStreams.end(), sharedStream),
- mRegisteredStreams.end());
- return AAUDIO_OK;
-}
-
-aaudio_result_t AAudioServiceEndpoint::startStream(sp<AAudioServiceStreamShared> sharedStream) {
- aaudio_result_t result = AAUDIO_OK;
- if (++mRunningStreams == 1) {
- // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
- std::lock_guard<std::mutex> lock(mLockStreams);
- result = getStreamInternal()->requestStart();
- startSharingThread_l();
- }
- return result;
-}
-
-aaudio_result_t AAudioServiceEndpoint::stopStream(sp<AAudioServiceStreamShared> sharedStream) {
- // Don't lock here because the disconnectRegisteredStreams also uses the lock.
- if (--mRunningStreams == 0) { // atomic
- stopSharingThread();
- getStreamInternal()->requestStop();
- }
- return AAUDIO_OK;
-}
-
-static void *aaudio_endpoint_thread_proc(void *context) {
- AAudioServiceEndpoint *endpoint = (AAudioServiceEndpoint *) context;
- if (endpoint != NULL) {
- return endpoint->callbackLoop();
- } else {
- return NULL;
- }
-}
-
-aaudio_result_t AAudioServiceEndpoint::startSharingThread_l() {
- // Launch the callback loop thread.
- int64_t periodNanos = getStreamInternal()->getFramesPerBurst()
- * AAUDIO_NANOS_PER_SECOND
- / getSampleRate();
- mCallbackEnabled.store(true);
- return getStreamInternal()->createThread(periodNanos, aaudio_endpoint_thread_proc, this);
-}
-
-aaudio_result_t AAudioServiceEndpoint::stopSharingThread() {
- mCallbackEnabled.store(false);
- aaudio_result_t result = getStreamInternal()->joinThread(NULL);
- return result;
-}
-
void AAudioServiceEndpoint::disconnectRegisteredStreams() {
std::lock_guard<std::mutex> lock(mLockStreams);
- for(auto sharedStream : mRegisteredStreams) {
- sharedStream->stop();
- sharedStream->disconnect();
+ for (const auto stream : mRegisteredStreams) {
+ stream->stop();
+ stream->disconnect();
}
mRegisteredStreams.clear();
}
+aaudio_result_t AAudioServiceEndpoint::registerStream(sp<AAudioServiceStreamBase>stream) {
+ std::lock_guard<std::mutex> lock(mLockStreams);
+ mRegisteredStreams.push_back(stream);
+ return AAUDIO_OK;
+}
+
+aaudio_result_t AAudioServiceEndpoint::unregisterStream(sp<AAudioServiceStreamBase>stream) {
+ std::lock_guard<std::mutex> lock(mLockStreams);
+ mRegisteredStreams.erase(std::remove(
+ mRegisteredStreams.begin(), mRegisteredStreams.end(), stream),
+ mRegisteredStreams.end());
+ return AAUDIO_OK;
+}
+
bool AAudioServiceEndpoint::matches(const AAudioStreamConfiguration& configuration) {
+ if (configuration.getDirection() != getDirection()) {
+ return false;
+ }
if (configuration.getDeviceId() != AAUDIO_UNSPECIFIED &&
- configuration.getDeviceId() != mStreamInternal->getDeviceId()) {
+ configuration.getDeviceId() != getDeviceId()) {
return false;
}
if (configuration.getSampleRate() != AAUDIO_UNSPECIFIED &&
- configuration.getSampleRate() != mStreamInternal->getSampleRate()) {
+ configuration.getSampleRate() != getSampleRate()) {
return false;
}
if (configuration.getSamplesPerFrame() != AAUDIO_UNSPECIFIED &&
- configuration.getSamplesPerFrame() != mStreamInternal->getSamplesPerFrame()) {
+ configuration.getSamplesPerFrame() != getSamplesPerFrame()) {
return false;
}
-
return true;
}
-
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index e40a670..c19cc35 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -24,70 +24,93 @@
#include "client/AudioStreamInternal.h"
#include "client/AudioStreamInternalPlay.h"
+#include "core/AAudioStreamParameters.h"
#include "binding/AAudioServiceMessage.h"
-#include "AAudioServiceStreamShared.h"
-#include "AAudioServiceStreamMMAP.h"
-#include "AAudioMixer.h"
-#include "AAudioService.h"
+#include "binding/AAudioStreamConfiguration.h"
+
+#include "AAudioServiceStreamBase.h"
namespace aaudio {
-class AAudioServiceEndpoint {
+/**
+ * AAudioServiceEndpoint is used by a subclass of AAudioServiceStreamBase
+ * to communicate with the underlying audio device or port.
+ */
+class AAudioServiceEndpoint
+ : public virtual android::RefBase
+ , public AAudioStreamParameters {
public:
- virtual ~AAudioServiceEndpoint() = default;
- std::string dump() const;
+ virtual ~AAudioServiceEndpoint();
- virtual aaudio_result_t open(const AAudioStreamConfiguration& configuration);
+ virtual std::string dump() const;
- int32_t getSampleRate() const { return mStreamInternal->getSampleRate(); }
- int32_t getSamplesPerFrame() const { return mStreamInternal->getSamplesPerFrame(); }
- int32_t getFramesPerBurst() const { return mStreamInternal->getFramesPerBurst(); }
+ virtual aaudio_result_t open(const aaudio::AAudioStreamRequest &request) = 0;
- aaudio_result_t registerStream(android::sp<AAudioServiceStreamShared> sharedStream);
- aaudio_result_t unregisterStream(android::sp<AAudioServiceStreamShared> sharedStream);
- aaudio_result_t startStream(android::sp<AAudioServiceStreamShared> sharedStream);
- aaudio_result_t stopStream(android::sp<AAudioServiceStreamShared> sharedStream);
- aaudio_result_t close();
+ virtual aaudio_result_t close() = 0;
+
+ aaudio_result_t registerStream(android::sp<AAudioServiceStreamBase> stream);
+
+ aaudio_result_t unregisterStream(android::sp<AAudioServiceStreamBase> stream);
+
+ virtual aaudio_result_t startStream(android::sp<AAudioServiceStreamBase> stream,
+ audio_port_handle_t *clientHandle) = 0;
+
+ virtual aaudio_result_t stopStream(android::sp<AAudioServiceStreamBase> stream,
+ audio_port_handle_t clientHandle) = 0;
+
+ virtual aaudio_result_t startClient(const android::AudioClient& client,
+ audio_port_handle_t *clientHandle) {
+ ALOGD("AAudioServiceEndpoint::startClient(%p, ...) AAUDIO_ERROR_UNAVAILABLE", &client);
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
+ virtual aaudio_result_t stopClient(audio_port_handle_t clientHandle) {
+ ALOGD("AAudioServiceEndpoint::stopClient(...) AAUDIO_ERROR_UNAVAILABLE");
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
+ /**
+ * @param positionFrames
+ * @param timeNanos
+ * @return AAUDIO_OK or AAUDIO_ERROR_UNAVAILABLE or other negative error
+ */
+ virtual aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) = 0;
+
+ virtual aaudio_result_t getTimestamp(int64_t *positionFrames, int64_t *timeNanos) = 0;
+
+ int32_t getFramesPerBurst() const {
+ return mFramesPerBurst;
+ }
int32_t getRequestedDeviceId() const { return mRequestedDeviceId; }
- int32_t getDeviceId() const { return mStreamInternal->getDeviceId(); }
-
- aaudio_direction_t getDirection() const { return mStreamInternal->getDirection(); }
-
- void disconnectRegisteredStreams();
-
- virtual void *callbackLoop() = 0;
-
- // This should only be called from the AAudioEndpointManager under a mutex.
- int32_t getReferenceCount() const {
- return mReferenceCount;
- }
-
- // This should only be called from the AAudioEndpointManager under a mutex.
- void setReferenceCount(int32_t count) {
- mReferenceCount = count;
- }
bool matches(const AAudioStreamConfiguration& configuration);
- virtual AudioStreamInternal *getStreamInternal() = 0;
+ // This should only be called from the AAudioEndpointManager under a mutex.
+ int32_t getOpenCount() const {
+ return mOpenCount;
+ }
- std::atomic<bool> mCallbackEnabled{false};
+ // This should only be called from the AAudioEndpointManager under a mutex.
+ void setOpenCount(int32_t count) {
+ mOpenCount = count;
+ }
+
+protected:
+ void disconnectRegisteredStreams();
mutable std::mutex mLockStreams;
+ std::vector<android::sp<AAudioServiceStreamBase>> mRegisteredStreams;
- std::vector<android::sp<AAudioServiceStreamShared>> mRegisteredStreams;
+ SimpleDoubleBuffer<Timestamp> mAtomicTimestamp;
- std::atomic<int> mRunningStreams{0};
+ android::AudioClient mMmapClient; // set in open, used in open and startStream
-private:
- aaudio_result_t startSharingThread_l();
- aaudio_result_t stopSharingThread();
-
- AudioStreamInternal *mStreamInternal = nullptr;
- int32_t mReferenceCount = 0;
+ int32_t mFramesPerBurst = 0;
+ int32_t mOpenCount = 0;
int32_t mRequestedDeviceId = 0;
+
};
} /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index 6a37330..c7d9b8e 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -30,20 +30,22 @@
#include "AAudioServiceEndpoint.h"
#include "AAudioServiceStreamShared.h"
#include "AAudioServiceEndpointCapture.h"
+#include "AAudioServiceEndpointShared.h"
using namespace android; // TODO just import names needed
using namespace aaudio; // TODO just import names needed
AAudioServiceEndpointCapture::AAudioServiceEndpointCapture(AAudioService &audioService)
: mStreamInternalCapture(audioService, true) {
+ mStreamInternal = &mStreamInternalCapture;
}
AAudioServiceEndpointCapture::~AAudioServiceEndpointCapture() {
delete mDistributionBuffer;
}
-aaudio_result_t AAudioServiceEndpointCapture::open(const AAudioStreamConfiguration& configuration) {
- aaudio_result_t result = AAudioServiceEndpoint::open(configuration);
+aaudio_result_t AAudioServiceEndpointCapture::open(const aaudio::AAudioStreamRequest &request) {
+ aaudio_result_t result = AAudioServiceEndpointShared::open(request);
if (result == AAUDIO_OK) {
delete mDistributionBuffer;
int distributionBufferSizeBytes = getStreamInternal()->getFramesPerBurst()
@@ -62,6 +64,9 @@
// result might be a frame count
while (mCallbackEnabled.load() && getStreamInternal()->isActive() && (result >= 0)) {
+
+ int64_t mmapFramesRead = getStreamInternal()->getFramesRead();
+
// Read audio data from stream using a blocking read.
result = getStreamInternal()->read(mDistributionBuffer, getFramesPerBurst(), timeoutNanos);
if (result == AAUDIO_ERROR_DISCONNECTED) {
@@ -74,18 +79,47 @@
}
// Distribute data to each active stream.
- { // use lock guard
+ { // brackets are for lock_guard
+
std::lock_guard <std::mutex> lock(mLockStreams);
- for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
- if (sharedStream->isRunning()) {
- FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
- if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
- getFramesPerBurst()) {
- underflowCount++;
- } else {
- fifo->write(mDistributionBuffer, getFramesPerBurst());
+ for (const auto clientStream : mRegisteredStreams) {
+ if (clientStream->isRunning()) {
+ int64_t clientFramesWritten = 0;
+ sp<AAudioServiceStreamShared> streamShared =
+ static_cast<AAudioServiceStreamShared *>(clientStream.get());
+
+ {
+ // Lock the AudioFifo to protect against close.
+ std::lock_guard <std::mutex> lock(streamShared->getAudioDataQueueLock());
+
+ FifoBuffer *fifo = streamShared->getAudioDataFifoBuffer_l();
+ if (fifo != nullptr) {
+
+ // Determine offset between framePosition in client's stream
+ // vs the underlying MMAP stream.
+ clientFramesWritten = fifo->getWriteCounter();
+ // There are two indices that refer to the same frame.
+ int64_t positionOffset = mmapFramesRead - clientFramesWritten;
+ streamShared->setTimestampPositionOffset(positionOffset);
+
+ if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
+ getFramesPerBurst()) {
+ underflowCount++;
+ } else {
+ fifo->write(mDistributionBuffer, getFramesPerBurst());
+ }
+ clientFramesWritten = fifo->getWriteCounter();
+ }
}
- sharedStream->markTransferTime(AudioClock::getNanoseconds());
+
+ if (clientFramesWritten > 0) {
+ // This timestamp represents the completion of data being written into the
+ // client buffer. It is sent to the client and used in the timing model
+ // to decide when data will be available to read.
+ Timestamp timestamp(clientFramesWritten, AudioClock::getNanoseconds());
+ streamShared->markTransferTime(timestamp);
+ }
+
}
}
}
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.h b/services/oboeservice/AAudioServiceEndpointCapture.h
index 8a3d72f..971da9a 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.h
+++ b/services/oboeservice/AAudioServiceEndpointCapture.h
@@ -20,18 +20,18 @@
#include "client/AudioStreamInternal.h"
#include "client/AudioStreamInternalCapture.h"
+#include "AAudioServiceEndpointShared.h"
+#include "AAudioServiceStreamShared.h"
+
namespace aaudio {
-class AAudioServiceEndpointCapture : public AAudioServiceEndpoint {
+class AAudioServiceEndpointCapture : public AAudioServiceEndpointShared {
public:
explicit AAudioServiceEndpointCapture(android::AAudioService &audioService);
virtual ~AAudioServiceEndpointCapture();
- aaudio_result_t open(const AAudioStreamConfiguration& configuration) override;
+ aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
- AudioStreamInternal *getStreamInternal() override {
- return &mStreamInternalCapture;
- }
void *callbackLoop() override;
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
new file mode 100644
index 0000000..7e6e247
--- /dev/null
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2017 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_TAG "AAudioServiceEndpointMMAP"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <algorithm>
+#include <assert.h>
+#include <map>
+#include <mutex>
+#include <sstream>
+#include <utils/Singleton.h>
+#include <vector>
+
+
+#include "AAudioEndpointManager.h"
+#include "AAudioServiceEndpoint.h"
+
+#include "core/AudioStreamBuilder.h"
+#include "AAudioServiceEndpoint.h"
+#include "AAudioServiceStreamShared.h"
+#include "AAudioServiceEndpointPlay.h"
+#include "AAudioServiceEndpointMMAP.h"
+
+
+#define AAUDIO_BUFFER_CAPACITY_MIN 4 * 512
+#define AAUDIO_SAMPLE_RATE_DEFAULT 48000
+
+// This is an estimate of the time difference between the HW and the MMAP time.
+// TODO Get presentation timestamps from the HAL instead of using these estimates.
+#define OUTPUT_ESTIMATED_HARDWARE_OFFSET_NANOS (3 * AAUDIO_NANOS_PER_MILLISECOND)
+#define INPUT_ESTIMATED_HARDWARE_OFFSET_NANOS (-1 * AAUDIO_NANOS_PER_MILLISECOND)
+
+using namespace android; // TODO just import names needed
+using namespace aaudio; // TODO just import names needed
+
+AAudioServiceEndpointMMAP::AAudioServiceEndpointMMAP()
+ : mMmapStream(nullptr) {}
+
+AAudioServiceEndpointMMAP::~AAudioServiceEndpointMMAP() {}
+
+std::string AAudioServiceEndpointMMAP::dump() const {
+ std::stringstream result;
+
+ result << " MMAP: framesTransferred = " << mFramesTransferred.get();
+ result << ", HW nanos = " << mHardwareTimeOffsetNanos;
+ result << ", port handle = " << mPortHandle;
+ result << ", audio data FD = " << mAudioDataFileDescriptor;
+ result << "\n";
+
+ result << " HW Offset Micros: " <<
+ (getHardwareTimeOffsetNanos()
+ / AAUDIO_NANOS_PER_MICROSECOND) << "\n";
+
+ result << AAudioServiceEndpoint::dump();
+ return result.str();
+}
+
+aaudio_result_t AAudioServiceEndpointMMAP::open(const aaudio::AAudioStreamRequest &request) {
+ aaudio_result_t result = AAUDIO_OK;
+ const audio_attributes_t attributes = {
+ .content_type = AUDIO_CONTENT_TYPE_MUSIC,
+ .usage = AUDIO_USAGE_MEDIA,
+ .source = AUDIO_SOURCE_VOICE_RECOGNITION,
+ .flags = AUDIO_FLAG_LOW_LATENCY,
+ .tags = ""
+ };
+ audio_config_base_t config;
+ audio_port_handle_t deviceId;
+
+ int32_t burstMinMicros = AAudioProperty_getHardwareBurstMinMicros();
+ int32_t burstMicros = 0;
+
+ copyFrom(request.getConstantConfiguration());
+
+ mMmapClient.clientUid = request.getUserId();
+ mMmapClient.clientPid = request.getProcessId();
+ mMmapClient.packageName.setTo(String16(""));
+
+ mRequestedDeviceId = deviceId = getDeviceId();
+
+ // Fill in config
+ aaudio_format_t aaudioFormat = getFormat();
+ if (aaudioFormat == AAUDIO_UNSPECIFIED || aaudioFormat == AAUDIO_FORMAT_PCM_FLOAT) {
+ aaudioFormat = AAUDIO_FORMAT_PCM_I16;
+ }
+ config.format = AAudioConvert_aaudioToAndroidDataFormat(aaudioFormat);
+
+ int32_t aaudioSampleRate = getSampleRate();
+ if (aaudioSampleRate == AAUDIO_UNSPECIFIED) {
+ aaudioSampleRate = AAUDIO_SAMPLE_RATE_DEFAULT;
+ }
+ config.sample_rate = aaudioSampleRate;
+
+ int32_t aaudioSamplesPerFrame = getSamplesPerFrame();
+
+ aaudio_direction_t direction = getDirection();
+ if (direction == AAUDIO_DIRECTION_OUTPUT) {
+ config.channel_mask = (aaudioSamplesPerFrame == AAUDIO_UNSPECIFIED)
+ ? AUDIO_CHANNEL_OUT_STEREO
+ : audio_channel_out_mask_from_count(aaudioSamplesPerFrame);
+ mHardwareTimeOffsetNanos = OUTPUT_ESTIMATED_HARDWARE_OFFSET_NANOS; // frames at DAC later
+
+ } else if (direction == AAUDIO_DIRECTION_INPUT) {
+ config.channel_mask = (aaudioSamplesPerFrame == AAUDIO_UNSPECIFIED)
+ ? AUDIO_CHANNEL_IN_STEREO
+ : audio_channel_in_mask_from_count(aaudioSamplesPerFrame);
+ mHardwareTimeOffsetNanos = INPUT_ESTIMATED_HARDWARE_OFFSET_NANOS; // frames at ADC earlier
+
+ } else {
+ ALOGE("openMmapStream - invalid direction = %d", direction);
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ }
+
+ MmapStreamInterface::stream_direction_t streamDirection =
+ (direction == AAUDIO_DIRECTION_OUTPUT)
+ ? MmapStreamInterface::DIRECTION_OUTPUT
+ : MmapStreamInterface::DIRECTION_INPUT;
+
+ // Open HAL stream. Set mMmapStream
+ status_t status = MmapStreamInterface::openMmapStream(streamDirection,
+ &attributes,
+ &config,
+ mMmapClient,
+ &deviceId,
+ this, // callback
+ mMmapStream,
+ &mPortHandle);
+ ALOGD("AAudioServiceEndpointMMAP::open() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
+ mMmapClient.clientUid, mMmapClient.clientPid, mPortHandle);
+ if (status != OK) {
+ ALOGE("openMmapStream returned status %d", status);
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
+ if (deviceId == AAUDIO_UNSPECIFIED) {
+ ALOGW("AAudioServiceEndpointMMAP::open() - openMmapStream() failed to set deviceId");
+ }
+ setDeviceId(deviceId);
+
+ // Create MMAP/NOIRQ buffer.
+ int32_t minSizeFrames = getBufferCapacity();
+ if (minSizeFrames <= 0) { // zero will get rejected
+ minSizeFrames = AAUDIO_BUFFER_CAPACITY_MIN;
+ }
+ status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
+ if (status != OK) {
+ ALOGE("AAudioServiceEndpointMMAP::open() - createMmapBuffer() failed with status %d %s",
+ status, strerror(-status));
+ result = AAUDIO_ERROR_UNAVAILABLE;
+ goto error;
+ } else {
+ ALOGD("createMmapBuffer status = %d, buffer_size = %d, burst_size %d"
+ ", Sharable FD: %s",
+ status,
+ abs(mMmapBufferinfo.buffer_size_frames),
+ mMmapBufferinfo.burst_size_frames,
+ mMmapBufferinfo.buffer_size_frames < 0 ? "Yes" : "No");
+ }
+
+ setBufferCapacity(mMmapBufferinfo.buffer_size_frames);
+ // The audio HAL indicates if the shared memory fd can be shared outside of audioserver
+ // by returning a negative buffer size
+ if (getBufferCapacity() < 0) {
+ // Exclusive mode can be used by client or service.
+ setBufferCapacity(-getBufferCapacity());
+ } else {
+ // Exclusive mode can only be used by the service because the FD cannot be shared.
+ uid_t audioServiceUid = getuid();
+ if ((mMmapClient.clientUid != audioServiceUid) &&
+ getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
+ // Fallback is handled by caller but indicate what is possible in case
+ // this is used in the future
+ setSharingMode(AAUDIO_SHARING_MODE_SHARED);
+ ALOGW("AAudioServiceEndpointMMAP::open() - exclusive FD cannot be used by client");
+ result = AAUDIO_ERROR_UNAVAILABLE;
+ goto error;
+ }
+ }
+
+ // Get information about the stream and pass it back to the caller.
+ setSamplesPerFrame((direction == AAUDIO_DIRECTION_OUTPUT)
+ ? audio_channel_count_from_out_mask(config.channel_mask)
+ : audio_channel_count_from_in_mask(config.channel_mask));
+
+ // AAudio creates a copy of this FD and retains ownership of the copy.
+ // Assume that AudioFlinger will close the original shared_memory_fd.
+ mAudioDataFileDescriptor.reset(dup(mMmapBufferinfo.shared_memory_fd));
+ if (mAudioDataFileDescriptor.get() == -1) {
+ ALOGE("AAudioServiceEndpointMMAP::open() - could not dup shared_memory_fd");
+ result = AAUDIO_ERROR_INTERNAL;
+ goto error;
+ }
+ mFramesPerBurst = mMmapBufferinfo.burst_size_frames;
+ setFormat(AAudioConvert_androidToAAudioDataFormat(config.format));
+ setSampleRate(config.sample_rate);
+
+ // Scale up the burst size to meet the minimum equivalent in microseconds.
+ // This is to avoid waking the CPU too often when the HW burst is very small
+ // or at high sample rates.
+ do {
+ if (burstMicros > 0) { // skip first loop
+ mFramesPerBurst *= 2;
+ }
+ burstMicros = mFramesPerBurst * static_cast<int64_t>(1000000) / getSampleRate();
+ } while (burstMicros < burstMinMicros);
+
+ ALOGD("AAudioServiceEndpointMMAP::open() original burst = %d, minMicros = %d, to burst = %d\n",
+ mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst);
+
+ ALOGD("AAudioServiceEndpointMMAP::open() actual rate = %d, channels = %d"
+ ", deviceId = %d, capacity = %d\n",
+ getSampleRate(), getSamplesPerFrame(), deviceId, getBufferCapacity());
+
+ return result;
+
+error:
+ close();
+ return result;
+}
+
+aaudio_result_t AAudioServiceEndpointMMAP::close() {
+
+ if (mMmapStream != 0) {
+ ALOGD("AAudioServiceEndpointMMAP::close() clear() endpoint");
+ // Needs to be explicitly cleared or CTS will fail but it is not clear why.
+ mMmapStream.clear();
+ // Apparently the above close is asynchronous. An attempt to open a new device
+ // right after a close can fail. Also some callbacks may still be in flight!
+ // FIXME Make closing synchronous.
+ AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND);
+ }
+
+ return AAUDIO_OK;
+}
+
+aaudio_result_t AAudioServiceEndpointMMAP::startStream(sp<AAudioServiceStreamBase> stream,
+ audio_port_handle_t *clientHandle) {
+ // Start the client on behalf of the AAudio service.
+ // Use the port handle that was provided by openMmapStream().
+ return startClient(mMmapClient, &mPortHandle);
+}
+
+aaudio_result_t AAudioServiceEndpointMMAP::stopStream(sp<AAudioServiceStreamBase> stream,
+ audio_port_handle_t clientHandle) {
+ mFramesTransferred.reset32();
+
+ // Round 64-bit counter up to a multiple of the buffer capacity.
+ // This is required because the 64-bit counter is used as an index
+ // into a circular buffer and the actual HW position is reset to zero
+ // when the stream is stopped.
+ mFramesTransferred.roundUp64(getBufferCapacity());
+
+ return stopClient(mPortHandle);
+}
+
+aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
+ audio_port_handle_t *clientHandle) {
+ if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
+ ALOGD("AAudioServiceEndpointMMAP::startClient(%p(uid=%d, pid=%d))",
+ &client, client.clientUid, client.clientPid);
+ audio_port_handle_t originalHandle = *clientHandle;
+ status_t status = mMmapStream->start(client, clientHandle);
+ aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
+ ALOGD("AAudioServiceEndpointMMAP::startClient() , %d => %d returns %d",
+ originalHandle, *clientHandle, result);
+ return result;
+}
+
+aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t clientHandle) {
+ if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
+ aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
+ ALOGD("AAudioServiceEndpointMMAP::stopClient(%d) returns %d", clientHandle, result);
+ return result;
+}
+
+// Get free-running DSP or DMA hardware position from the HAL.
+aaudio_result_t AAudioServiceEndpointMMAP::getFreeRunningPosition(int64_t *positionFrames,
+ int64_t *timeNanos) {
+ struct audio_mmap_position position;
+ if (mMmapStream == nullptr) {
+ return AAUDIO_ERROR_NULL;
+ }
+ status_t status = mMmapStream->getMmapPosition(&position);
+ ALOGV("AAudioServiceEndpointMMAP::getFreeRunningPosition() status= %d, pos = %d, nanos = %lld\n",
+ status, position.position_frames, (long long) position.time_nanoseconds);
+ aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
+ if (result == AAUDIO_ERROR_UNAVAILABLE) {
+ ALOGW("sendCurrentTimestamp(): getMmapPosition() has no position data available");
+ } else if (result != AAUDIO_OK) {
+ ALOGE("sendCurrentTimestamp(): getMmapPosition() returned status %d", status);
+ } else {
+ // Convert 32-bit position to 64-bit position.
+ mFramesTransferred.update32(position.position_frames);
+ *positionFrames = mFramesTransferred.get();
+ *timeNanos = position.time_nanoseconds;
+ }
+ return result;
+}
+
+aaudio_result_t AAudioServiceEndpointMMAP::getTimestamp(int64_t *positionFrames,
+ int64_t *timeNanos) {
+ return 0; // TODO
+}
+
+
+void AAudioServiceEndpointMMAP::onTearDown() {
+ ALOGD("AAudioServiceEndpointMMAP::onTearDown() called");
+ disconnectRegisteredStreams();
+};
+
+void AAudioServiceEndpointMMAP::onVolumeChanged(audio_channel_mask_t channels,
+ android::Vector<float> values) {
+ // TODO do we really need a different volume for each channel?
+ float volume = values[0];
+ ALOGD("AAudioServiceEndpointMMAP::onVolumeChanged() volume[0] = %f", volume);
+ std::lock_guard<std::mutex> lock(mLockStreams);
+ for(const auto stream : mRegisteredStreams) {
+ stream->onVolumeChanged(volume);
+ }
+};
+
+void AAudioServiceEndpointMMAP::onRoutingChanged(audio_port_handle_t deviceId) {
+ ALOGD("AAudioServiceEndpointMMAP::onRoutingChanged() called with %d, old = %d",
+ deviceId, getDeviceId());
+ if (getDeviceId() != AUDIO_PORT_HANDLE_NONE && getDeviceId() != deviceId) {
+ disconnectRegisteredStreams();
+ }
+ setDeviceId(deviceId);
+};
+
+/**
+ * Get an immutable description of the data queue from the HAL.
+ */
+aaudio_result_t AAudioServiceEndpointMMAP::getDownDataDescription(AudioEndpointParcelable &parcelable)
+{
+ // Gather information on the data queue based on HAL info.
+ int32_t bytesPerFrame = calculateBytesPerFrame();
+ int32_t capacityInBytes = getBufferCapacity() * bytesPerFrame;
+ int fdIndex = parcelable.addFileDescriptor(mAudioDataFileDescriptor, capacityInBytes);
+ parcelable.mDownDataQueueParcelable.setupMemory(fdIndex, 0, capacityInBytes);
+ parcelable.mDownDataQueueParcelable.setBytesPerFrame(bytesPerFrame);
+ parcelable.mDownDataQueueParcelable.setFramesPerBurst(mFramesPerBurst);
+ parcelable.mDownDataQueueParcelable.setCapacityInFrames(getBufferCapacity());
+ return AAUDIO_OK;
+}
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h
new file mode 100644
index 0000000..16b6269
--- /dev/null
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 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 AAUDIO_SERVICE_ENDPOINT_MMAP_H
+#define AAUDIO_SERVICE_ENDPOINT_MMAP_H
+
+#include <atomic>
+#include <functional>
+#include <mutex>
+#include <vector>
+
+#include "client/AudioStreamInternal.h"
+#include "client/AudioStreamInternalPlay.h"
+#include "binding/AAudioServiceMessage.h"
+#include "AAudioServiceEndpointShared.h"
+#include "AAudioServiceStreamShared.h"
+#include "AAudioServiceStreamMMAP.h"
+#include "AAudioMixer.h"
+#include "AAudioService.h"
+
+namespace aaudio {
+
+/**
+ * This is used by AAudioServiceStreamMMAP to access the MMAP devices
+ * through AudioFlinger.
+ */
+class AAudioServiceEndpointMMAP
+ : public AAudioServiceEndpoint
+ , public android::MmapStreamCallback {
+
+public:
+ AAudioServiceEndpointMMAP();
+
+ virtual ~AAudioServiceEndpointMMAP();
+
+ std::string dump() const override;
+
+ aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
+
+ aaudio_result_t close() override;
+
+ aaudio_result_t startStream(android::sp<AAudioServiceStreamBase> stream,
+ audio_port_handle_t *clientHandle) override;
+
+ aaudio_result_t stopStream(android::sp<AAudioServiceStreamBase> stream,
+ audio_port_handle_t clientHandle) override;
+
+ aaudio_result_t startClient(const android::AudioClient& client,
+ audio_port_handle_t *clientHandle) override;
+
+ aaudio_result_t stopClient(audio_port_handle_t clientHandle) override;
+
+ aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
+
+ aaudio_result_t getTimestamp(int64_t *positionFrames, int64_t *timeNanos) override;
+
+ // -------------- Callback functions for MmapStreamCallback ---------------------
+ void onTearDown() override;
+
+ void onVolumeChanged(audio_channel_mask_t channels,
+ android::Vector<float> values) override;
+
+ void onRoutingChanged(audio_port_handle_t deviceId) override;
+ // ------------------------------------------------------------------------------
+
+ aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable);
+
+ int64_t getHardwareTimeOffsetNanos() const {
+ return mHardwareTimeOffsetNanos;
+ }
+
+private:
+ MonotonicCounter mFramesTransferred;
+
+ // Interface to the AudioFlinger MMAP support.
+ android::sp<android::MmapStreamInterface> mMmapStream;
+ struct audio_mmap_buffer_info mMmapBufferinfo;
+ audio_port_handle_t mPortHandle = AUDIO_PORT_HANDLE_NONE;
+
+ android::base::unique_fd mAudioDataFileDescriptor;
+
+ int64_t mHardwareTimeOffsetNanos = 0; // TODO get from HAL
+
+};
+
+} /* namespace aaudio */
+
+#endif //AAUDIO_SERVICE_ENDPOINT_MMAP_H
+
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index b83b918..9b1833a 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceEndpointPlay"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -33,6 +33,7 @@
#include "AAudioServiceEndpoint.h"
#include "AAudioServiceStreamShared.h"
#include "AAudioServiceEndpointPlay.h"
+#include "AAudioServiceEndpointShared.h"
using namespace android; // TODO just import names needed
using namespace aaudio; // TODO just import names needed
@@ -41,13 +42,14 @@
AAudioServiceEndpointPlay::AAudioServiceEndpointPlay(AAudioService &audioService)
: mStreamInternalPlay(audioService, true) {
+ mStreamInternal = &mStreamInternalPlay;
}
AAudioServiceEndpointPlay::~AAudioServiceEndpointPlay() {
}
-aaudio_result_t AAudioServiceEndpointPlay::open(const AAudioStreamConfiguration& configuration) {
- aaudio_result_t result = AAudioServiceEndpoint::open(configuration);
+aaudio_result_t AAudioServiceEndpointPlay::open(const aaudio::AAudioStreamRequest &request) {
+ aaudio_result_t result = AAudioServiceEndpointShared::open(request);
if (result == AAUDIO_OK) {
mMixer.allocate(getStreamInternal()->getSamplesPerFrame(),
getStreamInternal()->getFramesPerBurst());
@@ -65,7 +67,6 @@
// Mix data from each application stream and write result to the shared MMAP stream.
void *AAudioServiceEndpointPlay::callbackLoop() {
- int32_t underflowCount = 0;
aaudio_result_t result = AAUDIO_OK;
int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
@@ -73,19 +74,54 @@
while (mCallbackEnabled.load() && getStreamInternal()->isActive() && (result >= 0)) {
// Mix data from each active stream.
mMixer.clear();
- { // use lock guard
+
+ { // brackets are for lock_guard
int index = 0;
+ int64_t mmapFramesWritten = getStreamInternal()->getFramesWritten();
+
std::lock_guard <std::mutex> lock(mLockStreams);
- for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
- if (sharedStream->isRunning()) {
- FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
- float volume = 1.0; // to match legacy volume
- bool underflowed = mMixer.mix(index, fifo, volume);
- underflowCount += underflowed ? 1 : 0;
- // TODO log underflows in each stream
- sharedStream->markTransferTime(AudioClock::getNanoseconds());
+ for (const auto clientStream : mRegisteredStreams) {
+ int64_t clientFramesRead = 0;
+
+ if (!clientStream->isRunning()) {
+ continue;
}
- index++;
+
+ sp<AAudioServiceStreamShared> streamShared =
+ static_cast<AAudioServiceStreamShared *>(clientStream.get());
+
+ {
+ // Lock the AudioFifo to protect against close.
+ std::lock_guard <std::mutex> lock(streamShared->getAudioDataQueueLock());
+
+ FifoBuffer *fifo = streamShared->getAudioDataFifoBuffer_l();
+ if (fifo != nullptr) {
+
+ // Determine offset between framePosition in client's stream
+ // vs the underlying MMAP stream.
+ clientFramesRead = fifo->getReadCounter();
+ // These two indices refer to the same frame.
+ int64_t positionOffset = mmapFramesWritten - clientFramesRead;
+ streamShared->setTimestampPositionOffset(positionOffset);
+
+ float volume = 1.0; // to match legacy volume
+ bool underflowed = mMixer.mix(index, fifo, volume);
+ if (underflowed) {
+ streamShared->incrementXRunCount();
+ }
+ clientFramesRead = fifo->getReadCounter();
+ }
+ }
+
+ if (clientFramesRead > 0) {
+ // This timestamp represents the completion of data being read out of the
+ // client buffer. It is sent to the client and used in the timing model
+ // to decide when the client has room to write more data.
+ Timestamp timestamp(clientFramesRead, AudioClock::getNanoseconds());
+ streamShared->markTransferTime(timestamp);
+ }
+
+ index++; // just used for labelling tracks in systrace
}
}
@@ -93,7 +129,7 @@
result = getStreamInternal()->write(mMixer.getOutputBuffer(),
getFramesPerBurst(), timeoutNanos);
if (result == AAUDIO_ERROR_DISCONNECTED) {
- disconnectRegisteredStreams();
+ AAudioServiceEndpointShared::disconnectRegisteredStreams();
break;
} else if (result != getFramesPerBurst()) {
ALOGW("AAudioServiceEndpoint(): callbackLoop() wrote %d / %d",
@@ -102,8 +138,5 @@
}
}
- ALOGW_IF((underflowCount > 0),
- "AAudioServiceEndpointPlay(): callbackLoop() had %d underflows", underflowCount);
-
return NULL; // TODO review
}
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.h b/services/oboeservice/AAudioServiceEndpointPlay.h
index c22f510..a0a383c 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.h
+++ b/services/oboeservice/AAudioServiceEndpointPlay.h
@@ -25,6 +25,7 @@
#include "client/AudioStreamInternal.h"
#include "client/AudioStreamInternalPlay.h"
#include "binding/AAudioServiceMessage.h"
+#include "AAudioServiceEndpointShared.h"
#include "AAudioServiceStreamShared.h"
#include "AAudioServiceStreamMMAP.h"
#include "AAudioMixer.h"
@@ -35,16 +36,12 @@
/**
* Contains a mixer and a stream for writing the result of the mix.
*/
-class AAudioServiceEndpointPlay : public AAudioServiceEndpoint {
+class AAudioServiceEndpointPlay : public AAudioServiceEndpointShared {
public:
explicit AAudioServiceEndpointPlay(android::AAudioService &audioService);
virtual ~AAudioServiceEndpointPlay();
- aaudio_result_t open(const AAudioStreamConfiguration& configuration) override;
-
- AudioStreamInternal *getStreamInternal() override {
- return &mStreamInternalPlay;
- }
+ aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
void *callbackLoop() override;
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
new file mode 100644
index 0000000..cd40066
--- /dev/null
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2017 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_TAG "AAudioServiceEndpointShared"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include "binding/AAudioServiceMessage.h"
+#include "client/AudioStreamInternal.h"
+#include "client/AudioStreamInternalPlay.h"
+#include "core/AudioStreamBuilder.h"
+
+#include "AAudioServiceEndpointShared.h"
+#include "AAudioServiceStreamShared.h"
+#include "AAudioServiceStreamMMAP.h"
+#include "AAudioMixer.h"
+#include "AAudioService.h"
+
+using namespace android;
+using namespace aaudio;
+
+// This is the maximum size in frames. The effective size can be tuned smaller at runtime.
+#define DEFAULT_BUFFER_CAPACITY (48 * 8)
+
+std::string AAudioServiceEndpointShared::dump() const {
+ std::stringstream result;
+
+ result << " SHARED: sharing exclusive stream with handle = 0x"
+ << std::setfill('0') << std::setw(8)
+ << std::hex << mStreamInternal->getServiceHandle()
+ << std::dec << std::setfill(' ');
+ result << "\n";
+ result << " Running Stream Count: " << mRunningStreamCount << "\n";
+
+ result << AAudioServiceEndpoint::dump();
+ return result.str();
+}
+
+// Share an AudioStreamInternal.
+aaudio_result_t AAudioServiceEndpointShared::open(const aaudio::AAudioStreamRequest &request) {
+ aaudio_result_t result = AAUDIO_OK;
+ const AAudioStreamConfiguration &configuration = request.getConstantConfiguration();
+
+ mRequestedDeviceId = configuration.getDeviceId();
+ setDirection(configuration.getDirection());
+
+ AudioStreamBuilder builder;
+ builder.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
+ // Don't fall back to SHARED because that would cause recursion.
+ builder.setSharingModeMatchRequired(true);
+ builder.setDeviceId(mRequestedDeviceId);
+ builder.setFormat(configuration.getFormat());
+ builder.setSampleRate(configuration.getSampleRate());
+ builder.setSamplesPerFrame(configuration.getSamplesPerFrame());
+ builder.setDirection(configuration.getDirection());
+ builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY);
+
+ result = mStreamInternal->open(builder);
+
+ setSampleRate(mStreamInternal->getSampleRate());
+ setSamplesPerFrame(mStreamInternal->getSamplesPerFrame());
+ setDeviceId(mStreamInternal->getDeviceId());
+ mFramesPerBurst = mStreamInternal->getFramesPerBurst();
+
+ return result;
+}
+
+aaudio_result_t AAudioServiceEndpointShared::close() {
+ return getStreamInternal()->close();
+}
+
+// Glue between C and C++ callbacks.
+static void *aaudio_endpoint_thread_proc(void *context) {
+ AAudioServiceEndpointShared *endpoint = (AAudioServiceEndpointShared *) context;
+ if (endpoint != NULL) {
+ return endpoint->callbackLoop();
+ } else {
+ return NULL;
+ }
+}
+
+aaudio_result_t aaudio::AAudioServiceEndpointShared::startSharingThread_l() {
+ // Launch the callback loop thread.
+ int64_t periodNanos = getStreamInternal()->getFramesPerBurst()
+ * AAUDIO_NANOS_PER_SECOND
+ / getSampleRate();
+ mCallbackEnabled.store(true);
+ return getStreamInternal()->createThread(periodNanos, aaudio_endpoint_thread_proc, this);
+}
+
+aaudio_result_t aaudio::AAudioServiceEndpointShared::stopSharingThread() {
+ mCallbackEnabled.store(false);
+ aaudio_result_t result = getStreamInternal()->joinThread(NULL);
+ return result;
+}
+
+aaudio_result_t AAudioServiceEndpointShared::startStream(sp<AAudioServiceStreamBase> sharedStream,
+ audio_port_handle_t *clientHandle) {
+ aaudio_result_t result = AAUDIO_OK;
+
+ {
+ std::lock_guard<std::mutex> lock(mLockStreams);
+ if (++mRunningStreamCount == 1) { // atomic
+ result = getStreamInternal()->requestStart();
+ if (result != AAUDIO_OK) {
+ --mRunningStreamCount;
+ } else {
+ result = startSharingThread_l();
+ if (result != AAUDIO_OK) {
+ getStreamInternal()->requestStop();
+ --mRunningStreamCount;
+ }
+ }
+ }
+ }
+
+ if (result == AAUDIO_OK) {
+ result = getStreamInternal()->startClient(sharedStream->getAudioClient(), clientHandle);
+ if (result != AAUDIO_OK) {
+ if (--mRunningStreamCount == 0) { // atomic
+ stopSharingThread();
+ getStreamInternal()->requestStop();
+ }
+ }
+ }
+
+ return result;
+}
+
+aaudio_result_t AAudioServiceEndpointShared::stopStream(sp<AAudioServiceStreamBase> sharedStream,
+ audio_port_handle_t clientHandle) {
+ // Don't lock here because the disconnectRegisteredStreams also uses the lock.
+
+ // Ignore result.
+ (void) getStreamInternal()->stopClient(clientHandle);
+
+ if (--mRunningStreamCount == 0) { // atomic
+ stopSharingThread();
+ getStreamInternal()->requestStop();
+ }
+ return AAUDIO_OK;
+}
+
+// Get timestamp that was written by the real-time service thread, eg. mixer.
+aaudio_result_t AAudioServiceEndpointShared::getFreeRunningPosition(int64_t *positionFrames,
+ int64_t *timeNanos) {
+ if (mAtomicTimestamp.isValid()) {
+ Timestamp timestamp = mAtomicTimestamp.read();
+ *positionFrames = timestamp.getPosition();
+ *timeNanos = timestamp.getNanoseconds();
+ return AAUDIO_OK;
+ } else {
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+}
+
+aaudio_result_t AAudioServiceEndpointShared::getTimestamp(int64_t *positionFrames,
+ int64_t *timeNanos) {
+ return mStreamInternal->getTimestamp(CLOCK_MONOTONIC, positionFrames, timeNanos);
+}
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
new file mode 100644
index 0000000..e3bd2c1
--- /dev/null
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 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 AAUDIO_SERVICE_ENDPOINT_SHARED_H
+#define AAUDIO_SERVICE_ENDPOINT_SHARED_H
+
+#include <atomic>
+#include <mutex>
+
+#include "AAudioServiceEndpoint.h"
+#include "client/AudioStreamInternal.h"
+#include "client/AudioStreamInternalPlay.h"
+#include "AAudioServiceStreamShared.h"
+#include "AAudioServiceStreamMMAP.h"
+#include "AAudioService.h"
+
+namespace aaudio {
+
+/**
+ * This Service class corresponds to a Client stream that shares an MMAP device through a mixer
+ * or an input distributor.
+ */
+class AAudioServiceEndpointShared : public AAudioServiceEndpoint {
+
+public:
+
+ std::string dump() const override;
+
+ aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
+
+ aaudio_result_t close() override;
+
+ aaudio_result_t startStream(android::sp<AAudioServiceStreamBase> stream,
+ audio_port_handle_t *clientHandle) override;
+
+ aaudio_result_t stopStream(android::sp<AAudioServiceStreamBase> stream,
+ audio_port_handle_t clientHandle) override;
+
+ aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
+
+ aaudio_result_t getTimestamp(int64_t *positionFrames, int64_t *timeNanos) override;
+
+ virtual void *callbackLoop() = 0;
+
+ AudioStreamInternal *getStreamInternal() const {
+ return mStreamInternal;
+ };
+
+protected:
+
+ aaudio_result_t startSharingThread_l();
+
+ aaudio_result_t stopSharingThread();
+
+ // pointer to object statically allocated in subclasses
+ AudioStreamInternal *mStreamInternal = nullptr;
+
+ std::atomic<bool> mCallbackEnabled{false};
+
+ std::atomic<int> mRunningStreamCount{0};
+};
+
+}
+
+#endif //AAUDIO_SERVICE_ENDPOINT_SHARED_H
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 5f7d179..d9b8766 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -18,12 +18,17 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <iomanip>
+#include <iostream>
#include <mutex>
#include "binding/IAAudioService.h"
#include "binding/AAudioServiceMessage.h"
#include "utility/AudioClock.h"
+#include "AAudioEndpointManager.h"
+#include "AAudioService.h"
+#include "AAudioServiceEndpoint.h"
#include "AAudioServiceStreamBase.h"
#include "TimestampScheduler.h"
@@ -35,9 +40,11 @@
* @return
*/
-AAudioServiceStreamBase::AAudioServiceStreamBase()
+AAudioServiceStreamBase::AAudioServiceStreamBase(AAudioService &audioService)
: mUpMessageQueue(nullptr)
- , mAAudioThread() {
+ , mTimestampThread()
+ , mAtomicTimestamp()
+ , mAudioService(audioService) {
mMmapClient.clientUid = -1;
mMmapClient.clientPid = -1;
mMmapClient.packageName = String16("");
@@ -47,61 +54,153 @@
ALOGD("AAudioServiceStreamBase::~AAudioServiceStreamBase() destroying %p", this);
// If the stream is deleted when OPEN or in use then audio resources will leak.
// This would indicate an internal error. So we want to find this ASAP.
- LOG_ALWAYS_FATAL_IF(!(mState == AAUDIO_STREAM_STATE_CLOSED
- || mState == AAUDIO_STREAM_STATE_UNINITIALIZED
- || mState == AAUDIO_STREAM_STATE_DISCONNECTED),
- "service stream still open, state = %d", mState);
+ LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
+ || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED
+ || getState() == AAUDIO_STREAM_STATE_DISCONNECTED),
+ "service stream still open, state = %d", getState());
+}
+
+std::string AAudioServiceStreamBase::dumpHeader() {
+ return std::string(" T Handle UId Run State Format Burst Chan Capacity");
}
std::string AAudioServiceStreamBase::dump() const {
std::stringstream result;
- result << " -------- handle = 0x" << std::hex << mHandle << std::dec << "\n";
- result << " state = " << AAudio_convertStreamStateToText(mState) << "\n";
- result << " format = " << mAudioFormat << "\n";
- result << " framesPerBurst = " << mFramesPerBurst << "\n";
- result << " channelCount = " << mSamplesPerFrame << "\n";
- result << " capacityFrames = " << mCapacityInFrames << "\n";
- result << " owner uid = " << mMmapClient.clientUid << "\n";
+ result << " 0x" << std::setfill('0') << std::setw(8) << std::hex << mHandle
+ << std::dec << std::setfill(' ') ;
+ result << std::setw(6) << mMmapClient.clientUid;
+ result << std::setw(4) << (isRunning() ? "yes" : " no");
+ result << std::setw(6) << getState();
+ result << std::setw(7) << getFormat();
+ result << std::setw(6) << mFramesPerBurst;
+ result << std::setw(5) << getSamplesPerFrame();
+ result << std::setw(9) << getBufferCapacity();
return result.str();
}
aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request,
- aaudio::AAudioStreamConfiguration &configurationOutput) {
+ aaudio_sharing_mode_t sharingMode) {
+ AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
+ aaudio_result_t result = AAUDIO_OK;
mMmapClient.clientUid = request.getUserId();
mMmapClient.clientPid = request.getProcessId();
- mMmapClient.packageName.setTo(String16("")); // FIXME what should we do here?
+ mMmapClient.packageName.setTo(String16("")); // TODO What should we do here?
- std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
- if (mUpMessageQueue != nullptr) {
- return AAUDIO_ERROR_INVALID_STATE;
- } else {
+ // Limit scope of lock to avoid recursive lock in close().
+ {
+ std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
+ if (mUpMessageQueue != nullptr) {
+ ALOGE("AAudioServiceStreamBase::open() called twice");
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+
mUpMessageQueue = new SharedRingBuffer();
- return mUpMessageQueue->allocate(sizeof(AAudioServiceMessage), QUEUE_UP_CAPACITY_COMMANDS);
+ result = mUpMessageQueue->allocate(sizeof(AAudioServiceMessage),
+ QUEUE_UP_CAPACITY_COMMANDS);
+ if (result != AAUDIO_OK) {
+ goto error;
+ }
+
+ // This is not protected by a lock because the stream cannot be
+ // referenced until the service returns a handle to the client.
+ // So only one thread can open a stream.
+ mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService,
+ request,
+ sharingMode);
+ if (mServiceEndpoint == nullptr) {
+ ALOGE("AAudioServiceStreamBase::open() openEndpoint() failed");
+ result = AAUDIO_ERROR_UNAVAILABLE;
+ goto error;
+ }
+ // Save a weak pointer that we will use to access the endpoint.
+ mServiceEndpointWeak = mServiceEndpoint;
+
+ mFramesPerBurst = mServiceEndpoint->getFramesPerBurst();
+ copyFrom(*mServiceEndpoint);
}
+ return result;
+
+error:
+ close();
+ return result;
}
aaudio_result_t AAudioServiceStreamBase::close() {
- if (mState != AAUDIO_STREAM_STATE_CLOSED) {
+ aaudio_result_t result = AAUDIO_OK;
+ if (getState() == AAUDIO_STREAM_STATE_CLOSED) {
+ return AAUDIO_OK;
+ }
+
+ stop();
+
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ result = AAUDIO_ERROR_INVALID_STATE;
+ } else {
+ endpoint->unregisterStream(this);
+ AAudioEndpointManager &endpointManager = AAudioEndpointManager::getInstance();
+ endpointManager.closeEndpoint(endpoint);
+
+ // AAudioService::closeStream() prevents two threads from closing at the same time.
+ mServiceEndpoint.clear(); // endpoint will hold the pointer until this method returns.
+ }
+
+
+ {
+ std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
stopTimestampThread();
- std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
delete mUpMessageQueue;
mUpMessageQueue = nullptr;
- mState = AAUDIO_STREAM_STATE_CLOSED;
}
- return AAUDIO_OK;
+
+ setState(AAUDIO_STREAM_STATE_CLOSED);
+ return result;
}
+aaudio_result_t AAudioServiceStreamBase::startDevice() {
+ mClientHandle = AUDIO_PORT_HANDLE_NONE;
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ return endpoint->startStream(this, &mClientHandle);
+}
+
+/**
+ * Start the flow of audio data.
+ *
+ * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
+ */
aaudio_result_t AAudioServiceStreamBase::start() {
+ aaudio_result_t result = AAUDIO_OK;
+
if (isRunning()) {
return AAUDIO_OK;
}
+
+ // Start with fresh presentation timestamps.
+ mAtomicTimestamp.clear();
+
+ mClientHandle = AUDIO_PORT_HANDLE_NONE;
+ result = startDevice();
+ if (result != AAUDIO_OK) goto error;
+
+ // This should happen at the end of the start.
sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED);
- mState = AAUDIO_STREAM_STATE_STARTED;
+ setState(AAUDIO_STREAM_STATE_STARTED);
mThreadEnabled.store(true);
- return mAAudioThread.start(this);
+ result = mTimestampThread.start(this);
+ if (result != AAUDIO_OK) goto error;
+
+ return result;
+
+error:
+ disconnect();
+ return result;
}
aaudio_result_t AAudioServiceStreamBase::pause() {
@@ -109,15 +208,30 @@
if (!isRunning()) {
return result;
}
+
+ // Send it now because the timestamp gets rounded up when stopStream() is called below.
+ // Also we don't need the timestamps while we are shutting down.
sendCurrentTimestamp();
- mThreadEnabled.store(false);
- result = mAAudioThread.stop();
+
+ result = stopTimestampThread();
if (result != AAUDIO_OK) {
disconnect();
return result;
}
+
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ result = endpoint->stopStream(this, mClientHandle);
+ if (result != AAUDIO_OK) {
+ ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
+ disconnect(); // TODO should we return or pause Base first?
+ }
+
sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
- mState = AAUDIO_STREAM_STATE_PAUSED;
+ setState(AAUDIO_STREAM_STATE_PAUSED);
return result;
}
@@ -126,15 +240,31 @@
if (!isRunning()) {
return result;
}
- // TODO wait for data to be played out
+
+ // Send it now because the timestamp gets rounded up when stopStream() is called below.
+ // Also we don't need the timestamps while we are shutting down.
sendCurrentTimestamp(); // warning - this calls a virtual function
result = stopTimestampThread();
if (result != AAUDIO_OK) {
disconnect();
return result;
}
+
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ // TODO wait for data to be played out
+ result = endpoint->stopStream(this, mClientHandle);
+ if (result != AAUDIO_OK) {
+ ALOGE("AAudioServiceStreamShared::stop() mServiceEndpoint returned %d", result);
+ disconnect();
+ // TODO what to do with result here?
+ }
+
sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
- mState = AAUDIO_STREAM_STATE_STOPPED;
+ setState(AAUDIO_STREAM_STATE_STOPPED);
return result;
}
@@ -142,14 +272,20 @@
aaudio_result_t result = AAUDIO_OK;
// clear flag that tells thread to loop
if (mThreadEnabled.exchange(false)) {
- result = mAAudioThread.stop();
+ result = mTimestampThread.stop();
}
return result;
}
aaudio_result_t AAudioServiceStreamBase::flush() {
+ if (getState() != AAUDIO_STREAM_STATE_PAUSED) {
+ ALOGE("AAudioServiceStreamBase::flush() stream not paused, state = %s",
+ AAudio_convertStreamStateToText(mState));
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ // Data will get flushed when the client receives the FLUSHED event.
sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED);
- mState = AAUDIO_STREAM_STATE_FLUSHED;
+ setState(AAUDIO_STREAM_STATE_FLUSHED);
return AAUDIO_OK;
}
@@ -157,7 +293,7 @@
void AAudioServiceStreamBase::run() {
ALOGD("AAudioServiceStreamBase::run() entering ----------------");
TimestampScheduler timestampScheduler;
- timestampScheduler.setBurstPeriod(mFramesPerBurst, mSampleRate);
+ timestampScheduler.setBurstPeriod(mFramesPerBurst, getSampleRate());
timestampScheduler.start(AudioClock::getNanoseconds());
int64_t nextTime = timestampScheduler.nextAbsoluteTime();
while(mThreadEnabled.load()) {
@@ -177,9 +313,9 @@
}
void AAudioServiceStreamBase::disconnect() {
- if (mState != AAUDIO_STREAM_STATE_DISCONNECTED) {
+ if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
- mState = AAUDIO_STREAM_STATE_DISCONNECTED;
+ setState(AAUDIO_STREAM_STATE_DISCONNECTED);
}
}
@@ -195,7 +331,7 @@
}
aaudio_result_t AAudioServiceStreamBase::writeUpMessageQueue(AAudioServiceMessage *command) {
- std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
+ std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
if (mUpMessageQueue == nullptr) {
ALOGE("writeUpMessageQueue(): mUpMessageQueue null! - stream not open");
return AAUDIO_ERROR_NULL;
@@ -211,15 +347,31 @@
aaudio_result_t AAudioServiceStreamBase::sendCurrentTimestamp() {
AAudioServiceMessage command;
+ // Send a timestamp for the clock model.
aaudio_result_t result = getFreeRunningPosition(&command.timestamp.position,
&command.timestamp.timestamp);
if (result == AAUDIO_OK) {
- // ALOGD("sendCurrentTimestamp(): position = %lld, nanos = %lld",
- // (long long) command.timestamp.position,
- // (long long) command.timestamp.timestamp);
- command.what = AAudioServiceMessage::code::TIMESTAMP;
+ ALOGV("sendCurrentTimestamp() SERVICE %8lld at %lld",
+ (long long) command.timestamp.position,
+ (long long) command.timestamp.timestamp);
+ command.what = AAudioServiceMessage::code::TIMESTAMP_SERVICE;
result = writeUpMessageQueue(&command);
- } else if (result == AAUDIO_ERROR_UNAVAILABLE) {
+
+ if (result == AAUDIO_OK) {
+ // Send a hardware timestamp for presentation time.
+ result = getHardwareTimestamp(&command.timestamp.position,
+ &command.timestamp.timestamp);
+ if (result == AAUDIO_OK) {
+ ALOGV("sendCurrentTimestamp() HARDWARE %8lld at %lld",
+ (long long) command.timestamp.position,
+ (long long) command.timestamp.timestamp);
+ command.what = AAudioServiceMessage::code::TIMESTAMP_HARDWARE;
+ result = writeUpMessageQueue(&command);
+ }
+ }
+ }
+
+ if (result == AAUDIO_ERROR_UNAVAILABLE) { // TODO review best error code
result = AAUDIO_OK; // just not available yet, try again later
}
return result;
@@ -230,8 +382,19 @@
* used to communicate with the underlying HAL or Service.
*/
aaudio_result_t AAudioServiceStreamBase::getDescription(AudioEndpointParcelable &parcelable) {
- // Gather information on the message queue.
- mUpMessageQueue->fillParcelable(parcelable,
- parcelable.mUpMessageQueueParcelable);
- return getDownDataDescription(parcelable);
+ {
+ std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
+ if (mUpMessageQueue == nullptr) {
+ ALOGE("getDescription(): mUpMessageQueue null! - stream not open");
+ return AAUDIO_ERROR_NULL;
+ }
+ // Gather information on the message queue.
+ mUpMessageQueue->fillParcelable(parcelable,
+ parcelable.mUpMessageQueueParcelable);
+ }
+ return getAudioDataDescription(parcelable);
+}
+
+void AAudioServiceStreamBase::onVolumeChanged(float volume) {
+ sendServiceEvent(AAUDIO_SERVICE_EVENT_VOLUME, volume);
}
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index cebefec..815b1cc 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -20,6 +20,7 @@
#include <assert.h>
#include <mutex>
+#include <media/AudioClient.h>
#include <utils/RefBase.h>
#include "fifo/FifoBuffer.h"
@@ -27,71 +28,97 @@
#include "binding/AudioEndpointParcelable.h"
#include "binding/AAudioServiceMessage.h"
#include "utility/AAudioUtilities.h"
-#include <media/AudioClient.h>
+#include "utility/AudioClock.h"
#include "SharedRingBuffer.h"
#include "AAudioThread.h"
+namespace android {
+ class AAudioService;
+}
+
namespace aaudio {
+class AAudioServiceEndpoint;
+
// We expect the queue to only have a few commands.
// This should be way more than we need.
#define QUEUE_UP_CAPACITY_COMMANDS (128)
/**
- * Base class for a stream in the AAudio service.
+ * Each instance of AAudioServiceStreamBase corresponds to a client stream.
+ * It uses a subclass of AAudioServiceEndpoint to communicate with the underlying device or port.
*/
class AAudioServiceStreamBase
: public virtual android::RefBase
+ , public AAudioStreamParameters
, public Runnable {
public:
- AAudioServiceStreamBase();
+ AAudioServiceStreamBase(android::AAudioService &aAudioService);
+
virtual ~AAudioServiceStreamBase();
enum {
ILLEGAL_THREAD_ID = 0
};
- std::string dump() const;
+ static std::string dumpHeader();
+
+ // does not include EOL
+ virtual std::string dump() const;
// -------------------------------------------------------------------
/**
* Open the device.
*/
- virtual aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
- aaudio::AAudioStreamConfiguration &configurationOutput) = 0;
+ virtual aaudio_result_t open(const aaudio::AAudioStreamRequest &request) = 0;
virtual aaudio_result_t close();
/**
- * Start the flow of data.
+ * Start the flow of audio data.
+ *
+ * This is not guaranteed to be synchronous but it currently is.
+ * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
*/
virtual aaudio_result_t start();
/**
- * Stop the flow of data such that start() can resume with loss of data.
- */
+ * Stop the flow of data so that start() can resume without loss of data.
+ *
+ * This is not guaranteed to be synchronous but it currently is.
+ * An AAUDIO_SERVICE_EVENT_PAUSED will be sent to the client when complete.
+ */
virtual aaudio_result_t pause();
/**
- * Stop the flow of data after data in buffer has played.
+ * Stop the flow of data after the currently queued data has finished playing.
+ *
+ * This is not guaranteed to be synchronous but it currently is.
+ * An AAUDIO_SERVICE_EVENT_STOPPED will be sent to the client when complete.
+ *
*/
virtual aaudio_result_t stop();
aaudio_result_t stopTimestampThread();
/**
- * Discard any data held by the underlying HAL or Service.
+ * Discard any data held by the underlying HAL or Service.
+ *
+ * An AAUDIO_SERVICE_EVENT_FLUSHED will be sent to the client when complete.
*/
virtual aaudio_result_t flush();
+
virtual aaudio_result_t startClient(const android::AudioClient& client __unused,
audio_port_handle_t *clientHandle __unused) {
+ ALOGD("AAudioServiceStreamBase::startClient(%p, ...) AAUDIO_ERROR_UNAVAILABLE", &client);
return AAUDIO_ERROR_UNAVAILABLE;
}
virtual aaudio_result_t stopClient(audio_port_handle_t clientHandle __unused) {
+ ALOGD("AAudioServiceStreamBase::stopClient(%d) AAUDIO_ERROR_UNAVAILABLE", clientHandle);
return AAUDIO_ERROR_UNAVAILABLE;
}
@@ -126,14 +153,14 @@
return mFramesPerBurst;
}
- int32_t calculateBytesPerFrame() const {
- return mSamplesPerFrame * AAudioConvert_formatToSizeInBytes(mAudioFormat);
- }
-
void run() override; // to implement Runnable
void disconnect();
+ const android::AudioClient &getAudioClient() {
+ return mMmapClient;
+ }
+
uid_t getOwnerUserId() const {
return mMmapClient.clientUid;
}
@@ -153,12 +180,26 @@
return mState;
}
+ void onVolumeChanged(float volume);
+
protected:
+ /**
+ * Open the device.
+ */
+ aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
+ aaudio_sharing_mode_t sharingMode);
+
void setState(aaudio_stream_state_t state) {
mState = state;
}
+ /**
+ * Device specific startup.
+ * @return AAUDIO_OK or negative error.
+ */
+ virtual aaudio_result_t startDevice();
+
aaudio_result_t writeUpMessageQueue(AAudioServiceMessage *command);
aaudio_result_t sendCurrentTimestamp();
@@ -170,27 +211,35 @@
*/
virtual aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) = 0;
- virtual aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) = 0;
+ virtual aaudio_result_t getHardwareTimestamp(int64_t *positionFrames, int64_t *timeNanos) = 0;
+
+ virtual aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) = 0;
aaudio_stream_state_t mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
pid_t mRegisteredClientThread = ILLEGAL_THREAD_ID;
SharedRingBuffer* mUpMessageQueue;
- std::mutex mLockUpMessageQueue;
+ std::mutex mUpMessageQueueLock;
- AAudioThread mAAudioThread;
+ AAudioThread mTimestampThread;
// This is used by one thread to tell another thread to exit. So it must be atomic.
- std::atomic<bool> mThreadEnabled;
+ std::atomic<bool> mThreadEnabled{false};
- aaudio_format_t mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED;
int32_t mFramesPerBurst = 0;
- int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED;
- int32_t mSampleRate = AAUDIO_UNSPECIFIED;
- int32_t mCapacityInFrames = AAUDIO_UNSPECIFIED;
- android::AudioClient mMmapClient;
+ android::AudioClient mMmapClient; // set in open, used in MMAP start()
audio_port_handle_t mClientHandle = AUDIO_PORT_HANDLE_NONE;
+ SimpleDoubleBuffer<Timestamp> mAtomicTimestamp;
+
+ android::AAudioService &mAudioService;
+
+ // The mServiceEndpoint variable can be accessed by multiple threads.
+ // So we access it by locally promoting a weak pointer to a smart pointer,
+ // which is thread-safe.
+ android::sp<AAudioServiceEndpoint> mServiceEndpoint;
+ android::wp<AAudioServiceEndpoint> mServiceEndpointWeak;
+
private:
aaudio_handle_t mHandle = -1;
};
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 08dd680..2e7ff8b 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -19,225 +19,81 @@
#include <utils/Log.h>
#include <atomic>
+#include <iomanip>
+#include <iostream>
#include <stdint.h>
#include <utils/String16.h>
#include <media/nbaio/AudioStreamOutSink.h>
#include <media/MmapStreamInterface.h>
+#include "binding/AudioEndpointParcelable.h"
+#include "utility/AAudioUtilities.h"
+
+#include "AAudioServiceEndpointMMAP.h"
#include "AAudioServiceStreamBase.h"
#include "AAudioServiceStreamMMAP.h"
-#include "binding/AudioEndpointParcelable.h"
#include "SharedMemoryProxy.h"
-#include "utility/AAudioUtilities.h"
using android::base::unique_fd;
using namespace android;
using namespace aaudio;
-#define AAUDIO_BUFFER_CAPACITY_MIN 4 * 512
-#define AAUDIO_SAMPLE_RATE_DEFAULT 48000
-
/**
* Service Stream that uses an MMAP buffer.
*/
-AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(const android::AudioClient& serviceClient,
+AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(android::AAudioService &aAudioService,
bool inService)
- : AAudioServiceStreamBase()
- , mMmapStreamCallback(new MyMmapStreamCallback(*this))
- , mPreviousFrameCounter(0)
- , mMmapStream(nullptr)
- , mServiceClient(serviceClient)
+ : AAudioServiceStreamBase(aAudioService)
, mInService(inService) {
}
aaudio_result_t AAudioServiceStreamMMAP::close() {
- if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+ if (getState() == AAUDIO_STREAM_STATE_CLOSED) {
return AAUDIO_OK;
}
+
stop();
- if (mMmapStream != 0) {
- mMmapStream.clear(); // TODO review. Is that all we have to do?
- // Apparently the above close is asynchronous. An attempt to open a new device
- // right after a close can fail. Also some callbacks may still be in flight!
- // FIXME Make closing synchronous.
- AudioClock::sleepForNanos(100 * AAUDIO_NANOS_PER_MILLISECOND);
- }
return AAudioServiceStreamBase::close();
}
// Open stream on HAL and pass information about the shared memory buffer back to the client.
-aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest &request,
- aaudio::AAudioStreamConfiguration &configurationOutput) {
- const audio_attributes_t attributes = {
- .content_type = AUDIO_CONTENT_TYPE_MUSIC,
- .usage = AUDIO_USAGE_MEDIA,
- .source = AUDIO_SOURCE_VOICE_RECOGNITION,
- .flags = AUDIO_FLAG_LOW_LATENCY,
- .tags = ""
- };
- audio_config_base_t config;
+aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest &request) {
- aaudio_result_t result = AAudioServiceStreamBase::open(request, configurationOutput);
+ sp<AAudioServiceStreamMMAP> keep(this);
+
+ aaudio_result_t result = AAudioServiceStreamBase::open(request,
+ AAUDIO_SHARING_MODE_EXCLUSIVE);
if (result != AAUDIO_OK) {
- ALOGE("AAudioServiceStreamBase open returned %d", result);
return result;
}
- const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
- audio_port_handle_t deviceId = configurationInput.getDeviceId();
- aaudio_direction_t direction = request.getDirection();
-
- // Fill in config
- aaudio_format_t aaudioFormat = configurationInput.getFormat();
- if (aaudioFormat == AAUDIO_UNSPECIFIED || aaudioFormat == AAUDIO_FORMAT_PCM_FLOAT) {
- aaudioFormat = AAUDIO_FORMAT_PCM_I16;
- }
- config.format = AAudioConvert_aaudioToAndroidDataFormat(aaudioFormat);
-
- int32_t aaudioSampleRate = configurationInput.getSampleRate();
- if (aaudioSampleRate == AAUDIO_UNSPECIFIED) {
- aaudioSampleRate = AAUDIO_SAMPLE_RATE_DEFAULT;
- }
- config.sample_rate = aaudioSampleRate;
-
- int32_t aaudioSamplesPerFrame = configurationInput.getSamplesPerFrame();
-
- if (direction == AAUDIO_DIRECTION_OUTPUT) {
- config.channel_mask = (aaudioSamplesPerFrame == AAUDIO_UNSPECIFIED)
- ? AUDIO_CHANNEL_OUT_STEREO
- : audio_channel_out_mask_from_count(aaudioSamplesPerFrame);
- } else if (direction == AAUDIO_DIRECTION_INPUT) {
- config.channel_mask = (aaudioSamplesPerFrame == AAUDIO_UNSPECIFIED)
- ? AUDIO_CHANNEL_IN_STEREO
- : audio_channel_in_mask_from_count(aaudioSamplesPerFrame);
- } else {
- ALOGE("openMmapStream - invalid direction = %d", direction);
- return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
}
- MmapStreamInterface::stream_direction_t streamDirection = (direction == AAUDIO_DIRECTION_OUTPUT)
- ? MmapStreamInterface::DIRECTION_OUTPUT : MmapStreamInterface::DIRECTION_INPUT;
-
- // Open HAL stream.
- status_t status = MmapStreamInterface::openMmapStream(streamDirection,
- &attributes,
- &config,
- mMmapClient,
- &deviceId,
- mMmapStreamCallback,
- mMmapStream,
- &mPortHandle);
- if (status != OK) {
- ALOGE("openMmapStream returned status %d", status);
- return AAUDIO_ERROR_UNAVAILABLE;
+ result = endpoint->registerStream(keep);
+ if (result != AAUDIO_OK) {
+ return result;
}
- if (deviceId == AAUDIO_UNSPECIFIED) {
- ALOGW("AAudioServiceStreamMMAP::open() - openMmapStream() failed to set deviceId");
- }
-
- // Create MMAP/NOIRQ buffer.
- int32_t minSizeFrames = configurationInput.getBufferCapacity();
- if (minSizeFrames <= 0) { // zero will get rejected
- minSizeFrames = AAUDIO_BUFFER_CAPACITY_MIN;
- }
- status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
- if (status != OK) {
- ALOGE("AAudioServiceStreamMMAP::open() - createMmapBuffer() returned status %d",
- status);
- return AAUDIO_ERROR_UNAVAILABLE;
- } else {
- ALOGD("createMmapBuffer status = %d, buffer_size = %d, burst_size %d"
- ", Sharable FD: %s",
- status,
- abs(mMmapBufferinfo.buffer_size_frames),
- mMmapBufferinfo.burst_size_frames,
- mMmapBufferinfo.buffer_size_frames < 0 ? "Yes" : "No");
- }
-
- mCapacityInFrames = mMmapBufferinfo.buffer_size_frames;
- // FIXME: the audio HAL indicates if the shared memory fd can be shared outside of audioserver
- // by returning a negative buffer size
- if (mCapacityInFrames < 0) {
- // Exclusive mode is possible from any client
- mCapacityInFrames = -mCapacityInFrames;
- } else {
- // exclusive mode is only possible if the final fd destination is inside audioserver
- if ((mMmapClient.clientUid != mServiceClient.clientUid) &&
- configurationInput.getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
- // Fallback is handled by caller but indicate what is possible in case
- // this is used in the future
- configurationOutput.setSharingMode(AAUDIO_SHARING_MODE_SHARED);
- return AAUDIO_ERROR_UNAVAILABLE;
- }
- }
-
- // Get information about the stream and pass it back to the caller.
- mSamplesPerFrame = (direction == AAUDIO_DIRECTION_OUTPUT)
- ? audio_channel_count_from_out_mask(config.channel_mask)
- : audio_channel_count_from_in_mask(config.channel_mask);
-
- // AAudio creates a copy of this FD and retains ownership of the copy.
- // Assume that AudioFlinger will close the original shared_memory_fd.
- mAudioDataFileDescriptor.reset(dup(mMmapBufferinfo.shared_memory_fd));
- if (mAudioDataFileDescriptor.get() == -1) {
- ALOGE("AAudioServiceStreamMMAP::open() - could not dup shared_memory_fd");
- return AAUDIO_ERROR_INTERNAL; // TODO review
- }
- mFramesPerBurst = mMmapBufferinfo.burst_size_frames;
- mAudioFormat = AAudioConvert_androidToAAudioDataFormat(config.format);
- mSampleRate = config.sample_rate;
-
- // Scale up the burst size to meet the minimum equivalent in microseconds.
- // This is to avoid waking the CPU too often when the HW burst is very small
- // or at high sample rates.
- int32_t burstMinMicros = AAudioProperty_getHardwareBurstMinMicros();
- int32_t burstMicros = 0;
- do {
- if (burstMicros > 0) { // skip first loop
- mFramesPerBurst *= 2;
- }
- burstMicros = mFramesPerBurst * static_cast<int64_t>(1000000) / mSampleRate;
- } while (burstMicros < burstMinMicros);
-
- ALOGD("AAudioServiceStreamMMAP::open() original burst = %d, minMicros = %d, final burst = %d\n",
- mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst);
-
- ALOGD("AAudioServiceStreamMMAP::open() actual rate = %d, channels = %d, deviceId = %d\n",
- mSampleRate, mSamplesPerFrame, deviceId);
-
- // Fill in AAudioStreamConfiguration
- configurationOutput.setSampleRate(mSampleRate);
- configurationOutput.setSamplesPerFrame(mSamplesPerFrame);
- configurationOutput.setFormat(mAudioFormat);
- configurationOutput.setDeviceId(deviceId);
-
setState(AAUDIO_STREAM_STATE_OPEN);
+
return AAUDIO_OK;
}
/**
* Start the flow of data.
*/
-aaudio_result_t AAudioServiceStreamMMAP::start() {
- if (isRunning()) {
- return AAUDIO_OK;
- }
- if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
- aaudio_result_t result;
- status_t status = mMmapStream->start(mServiceClient, &mPortHandle);
- if (status != OK) {
- ALOGE("AAudioServiceStreamMMAP::start() mMmapStream->start() returned %d", status);
- disconnect();
- result = AAudioConvert_androidToAAudioResult(status);
- } else {
- result = AAudioServiceStreamBase::start();
- if (!mInService && result == AAUDIO_OK) {
- startClient(mMmapClient, &mClientHandle);
- }
+aaudio_result_t AAudioServiceStreamMMAP::startDevice() {
+ aaudio_result_t result = AAudioServiceStreamBase::startDevice();
+ if (!mInService && result == AAUDIO_OK) {
+ // Note that this can sometimes take 200 to 300 msec for a cold start!
+ result = startClient(mMmapClient, &mClientHandle);
}
return result;
}
@@ -249,104 +105,106 @@
if (!isRunning()) {
return AAUDIO_OK;
}
- if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
- aaudio_result_t result1 = AAudioServiceStreamBase::pause();
+ aaudio_result_t result = AAudioServiceStreamBase::pause();
+ // TODO put before base::pause()?
if (!mInService) {
- stopClient(mClientHandle);
+ (void) stopClient(mClientHandle);
}
- status_t status = mMmapStream->stop(mPortHandle);
- mFramesRead.reset32();
- return (result1 != AAUDIO_OK) ? result1 : AAudioConvert_androidToAAudioResult(status);
+ return result;
}
aaudio_result_t AAudioServiceStreamMMAP::stop() {
if (!isRunning()) {
return AAUDIO_OK;
}
- if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
- aaudio_result_t result1 = AAudioServiceStreamBase::stop();
+ aaudio_result_t result = AAudioServiceStreamBase::stop();
+ // TODO put before base::stop()?
if (!mInService) {
- stopClient(mClientHandle);
- }
- aaudio_result_t status = mMmapStream->stop(mPortHandle);
- mFramesRead.reset32();
- return (result1 != AAUDIO_OK) ? result1 : AAudioConvert_androidToAAudioResult(status);
-}
-
-/**
- * Discard any data held by the underlying HAL or Service.
- */
-aaudio_result_t AAudioServiceStreamMMAP::flush() {
- if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
- // TODO how do we flush an MMAP/NOIRQ buffer? sync pointers?
- return AAudioServiceStreamBase::flush();;
-}
-
-aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
- audio_port_handle_t *clientHandle) {
- return AAudioConvert_androidToAAudioResult(mMmapStream->start(client, clientHandle));
-}
-
-aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) {
- return AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
-}
-
-aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positionFrames,
- int64_t *timeNanos) {
- struct audio_mmap_position position;
- if (mMmapStream == nullptr) {
- disconnect();
- return AAUDIO_ERROR_NULL;
- }
- status_t status = mMmapStream->getMmapPosition(&position);
- aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
- if (result == AAUDIO_ERROR_UNAVAILABLE) {
- ALOGW("sendCurrentTimestamp(): getMmapPosition() has no position data yet");
- } else if (result != AAUDIO_OK) {
- ALOGE("sendCurrentTimestamp(): getMmapPosition() returned status %d", status);
- disconnect();
- } else {
- mFramesRead.update32(position.position_frames);
- *positionFrames = mFramesRead.get();
- *timeNanos = position.time_nanoseconds;
+ (void) stopClient(mClientHandle);
}
return result;
}
-void AAudioServiceStreamMMAP::onTearDown() {
- ALOGD("AAudioServiceStreamMMAP::onTearDown() called");
- disconnect();
-};
+aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
+ audio_port_handle_t *clientHandle) {
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ // Start the client on behalf of the application. Generate a new porthandle.
+ aaudio_result_t result = endpoint->startClient(client, clientHandle);
+ return result;
+}
-void AAudioServiceStreamMMAP::onVolumeChanged(audio_channel_mask_t channels,
- android::Vector<float> values) {
- // TODO do we really need a different volume for each channel?
- float volume = values[0];
- ALOGD("AAudioServiceStreamMMAP::onVolumeChanged() volume[0] = %f", volume);
- sendServiceEvent(AAUDIO_SERVICE_EVENT_VOLUME, volume);
-};
+aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) {
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ aaudio_result_t result = endpoint->stopClient(clientHandle);
+ return result;
+}
-void AAudioServiceStreamMMAP::onRoutingChanged(audio_port_handle_t deviceId) {
- ALOGD("AAudioServiceStreamMMAP::onRoutingChanged() called with %d, old = %d",
- deviceId, mDeviceId);
- if (mDeviceId != AUDIO_PORT_HANDLE_NONE && mDeviceId != deviceId) {
+// Get free-running DSP or DMA hardware position from the HAL.
+aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positionFrames,
+ int64_t *timeNanos) {
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
+ static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
+
+ aaudio_result_t result = serviceEndpointMMAP->getFreeRunningPosition(positionFrames, timeNanos);
+ if (result == AAUDIO_OK) {
+ Timestamp timestamp(*positionFrames, *timeNanos);
+ mAtomicTimestamp.write(timestamp);
+ *positionFrames = timestamp.getPosition();
+ *timeNanos = timestamp.getNanoseconds();
+ } else if (result != AAUDIO_ERROR_UNAVAILABLE) {
disconnect();
}
- mDeviceId = deviceId;
-};
+ return result;
+}
+
+// Get timestamp that was written by getFreeRunningPosition()
+aaudio_result_t AAudioServiceStreamMMAP::getHardwareTimestamp(int64_t *positionFrames,
+ int64_t *timeNanos) {
+
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
+ static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
+
+ // TODO Get presentation timestamp from the HAL
+ if (mAtomicTimestamp.isValid()) {
+ Timestamp timestamp = mAtomicTimestamp.read();
+ *positionFrames = timestamp.getPosition();
+ *timeNanos = timestamp.getNanoseconds() + serviceEndpointMMAP->getHardwareTimeOffsetNanos();
+ return AAUDIO_OK;
+ } else {
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+}
/**
* Get an immutable description of the data queue from the HAL.
*/
-aaudio_result_t AAudioServiceStreamMMAP::getDownDataDescription(AudioEndpointParcelable &parcelable)
+aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription(
+ AudioEndpointParcelable &parcelable)
{
- // Gather information on the data queue based on HAL info.
- int32_t bytesPerFrame = calculateBytesPerFrame();
- int32_t capacityInBytes = mCapacityInFrames * bytesPerFrame;
- int fdIndex = parcelable.addFileDescriptor(mAudioDataFileDescriptor, capacityInBytes);
- parcelable.mDownDataQueueParcelable.setupMemory(fdIndex, 0, capacityInBytes);
- parcelable.mDownDataQueueParcelable.setBytesPerFrame(bytesPerFrame);
- parcelable.mDownDataQueueParcelable.setFramesPerBurst(mFramesPerBurst);
- parcelable.mDownDataQueueParcelable.setCapacityInFrames(mCapacityInFrames);
- return AAUDIO_OK;
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
+ static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
+ return serviceEndpointMMAP->getDownDataDescription(parcelable);
}
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index b69dc46..e2415d0 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -37,27 +37,20 @@
namespace aaudio {
- /**
- * Manage one memory mapped buffer that originated from a HAL.
- */
-class AAudioServiceStreamMMAP
- : public AAudioServiceStreamBase
- , public android::MmapStreamCallback {
+
+/**
+ * These corresponds to an EXCLUSIVE mode MMAP client stream.
+ * It has exclusive use of one AAudioServiceEndpointMMAP to communicate with the underlying
+ * device or port.
+ */
+class AAudioServiceStreamMMAP : public AAudioServiceStreamBase {
public:
- AAudioServiceStreamMMAP(const android::AudioClient& serviceClient, bool inService);
+ AAudioServiceStreamMMAP(android::AAudioService &aAudioService,
+ bool inService);
virtual ~AAudioServiceStreamMMAP() = default;
- aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
- aaudio::AAudioStreamConfiguration &configurationOutput) override;
-
- /**
- * Start the flow of audio data.
- *
- * This is not guaranteed to be synchronous but it currently is.
- * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
- */
- aaudio_result_t start() override;
+ aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
/**
* Stop the flow of data so that start() can resume without loss of data.
@@ -69,79 +62,34 @@
aaudio_result_t stop() override;
- /**
- * Discard any data held by the underlying HAL or Service.
- *
- * This is not guaranteed to be synchronous but it currently is.
- * An AAUDIO_SERVICE_EVENT_FLUSHED will be sent to the client when complete.
- */
- aaudio_result_t flush() override;
+ aaudio_result_t startClient(const android::AudioClient& client,
+ audio_port_handle_t *clientHandle) override;
+
+ aaudio_result_t stopClient(audio_port_handle_t clientHandle) override;
aaudio_result_t close() override;
- virtual aaudio_result_t startClient(const android::AudioClient& client,
- audio_port_handle_t *clientHandle);
-
- virtual aaudio_result_t stopClient(audio_port_handle_t clientHandle);
-
/**
* Send a MMAP/NOIRQ buffer timestamp to the client.
*/
- aaudio_result_t sendCurrentTimestamp();
-
- // -------------- Callback functions ---------------------
- void onTearDown() override;
-
- void onVolumeChanged(audio_channel_mask_t channels,
- android::Vector<float> values) override;
-
- void onRoutingChanged(audio_port_handle_t deviceId) override;
protected:
- aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) override;
+ aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) override;
aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
+ aaudio_result_t getHardwareTimestamp(int64_t *positionFrames, int64_t *timeNanos) override;
+
+ /**
+ * Device specific startup.
+ * @return AAUDIO_OK or negative error.
+ */
+ aaudio_result_t startDevice() override;
+
private:
- // This proxy class was needed to prevent a crash in AudioFlinger
- // when the stream was closed.
- class MyMmapStreamCallback : public android::MmapStreamCallback {
- public:
- explicit MyMmapStreamCallback(android::MmapStreamCallback &serviceCallback)
- : mServiceCallback(serviceCallback){}
- virtual ~MyMmapStreamCallback() = default;
- void onTearDown() override {
- mServiceCallback.onTearDown();
- };
-
- void onVolumeChanged(audio_channel_mask_t channels, android::Vector<float> values) override
- {
- mServiceCallback.onVolumeChanged(channels, values);
- };
-
- void onRoutingChanged(audio_port_handle_t deviceId) override {
- mServiceCallback.onRoutingChanged(deviceId);
- };
-
- private:
- android::MmapStreamCallback &mServiceCallback;
- };
-
- android::sp<MyMmapStreamCallback> mMmapStreamCallback;
- MonotonicCounter mFramesWritten;
- MonotonicCounter mFramesRead;
- int32_t mPreviousFrameCounter = 0; // from HAL
-
- // Interface to the AudioFlinger MMAP support.
- android::sp<android::MmapStreamInterface> mMmapStream;
- struct audio_mmap_buffer_info mMmapBufferinfo;
- audio_port_handle_t mPortHandle = AUDIO_PORT_HANDLE_NONE;
- audio_port_handle_t mDeviceId = AUDIO_PORT_HANDLE_NONE;
- android::AudioClient mServiceClient;
- bool mInService = false;
- android::base::unique_fd mAudioDataFileDescriptor;
+ bool mInService = false;
};
} // namespace aaudio
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 5654113..f55c40d 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -18,6 +18,8 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <iomanip>
+#include <iostream>
#include <mutex>
#include <aaudio/AAudio.h>
@@ -40,8 +42,32 @@
#define MAX_FRAMES_PER_BUFFER (32 * 1024)
AAudioServiceStreamShared::AAudioServiceStreamShared(AAudioService &audioService)
- : mAudioService(audioService)
- {
+ : AAudioServiceStreamBase(audioService)
+ , mTimestampPositionOffset(0)
+ , mXRunCount(0) {
+}
+
+std::string AAudioServiceStreamShared::dumpHeader() {
+ std::stringstream result;
+ result << AAudioServiceStreamBase::dumpHeader();
+ result << " Write# Read# Avail XRuns";
+ return result.str();
+}
+
+std::string AAudioServiceStreamShared::dump() const {
+ std::stringstream result;
+
+ result << AAudioServiceStreamBase::dump();
+
+ auto fifo = mAudioDataQueue->getFifoBuffer();
+ int32_t readCounter = fifo->getReadCounter();
+ int32_t writeCounter = fifo->getWriteCounter();
+ result << std::setw(10) << writeCounter;
+ result << std::setw(10) << readCounter;
+ result << std::setw(8) << (writeCounter - readCounter);
+ result << std::setw(8) << getXRunCount();
+
+ return result.str();
}
int32_t AAudioServiceStreamShared::calculateBufferCapacity(int32_t requestedCapacityFrames,
@@ -90,89 +116,79 @@
return capacityInFrames;
}
-aaudio_result_t AAudioServiceStreamShared::open(const aaudio::AAudioStreamRequest &request,
- aaudio::AAudioStreamConfiguration &configurationOutput) {
+aaudio_result_t AAudioServiceStreamShared::open(const aaudio::AAudioStreamRequest &request) {
sp<AAudioServiceStreamShared> keep(this);
- aaudio_result_t result = AAudioServiceStreamBase::open(request, configurationOutput);
+ aaudio_result_t result = AAudioServiceStreamBase::open(request, AAUDIO_SHARING_MODE_SHARED);
if (result != AAUDIO_OK) {
ALOGE("AAudioServiceStreamBase open() returned %d", result);
return result;
}
const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
- aaudio_direction_t direction = request.getDirection();
- AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
- mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService, configurationOutput, direction);
- if (mServiceEndpoint == nullptr) {
- ALOGE("AAudioServiceStreamShared::open() mServiceEndPoint = %p", mServiceEndpoint);
- return AAUDIO_ERROR_UNAVAILABLE;
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ result = AAUDIO_ERROR_INVALID_STATE;
+ goto error;
}
// Is the request compatible with the shared endpoint?
- mAudioFormat = configurationInput.getFormat();
- if (mAudioFormat == AAUDIO_FORMAT_UNSPECIFIED) {
- mAudioFormat = AAUDIO_FORMAT_PCM_FLOAT;
- } else if (mAudioFormat != AAUDIO_FORMAT_PCM_FLOAT) {
- ALOGE("AAudioServiceStreamShared::open() mAudioFormat = %d, need FLOAT", mAudioFormat);
+ setFormat(configurationInput.getFormat());
+ if (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) {
+ setFormat(AAUDIO_FORMAT_PCM_FLOAT);
+ } else if (getFormat() != AAUDIO_FORMAT_PCM_FLOAT) {
+ ALOGE("AAudioServiceStreamShared::open() mAudioFormat = %d, need FLOAT", getFormat());
result = AAUDIO_ERROR_INVALID_FORMAT;
goto error;
}
- mSampleRate = configurationInput.getSampleRate();
- if (mSampleRate == AAUDIO_UNSPECIFIED) {
- mSampleRate = mServiceEndpoint->getSampleRate();
- } else if (mSampleRate != mServiceEndpoint->getSampleRate()) {
+ setSampleRate(configurationInput.getSampleRate());
+ if (getSampleRate() == AAUDIO_UNSPECIFIED) {
+ setSampleRate(endpoint->getSampleRate());
+ } else if (getSampleRate() != endpoint->getSampleRate()) {
ALOGE("AAudioServiceStreamShared::open() mSampleRate = %d, need %d",
- mSampleRate, mServiceEndpoint->getSampleRate());
+ getSampleRate(), endpoint->getSampleRate());
result = AAUDIO_ERROR_INVALID_RATE;
goto error;
}
- mSamplesPerFrame = configurationInput.getSamplesPerFrame();
- if (mSamplesPerFrame == AAUDIO_UNSPECIFIED) {
- mSamplesPerFrame = mServiceEndpoint->getSamplesPerFrame();
- } else if (mSamplesPerFrame != mServiceEndpoint->getSamplesPerFrame()) {
+ setSamplesPerFrame(configurationInput.getSamplesPerFrame());
+ if (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) {
+ setSamplesPerFrame(endpoint->getSamplesPerFrame());
+ } else if (getSamplesPerFrame() != endpoint->getSamplesPerFrame()) {
ALOGE("AAudioServiceStreamShared::open() mSamplesPerFrame = %d, need %d",
- mSamplesPerFrame, mServiceEndpoint->getSamplesPerFrame());
+ getSamplesPerFrame(), endpoint->getSamplesPerFrame());
result = AAUDIO_ERROR_OUT_OF_RANGE;
goto error;
}
- mFramesPerBurst = mServiceEndpoint->getFramesPerBurst();
- ALOGD("AAudioServiceStreamShared::open() mSampleRate = %d, mFramesPerBurst = %d",
- mSampleRate, mFramesPerBurst);
-
- mCapacityInFrames = calculateBufferCapacity(configurationInput.getBufferCapacity(),
- mFramesPerBurst);
- if (mCapacityInFrames < 0) {
- result = mCapacityInFrames; // negative error code
- mCapacityInFrames = 0;
+ setBufferCapacity(calculateBufferCapacity(configurationInput.getBufferCapacity(),
+ mFramesPerBurst));
+ if (getBufferCapacity() < 0) {
+ result = getBufferCapacity(); // negative error code
+ setBufferCapacity(0);
goto error;
}
- // Create audio data shared memory buffer for client.
- mAudioDataQueue = new SharedRingBuffer();
- result = mAudioDataQueue->allocate(calculateBytesPerFrame(), mCapacityInFrames);
- if (result != AAUDIO_OK) {
- ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames",
- mCapacityInFrames);
- result = AAUDIO_ERROR_NO_MEMORY;
- goto error;
+ {
+ std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
+ // Create audio data shared memory buffer for client.
+ mAudioDataQueue = new SharedRingBuffer();
+ result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
+ if (result != AAUDIO_OK) {
+ ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames",
+ getBufferCapacity());
+ result = AAUDIO_ERROR_NO_MEMORY;
+ goto error;
+ }
}
ALOGD("AAudioServiceStreamShared::open() actual rate = %d, channels = %d, deviceId = %d",
- mSampleRate, mSamplesPerFrame, mServiceEndpoint->getDeviceId());
+ getSampleRate(), getSamplesPerFrame(), endpoint->getDeviceId());
- // Fill in configuration for client.
- configurationOutput.setSampleRate(mSampleRate);
- configurationOutput.setSamplesPerFrame(mSamplesPerFrame);
- configurationOutput.setFormat(mAudioFormat);
- configurationOutput.setDeviceId(mServiceEndpoint->getDeviceId());
-
- result = mServiceEndpoint->registerStream(keep);
+ result = endpoint->registerStream(keep);
if (result != AAUDIO_OK) {
goto error;
}
@@ -185,121 +201,30 @@
return result;
}
-/**
- * Start the flow of audio data.
- *
- * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
- */
-aaudio_result_t AAudioServiceStreamShared::start() {
- if (isRunning()) {
- return AAUDIO_OK;
- }
- AAudioServiceEndpoint *endpoint = mServiceEndpoint;
- if (endpoint == nullptr) {
- return AAUDIO_ERROR_INVALID_STATE;
- }
- // For output streams, this will add the stream to the mixer.
- aaudio_result_t result = endpoint->startStream(this);
- if (result != AAUDIO_OK) {
- ALOGE("AAudioServiceStreamShared::start() mServiceEndpoint returned %d", result);
- disconnect();
- } else {
- result = endpoint->getStreamInternal()->startClient(mMmapClient, &mClientHandle);
- if (result == AAUDIO_OK) {
- result = AAudioServiceStreamBase::start();
- }
- }
- return result;
-}
-
-/**
- * Stop the flow of data so that start() can resume without loss of data.
- *
- * An AAUDIO_SERVICE_EVENT_PAUSED will be sent to the client when complete.
-*/
-aaudio_result_t AAudioServiceStreamShared::pause() {
- if (!isRunning()) {
- return AAUDIO_OK;
- }
- AAudioServiceEndpoint *endpoint = mServiceEndpoint;
- if (endpoint == nullptr) {
- return AAUDIO_ERROR_INVALID_STATE;
- }
- endpoint->getStreamInternal()->stopClient(mClientHandle);
- aaudio_result_t result = endpoint->stopStream(this);
- if (result != AAUDIO_OK) {
- ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
- disconnect(); // TODO should we return or pause Base first?
- }
- return AAudioServiceStreamBase::pause();
-}
-
-aaudio_result_t AAudioServiceStreamShared::stop() {
- if (!isRunning()) {
- return AAUDIO_OK;
- }
- AAudioServiceEndpoint *endpoint = mServiceEndpoint;
- if (endpoint == nullptr) {
- return AAUDIO_ERROR_INVALID_STATE;
- }
- endpoint->getStreamInternal()->stopClient(mClientHandle);
- aaudio_result_t result = endpoint->stopStream(this);
- if (result != AAUDIO_OK) {
- ALOGE("AAudioServiceStreamShared::stop() mServiceEndpoint returned %d", result);
- disconnect();
- }
- return AAudioServiceStreamBase::stop();
-}
-
-/**
- * Discard any data held by the underlying HAL or Service.
- *
- * An AAUDIO_SERVICE_EVENT_FLUSHED will be sent to the client when complete.
- */
-aaudio_result_t AAudioServiceStreamShared::flush() {
- AAudioServiceEndpoint *endpoint = mServiceEndpoint;
- if (endpoint == nullptr) {
- return AAUDIO_ERROR_INVALID_STATE;
- }
- if (mState != AAUDIO_STREAM_STATE_PAUSED) {
- ALOGE("AAudioServiceStreamShared::flush() stream not paused, state = %s",
- AAudio_convertStreamStateToText(mState));
- return AAUDIO_ERROR_INVALID_STATE;
- }
- // Data will get flushed when the client receives the FLUSHED event.
- return AAudioServiceStreamBase::flush();
-}
aaudio_result_t AAudioServiceStreamShared::close() {
- if (mState == AAUDIO_STREAM_STATE_CLOSED) {
- return AAUDIO_OK;
- }
+ aaudio_result_t result = AAudioServiceStreamBase::close();
- stop();
-
- AAudioServiceEndpoint *endpoint = mServiceEndpoint;
- if (endpoint == nullptr) {
- return AAUDIO_ERROR_INVALID_STATE;
- }
-
- endpoint->unregisterStream(this);
-
- AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
- mEndpointManager.closeEndpoint(endpoint);
- mServiceEndpoint = nullptr;
-
- if (mAudioDataQueue != nullptr) {
+ {
+ std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
delete mAudioDataQueue;
mAudioDataQueue = nullptr;
}
- return AAudioServiceStreamBase::close();
+
+ return result;
}
/**
* Get an immutable description of the data queue created by this service.
*/
-aaudio_result_t AAudioServiceStreamShared::getDownDataDescription(AudioEndpointParcelable &parcelable)
+aaudio_result_t AAudioServiceStreamShared::getAudioDataDescription(
+ AudioEndpointParcelable &parcelable)
{
+ std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
+ if (mAudioDataQueue == nullptr) {
+ ALOGE("getAudioDataDescription(): mUpMessageQueue null! - stream not open");
+ return AAUDIO_ERROR_NULL;
+ }
// Gather information on the data queue.
mAudioDataQueue->fillParcelable(parcelable,
parcelable.mDownDataQueueParcelable);
@@ -307,15 +232,43 @@
return AAUDIO_OK;
}
-void AAudioServiceStreamShared::markTransferTime(int64_t nanoseconds) {
- mMarkedPosition = mAudioDataQueue->getFifoBuffer()->getReadCounter();
- mMarkedTime = nanoseconds;
+void AAudioServiceStreamShared::markTransferTime(Timestamp ×tamp) {
+ mAtomicTimestamp.write(timestamp);
}
+// Get timestamp that was written by mixer or distributor.
aaudio_result_t AAudioServiceStreamShared::getFreeRunningPosition(int64_t *positionFrames,
+ int64_t *timeNanos) {
+ // TODO Get presentation timestamp from the HAL
+ if (mAtomicTimestamp.isValid()) {
+ Timestamp timestamp = mAtomicTimestamp.read();
+ *positionFrames = timestamp.getPosition();
+ *timeNanos = timestamp.getNanoseconds();
+ return AAUDIO_OK;
+ } else {
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+}
+
+// Get timestamp from lower level service.
+aaudio_result_t AAudioServiceStreamShared::getHardwareTimestamp(int64_t *positionFrames,
int64_t *timeNanos) {
- // TODO get these two numbers as an atomic pair
- *positionFrames = mMarkedPosition;
- *timeNanos = mMarkedTime;
- return AAUDIO_OK;
+
+ int64_t position = 0;
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+
+ aaudio_result_t result = endpoint->getTimestamp(&position, timeNanos);
+ if (result == AAUDIO_OK) {
+ int64_t offset = mTimestampPositionOffset.load();
+ // TODO, do not go below starting value
+ position -= offset; // Offset from shared MMAP stream
+ ALOGV("getHardwareTimestamp() %8lld = %8lld - %8lld",
+ (long long) position, (long long) (position + offset), (long long) offset);
+ }
+ *positionFrames = position;
+ return result;
}
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index 6b67337..8499ea5 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -46,53 +46,55 @@
AAudioServiceStreamShared(android::AAudioService &aAudioService);
virtual ~AAudioServiceStreamShared() = default;
- aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
- aaudio::AAudioStreamConfiguration &configurationOutput) override;
+ static std::string dumpHeader();
- /**
- * Start the flow of audio data.
- *
- * This is not guaranteed to be synchronous but it currently is.
- * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
- */
- aaudio_result_t start() override;
+ std::string dump() const override;
- /**
- * Stop the flow of data so that start() can resume without loss of data.
- *
- * This is not guaranteed to be synchronous but it currently is.
- * An AAUDIO_SERVICE_EVENT_PAUSED will be sent to the client when complete.
- */
- aaudio_result_t pause() override;
-
- /**
- * Stop the flow of data after data in buffer has played.
- */
- aaudio_result_t stop() override;
-
- /**
- * Discard any data held by the underlying HAL or Service.
- *
- * This is not guaranteed to be synchronous but it currently is.
- * An AAUDIO_SERVICE_EVENT_FLUSHED will be sent to the client when complete.
- */
- aaudio_result_t flush() override;
+ aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
aaudio_result_t close() override;
- android::FifoBuffer *getDataFifoBuffer() { return mAudioDataQueue->getFifoBuffer(); }
+ /**
+ * This must be locked when calling getAudioDataFifoBuffer_l() and while
+ * using the FifoBuffer it returns.
+ */
+ std::mutex &getAudioDataQueueLock() {
+ return mAudioDataQueueLock;
+ }
+
+ /**
+ * This must only be call under getAudioDataQueueLock().
+ * @return
+ */
+ android::FifoBuffer *getAudioDataFifoBuffer_l() { return (mAudioDataQueue == nullptr)
+ ? nullptr
+ : mAudioDataQueue->getFifoBuffer(); }
/* Keep a record of when a buffer transfer completed.
* This allows for a more accurate timing model.
*/
- void markTransferTime(int64_t nanoseconds);
+ void markTransferTime(Timestamp ×tamp);
+
+ void setTimestampPositionOffset(int64_t deltaFrames) {
+ mTimestampPositionOffset.store(deltaFrames);
+ }
+
+ void incrementXRunCount() {
+ mXRunCount++;
+ }
+
+ int32_t getXRunCount() const {
+ return mXRunCount.load();
+ }
protected:
- aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) override;
+ aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) override;
aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
+ aaudio_result_t getHardwareTimestamp(int64_t *positionFrames, int64_t *timeNanos) override;
+
/**
* @param requestedCapacityFrames
* @param framesPerBurst
@@ -102,12 +104,12 @@
int32_t framesPerBurst);
private:
- android::AAudioService &mAudioService;
- AAudioServiceEndpoint *mServiceEndpoint = nullptr;
- SharedRingBuffer *mAudioDataQueue = nullptr;
+ SharedRingBuffer *mAudioDataQueue = nullptr; // protected by mAudioDataQueueLock
+ std::mutex mAudioDataQueueLock;
- int64_t mMarkedPosition = 0;
- int64_t mMarkedTime = 0;
+ std::atomic<int64_t> mTimestampPositionOffset;
+ std::atomic<int32_t> mXRunCount;
+
};
} /* namespace aaudio */
diff --git a/services/oboeservice/AAudioStreamTracker.cpp b/services/oboeservice/AAudioStreamTracker.cpp
new file mode 100644
index 0000000..ef88b34
--- /dev/null
+++ b/services/oboeservice/AAudioStreamTracker.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AAudioStreamTracker"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include <aaudio/AAudio.h>
+#include <utils/String16.h>
+
+#include "AAudioStreamTracker.h"
+
+using namespace android;
+using namespace aaudio;
+
+sp<AAudioServiceStreamBase> AAudioStreamTracker::removeStreamByHandle(
+ aaudio_handle_t streamHandle) {
+ std::lock_guard<std::mutex> lock(mHandleLock);
+ sp<AAudioServiceStreamBase> serviceStream;
+ auto it = mStreamsByHandle.find(streamHandle);
+ if (it != mStreamsByHandle.end()) {
+ serviceStream = it->second;
+ mStreamsByHandle.erase(it);
+ }
+ return serviceStream;
+}
+
+sp<AAudioServiceStreamBase> AAudioStreamTracker::getStreamByHandle(
+ aaudio_handle_t streamHandle) {
+ std::lock_guard<std::mutex> lock(mHandleLock);
+ sp<AAudioServiceStreamBase> serviceStream;
+ auto it = mStreamsByHandle.find(streamHandle);
+ if (it != mStreamsByHandle.end()) {
+ serviceStream = it->second;
+ }
+ return serviceStream;
+}
+
+// advance to next legal handle value
+__attribute__((no_sanitize("integer")))
+aaudio_handle_t AAudioStreamTracker::bumpHandle(aaudio_handle_t handle) {
+ handle++;
+ // Only use positive integers.
+ if (handle <= 0) {
+ handle = 1;
+ }
+ return handle;
+}
+
+aaudio_handle_t AAudioStreamTracker::addStreamForHandle(sp<AAudioServiceStreamBase> serviceStream) {
+ std::lock_guard<std::mutex> lock(mHandleLock);
+ aaudio_handle_t handle = mPreviousHandle.load();
+ // Assign a unique handle.
+ while (true) {
+ handle = bumpHandle(handle);
+ sp<AAudioServiceStreamBase> oldServiceStream = mStreamsByHandle[handle];
+ // Is this an unused handle? It would be extremely unlikely to wrap
+ // around and collide with a very old handle. But just in case.
+ if (oldServiceStream.get() == nullptr) {
+ mStreamsByHandle[handle] = serviceStream;
+ break;
+ }
+ }
+ mPreviousHandle.store(handle);
+ return handle;
+}
+
+std::string AAudioStreamTracker::dump() const {
+ std::stringstream result;
+ const bool isLocked = AAudio_tryUntilTrue(
+ [this]()->bool { return mHandleLock.try_lock(); } /* f */,
+ 50 /* times */,
+ 20 /* sleepMs */);
+ if (!isLocked) {
+ result << "AAudioStreamTracker may be deadlocked\n";
+ } else {
+ result << "Stream Handles:\n";
+ for (const auto& it : mStreamsByHandle) {
+ aaudio_handle_t handle = it.second->getHandle();
+ result << " 0x" << std::setfill('0') << std::setw(8) << std::hex << handle
+ << std::dec << std::setfill(' ') << "\n";
+ }
+
+ mHandleLock.unlock();
+ }
+ return result.str();
+}
diff --git a/services/oboeservice/AAudioStreamTracker.h b/services/oboeservice/AAudioStreamTracker.h
new file mode 100644
index 0000000..70d440d
--- /dev/null
+++ b/services/oboeservice/AAudioStreamTracker.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAUDIO_AAUDIO_STREAM_TRACKER_H
+#define AAUDIO_AAUDIO_STREAM_TRACKER_H
+
+#include <time.h>
+#include <pthread.h>
+
+#include <aaudio/AAudio.h>
+
+#include "binding/AAudioCommon.h"
+
+#include "AAudioServiceStreamBase.h"
+
+namespace aaudio {
+
+class AAudioStreamTracker {
+
+public:
+ /**
+ * Remove the stream associated with the handle.
+ * @param streamHandle
+ * @return strong pointer to the stream if found or to nullptr
+ */
+ android::sp<AAudioServiceStreamBase> removeStreamByHandle(aaudio_handle_t streamHandle);
+
+ /**
+ * Look up a stream based on the handle.
+ * @param streamHandle
+ * @return strong pointer to the stream if found or to nullptr
+ */
+ android::sp<aaudio::AAudioServiceStreamBase> getStreamByHandle(aaudio_handle_t streamHandle);
+
+ /**
+ * Store a strong pointer to the stream and return a unique handle for future reference.
+ * The handle is guaranteed not to collide with an existing stream.
+ * @param serviceStream
+ * @return handle for identifying the stream
+ */
+ aaudio_handle_t addStreamForHandle(android::sp<AAudioServiceStreamBase> serviceStream);
+
+ /**
+ * @return string that can be added to dumpsys
+ */
+ std::string dump() const;
+
+private:
+ static aaudio_handle_t bumpHandle(aaudio_handle_t handle);
+
+ // Track stream using a unique handle that wraps. Only use positive half.
+ mutable std::mutex mHandleLock;
+ std::atomic<aaudio_handle_t> mPreviousHandle{0};
+ std::map<aaudio_handle_t, android::sp<aaudio::AAudioServiceStreamBase>> mStreamsByHandle;
+};
+
+
+} /* namespace aaudio */
+
+#endif /* AAUDIO_AAUDIO_STREAM_TRACKER_H */
diff --git a/services/oboeservice/AAudioThread.cpp b/services/oboeservice/AAudioThread.cpp
index ebb50f8..c6fb57d 100644
--- a/services/oboeservice/AAudioThread.cpp
+++ b/services/oboeservice/AAudioThread.cpp
@@ -53,7 +53,7 @@
aaudio_result_t AAudioThread::start(Runnable *runnable) {
if (mHasThread) {
- ALOGE("AAudioThread::start() - mHasThread.load() already true");
+ ALOGE("AAudioThread::start() - mHasThread already true");
return AAUDIO_ERROR_INVALID_STATE;
}
// mRunnable will be read by the new thread when it starts.
@@ -71,6 +71,7 @@
aaudio_result_t AAudioThread::stop() {
if (!mHasThread) {
+ ALOGE("AAudioThread::stop() but no thread running");
return AAUDIO_ERROR_INVALID_STATE;
}
int err = pthread_join(mThread, nullptr);
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
index a896a7a..584b2ef 100644
--- a/services/oboeservice/Android.mk
+++ b/services/oboeservice/Android.mk
@@ -22,7 +22,6 @@
$(TOP)/frameworks/av/media/libaaudio/src
LOCAL_SRC_FILES += \
- $(LIBAAUDIO_SRC_DIR)/utility/HandleTracker.cpp \
SharedMemoryProxy.cpp \
SharedRingBuffer.cpp \
AAudioClientTracker.cpp \
@@ -31,10 +30,13 @@
AAudioService.cpp \
AAudioServiceEndpoint.cpp \
AAudioServiceEndpointCapture.cpp \
+ AAudioServiceEndpointMMAP.cpp \
AAudioServiceEndpointPlay.cpp \
+ AAudioServiceEndpointShared.cpp \
AAudioServiceStreamBase.cpp \
AAudioServiceStreamMMAP.cpp \
AAudioServiceStreamShared.cpp \
+ AAudioStreamTracker.cpp \
TimestampScheduler.cpp \
AAudioThread.cpp
diff --git a/services/oboeservice/OWNERS b/services/oboeservice/OWNERS
new file mode 100644
index 0000000..f4d51f9
--- /dev/null
+++ b/services/oboeservice/OWNERS
@@ -0,0 +1 @@
+philburk@google.com
diff --git a/services/oboeservice/SharedMemoryProxy.cpp b/services/oboeservice/SharedMemoryProxy.cpp
index fc4532c..c31557e 100644
--- a/services/oboeservice/SharedMemoryProxy.cpp
+++ b/services/oboeservice/SharedMemoryProxy.cpp
@@ -16,12 +16,11 @@
#define LOG_TAG "AAudioService"
//#define LOG_NDEBUG 0
-#include <utils/Log.h>
+#include <log/log.h>
#include <aaudio/AAudio.h>
#include "SharedMemoryProxy.h"
-using namespace android;
using namespace aaudio;
SharedMemoryProxy::~SharedMemoryProxy()
diff --git a/services/radio/Android.mk b/services/radio/Android.mk
deleted file mode 100644
index 1b50dc3..0000000
--- a/services/radio/Android.mk
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-
-LOCAL_SRC_FILES:= \
- RadioService.cpp
-
-LOCAL_SHARED_LIBRARIES:= \
- liblog \
- libutils \
- libbinder \
- libcutils \
- libaudioclient \
- libhardware \
- libradio \
- libradio_metadata
-
-ifeq ($(USE_LEGACY_LOCAL_AUDIO_HAL),true)
-# libhardware configuration
-LOCAL_SRC_FILES += \
- RadioHalLegacy.cpp
-else
-# Treble configuration
-
-LOCAL_SRC_FILES += \
- HidlUtils.cpp \
- RadioHalHidl.cpp
-
-LOCAL_SHARED_LIBRARIES += \
- libhwbinder \
- libhidlbase \
- libhidltransport \
- libbase \
- libaudiohal \
- android.hardware.broadcastradio@1.0
-endif
-
-LOCAL_CFLAGS += -Wall -Wextra -Werror
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_MODULE:= libradioservice
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/radio/HidlUtils.cpp b/services/radio/HidlUtils.cpp
deleted file mode 100644
index 6895377..0000000
--- a/services/radio/HidlUtils.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define LOG_TAG "HidlUtils"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <utils/misc.h>
-#include <system/radio_metadata.h>
-
-#include "HidlUtils.h"
-
-namespace android {
-
-using android::hardware::broadcastradio::V1_0::MetadataType;
-using android::hardware::broadcastradio::V1_0::Band;
-using android::hardware::broadcastradio::V1_0::Deemphasis;
-using android::hardware::broadcastradio::V1_0::Rds;
-
-//static
-int HidlUtils::convertHalResult(Result result)
-{
- switch (result) {
- case Result::OK:
- return 0;
- case Result::INVALID_ARGUMENTS:
- return -EINVAL;
- case Result::INVALID_STATE:
- return -ENOSYS;
- case Result::TIMEOUT:
- return -ETIMEDOUT;
- case Result::NOT_INITIALIZED:
- default:
- return -ENODEV;
- }
-}
-
-
-//static
-void HidlUtils::convertBandConfigToHal(BandConfig *halConfig,
- const radio_hal_band_config_t *config)
-{
- halConfig->type = static_cast<Band>(config->type);
- halConfig->antennaConnected = config->antenna_connected;
- halConfig->lowerLimit = config->lower_limit;
- halConfig->upperLimit = config->upper_limit;
- halConfig->spacings.setToExternal(const_cast<unsigned int *>(&config->spacings[0]),
- config->num_spacings * sizeof(uint32_t));
- // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
- halConfig->spacings.resize(config->num_spacings);
-
- if (halConfig->type == Band::FM) {
- halConfig->ext.fm.deemphasis = static_cast<Deemphasis>(config->fm.deemphasis);
- halConfig->ext.fm.stereo = config->fm.stereo;
- halConfig->ext.fm.rds = static_cast<Rds>(config->fm.rds);
- halConfig->ext.fm.ta = config->fm.ta;
- halConfig->ext.fm.af = config->fm.af;
- halConfig->ext.fm.ea = config->fm.ea;
- } else {
- halConfig->ext.am.stereo = config->am.stereo;
- }
-}
-
-//static
-void HidlUtils::convertPropertiesFromHal(radio_hal_properties_t *properties,
- const Properties *halProperties)
-{
- properties->class_id = static_cast<radio_class_t>(halProperties->classId);
- strlcpy(properties->implementor, halProperties->implementor.c_str(), RADIO_STRING_LEN_MAX);
- strlcpy(properties->product, halProperties->product.c_str(), RADIO_STRING_LEN_MAX);
- strlcpy(properties->version, halProperties->version.c_str(), RADIO_STRING_LEN_MAX);
- strlcpy(properties->serial, halProperties->serial.c_str(), RADIO_STRING_LEN_MAX);
- properties->num_tuners = halProperties->numTuners;
- properties->num_audio_sources = halProperties->numAudioSources;
- properties->supports_capture = halProperties->supportsCapture;
- properties->num_bands = halProperties->bands.size();
-
- for (size_t i = 0; i < halProperties->bands.size(); i++) {
- convertBandConfigFromHal(&properties->bands[i], &halProperties->bands[i]);
- }
-}
-
-//static
-void HidlUtils::convertBandConfigFromHal(radio_hal_band_config_t *config,
- const BandConfig *halConfig)
-{
- config->type = static_cast<radio_band_t>(halConfig->type);
- config->antenna_connected = halConfig->antennaConnected;
- config->lower_limit = halConfig->lowerLimit;
- config->upper_limit = halConfig->upperLimit;
- config->num_spacings = halConfig->spacings.size();
- if (config->num_spacings > RADIO_NUM_SPACINGS_MAX) {
- config->num_spacings = RADIO_NUM_SPACINGS_MAX;
- }
- memcpy(config->spacings, halConfig->spacings.data(),
- sizeof(uint32_t) * config->num_spacings);
-
- if (halConfig->type == Band::FM) {
- config->fm.deemphasis = static_cast<radio_deemphasis_t>(halConfig->ext.fm.deemphasis);
- config->fm.stereo = halConfig->ext.fm.stereo;
- config->fm.rds = static_cast<radio_rds_t>(halConfig->ext.fm.rds);
- config->fm.ta = halConfig->ext.fm.ta;
- config->fm.af = halConfig->ext.fm.af;
- config->fm.ea = halConfig->ext.fm.ea;
- } else {
- config->am.stereo = halConfig->ext.am.stereo;
- }
-}
-
-
-//static
-void HidlUtils::convertProgramInfoFromHal(radio_program_info_t *info,
- const ProgramInfo *halInfo)
-{
- info->channel = halInfo->channel;
- info->sub_channel = halInfo->subChannel;
- info->tuned = halInfo->tuned;
- info->stereo = halInfo->stereo;
- info->digital = halInfo->digital;
- info->signal_strength = halInfo->signalStrength;
- convertMetaDataFromHal(&info->metadata, halInfo->metadata,
- halInfo->channel, halInfo->subChannel);
-}
-
-// TODO(twasilczyk): drop unnecessary channel info
-//static
-void HidlUtils::convertMetaDataFromHal(radio_metadata_t **metadata,
- const hidl_vec<MetaData>& halMetadata,
- uint32_t channel __unused,
- uint32_t subChannel __unused)
-{
-
- if (metadata == nullptr || *metadata == nullptr) {
- ALOGE("destination metadata buffer is a nullptr");
- return;
- }
- for (size_t i = 0; i < halMetadata.size(); i++) {
- radio_metadata_key_t key = static_cast<radio_metadata_key_t>(halMetadata[i].key);
- radio_metadata_type_t type = static_cast<radio_metadata_key_t>(halMetadata[i].type);
- radio_metadata_clock_t clock;
-
- switch (type) {
- case RADIO_METADATA_TYPE_INT:
- radio_metadata_add_int(metadata, key, halMetadata[i].intValue);
- break;
- case RADIO_METADATA_TYPE_TEXT:
- radio_metadata_add_text(metadata, key, halMetadata[i].stringValue.c_str());
- break;
- case RADIO_METADATA_TYPE_RAW:
- radio_metadata_add_raw(metadata, key,
- halMetadata[i].rawValue.data(),
- halMetadata[i].rawValue.size());
- break;
- case RADIO_METADATA_TYPE_CLOCK:
- clock.utc_seconds_since_epoch =
- halMetadata[i].clockValue.utcSecondsSinceEpoch;
- clock.timezone_offset_in_minutes =
- halMetadata[i].clockValue.timezoneOffsetInMinutes;
- radio_metadata_add_clock(metadata, key, &clock);
- break;
- default:
- ALOGW("%s invalid metadata type %u",__FUNCTION__, halMetadata[i].type);
- break;
- }
- }
-}
-
-} // namespace android
diff --git a/services/radio/HidlUtils.h b/services/radio/HidlUtils.h
deleted file mode 100644
index c771060..0000000
--- a/services/radio/HidlUtils.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_HARDWARE_RADIO_HAL_HIDL_UTILS_H
-#define ANDROID_HARDWARE_RADIO_HAL_HIDL_UTILS_H
-
-#include <android/hardware/broadcastradio/1.0/types.h>
-#include <hardware/radio.h>
-
-namespace android {
-
-using android::hardware::hidl_vec;
-using android::hardware::broadcastradio::V1_0::Result;
-using android::hardware::broadcastradio::V1_0::Properties;
-using android::hardware::broadcastradio::V1_0::BandConfig;
-using android::hardware::broadcastradio::V1_0::ProgramInfo;
-using android::hardware::broadcastradio::V1_0::MetaData;
-
-class HidlUtils {
-public:
- static int convertHalResult(Result result);
- static void convertBandConfigFromHal(radio_hal_band_config_t *config,
- const BandConfig *halConfig);
- static void convertPropertiesFromHal(radio_hal_properties_t *properties,
- const Properties *halProperties);
- static void convertBandConfigToHal(BandConfig *halConfig,
- const radio_hal_band_config_t *config);
- static void convertProgramInfoFromHal(radio_program_info_t *info,
- const ProgramInfo *halInfo);
- static void convertMetaDataFromHal(radio_metadata_t **metadata,
- const hidl_vec<MetaData>& halMetadata,
- uint32_t channel,
- uint32_t subChannel);
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_RADIO_HAL_HIDL_UTILS_H
diff --git a/services/radio/RadioHalHidl.cpp b/services/radio/RadioHalHidl.cpp
deleted file mode 100644
index f637275..0000000
--- a/services/radio/RadioHalHidl.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "RadioHalHidl"
-//#define LOG_NDEBUG 0
-
-#include <media/audiohal/hidl/HalDeathHandler.h>
-#include <utils/Log.h>
-#include <utils/misc.h>
-#include <system/RadioMetadataWrapper.h>
-#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
-
-#include "RadioHalHidl.h"
-#include "HidlUtils.h"
-
-namespace android {
-
-using android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
-using android::hardware::broadcastradio::V1_0::Class;
-using android::hardware::broadcastradio::V1_0::Direction;
-using android::hardware::broadcastradio::V1_0::Properties;
-
-
-/* static */
-sp<RadioInterface> RadioInterface::connectModule(radio_class_t classId)
-{
- return new RadioHalHidl(classId);
-}
-
-int RadioHalHidl::getProperties(radio_hal_properties_t *properties)
-{
- ALOGV("%s IN", __FUNCTION__);
- sp<IBroadcastRadio> module = getService();
- if (module == 0) {
- return -ENODEV;
- }
- Properties halProperties;
- Result halResult = Result::NOT_INITIALIZED;
- Return<void> hidlReturn =
- module->getProperties([&](Result result, const Properties& properties) {
- halResult = result;
- if (result == Result::OK) {
- halProperties = properties;
- }
- });
-
- if (halResult == Result::OK) {
- HidlUtils::convertPropertiesFromHal(properties, &halProperties);
- }
- return HidlUtils::convertHalResult(halResult);
-}
-
-int RadioHalHidl::openTuner(const radio_hal_band_config_t *config,
- bool audio,
- sp<TunerCallbackInterface> callback,
- sp<TunerInterface>& tuner)
-{
- sp<IBroadcastRadio> module = getService();
- if (module == 0) {
- return -ENODEV;
- }
- sp<Tuner> tunerImpl = new Tuner(callback, this);
-
- BandConfig halConfig;
- Result halResult = Result::NOT_INITIALIZED;
- sp<ITuner> halTuner;
-
- HidlUtils::convertBandConfigToHal(&halConfig, config);
- Return<void> hidlReturn =
- module->openTuner(halConfig, audio, tunerImpl,
- [&](Result result, const sp<ITuner>& tuner) {
- halResult = result;
- if (result == Result::OK) {
- halTuner = tuner;
- }
- });
-
- if (halResult == Result::OK) {
- tunerImpl->setHalTuner(halTuner);
- tuner = tunerImpl;
- }
-
- return HidlUtils::convertHalResult(halResult);
-}
-
-int RadioHalHidl::closeTuner(sp<TunerInterface>& tuner)
-{
- sp<Tuner> tunerImpl = static_cast<Tuner *>(tuner.get());
- sp<ITuner> clearTuner;
- tunerImpl->setHalTuner(clearTuner);
- return 0;
-}
-
-RadioHalHidl::RadioHalHidl(radio_class_t classId)
- : mClassId(classId)
-{
-}
-
-RadioHalHidl::~RadioHalHidl()
-{
-}
-
-sp<IBroadcastRadio> RadioHalHidl::getService()
-{
- if (mHalModule == 0) {
- sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService();
- if (factory != 0) {
- factory->connectModule(static_cast<Class>(mClassId),
- [&](Result retval, const ::android::sp<IBroadcastRadio>& result) {
- if (retval == Result::OK) {
- mHalModule = result;
- }
- });
- }
- }
- ALOGV("%s OUT module %p", __FUNCTION__, mHalModule.get());
- return mHalModule;
-}
-
-void RadioHalHidl::clearService()
-{
- ALOGV("%s IN module %p", __FUNCTION__, mHalModule.get());
- mHalModule.clear();
-}
-
-
-int RadioHalHidl::Tuner::setConfiguration(const radio_hal_band_config_t *config)
-{
- ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
-
- if (mHalTuner == 0) {
- return -ENODEV;
- }
- BandConfig halConfig;
- HidlUtils::convertBandConfigToHal(&halConfig, config);
-
- Return<Result> hidlResult = mHalTuner->setConfiguration(halConfig);
- return HidlUtils::convertHalResult(hidlResult);
-}
-
-int RadioHalHidl::Tuner::getConfiguration(radio_hal_band_config_t *config)
-{
- ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
- if (mHalTuner == 0) {
- return -ENODEV;
- }
- BandConfig halConfig;
- Result halResult;
- Return<void> hidlReturn =
- mHalTuner->getConfiguration([&](Result result, const BandConfig& config) {
- halResult = result;
- if (result == Result::OK) {
- halConfig = config;
- }
- });
- if (hidlReturn.isOk() && halResult == Result::OK) {
- HidlUtils::convertBandConfigFromHal(config, &halConfig);
- }
- return HidlUtils::convertHalResult(halResult);
-}
-
-int RadioHalHidl::Tuner::scan(radio_direction_t direction, bool skip_sub_channel)
-{
- ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
- if (mHalTuner == 0) {
- return -ENODEV;
- }
- Return<Result> hidlResult =
- mHalTuner->scan(static_cast<Direction>(direction), skip_sub_channel);
- return HidlUtils::convertHalResult(hidlResult);
-}
-
-int RadioHalHidl::Tuner::step(radio_direction_t direction, bool skip_sub_channel)
-{
- ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
- if (mHalTuner == 0) {
- return -ENODEV;
- }
- Return<Result> hidlResult =
- mHalTuner->step(static_cast<Direction>(direction), skip_sub_channel);
- return HidlUtils::convertHalResult(hidlResult);
-}
-
-int RadioHalHidl::Tuner::tune(unsigned int channel, unsigned int sub_channel)
-{
- ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
- if (mHalTuner == 0) {
- return -ENODEV;
- }
- Return<Result> hidlResult =
- mHalTuner->tune(channel, sub_channel);
- return HidlUtils::convertHalResult(hidlResult);
-}
-
-int RadioHalHidl::Tuner::cancel()
-{
- ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
- if (mHalTuner == 0) {
- return -ENODEV;
- }
- Return<Result> hidlResult = mHalTuner->cancel();
- return HidlUtils::convertHalResult(hidlResult);
-}
-
-int RadioHalHidl::Tuner::getProgramInformation(radio_program_info_t *info)
-{
- ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
- if (mHalTuner == 0) {
- return -ENODEV;
- }
- if (info == nullptr || info->metadata == nullptr) {
- return BAD_VALUE;
- }
- ProgramInfo halInfo;
- Result halResult;
- Return<void> hidlReturn = mHalTuner->getProgramInformation(
- [&](Result result, const ProgramInfo& info) {
- halResult = result;
- if (result == Result::OK) {
- halInfo = info;
- }
- });
- if (hidlReturn.isOk() && halResult == Result::OK) {
- HidlUtils::convertProgramInfoFromHal(info, &halInfo);
- }
- return HidlUtils::convertHalResult(halResult);
-}
-
-Return<void> RadioHalHidl::Tuner::hardwareFailure()
-{
- ALOGV("%s IN", __FUNCTION__);
- handleHwFailure();
- return Return<void>();
-}
-
-Return<void> RadioHalHidl::Tuner::configChange(Result result, const BandConfig& config)
-{
- ALOGV("%s IN", __FUNCTION__);
- radio_hal_event_t event;
- memset(&event, 0, sizeof(radio_hal_event_t));
- event.type = RADIO_EVENT_CONFIG;
- event.status = HidlUtils::convertHalResult(result);
- HidlUtils::convertBandConfigFromHal(&event.config, &config);
- onCallback(&event);
- return Return<void>();
-}
-
-Return<void> RadioHalHidl::Tuner::tuneComplete(Result result, const ProgramInfo& info)
-{
- ALOGV("%s IN", __FUNCTION__);
- radio_hal_event_t event = {};
- RadioMetadataWrapper metadataWrapper(&event.info.metadata);
-
- event.type = RADIO_EVENT_TUNED;
- event.status = HidlUtils::convertHalResult(result);
- HidlUtils::convertProgramInfoFromHal(&event.info, &info);
- onCallback(&event);
- return Return<void>();
-}
-
-Return<void> RadioHalHidl::Tuner::afSwitch(const ProgramInfo& info)
-{
- ALOGV("%s IN", __FUNCTION__);
- radio_hal_event_t event = {};
- RadioMetadataWrapper metadataWrapper(&event.info.metadata);
-
- event.type = RADIO_EVENT_AF_SWITCH;
- HidlUtils::convertProgramInfoFromHal(&event.info, &info);
- onCallback(&event);
- return Return<void>();
-}
-
-Return<void> RadioHalHidl::Tuner::antennaStateChange(bool connected)
-{
- ALOGV("%s IN", __FUNCTION__);
- radio_hal_event_t event;
- memset(&event, 0, sizeof(radio_hal_event_t));
- event.type = RADIO_EVENT_ANTENNA;
- event.on = connected;
- onCallback(&event);
- return Return<void>();
-}
-Return<void> RadioHalHidl::Tuner::trafficAnnouncement(bool active)
-{
- ALOGV("%s IN", __FUNCTION__);
- radio_hal_event_t event;
- memset(&event, 0, sizeof(radio_hal_event_t));
- event.type = RADIO_EVENT_TA;
- event.on = active;
- onCallback(&event);
- return Return<void>();
-}
-Return<void> RadioHalHidl::Tuner::emergencyAnnouncement(bool active)
-{
- ALOGV("%s IN", __FUNCTION__);
- radio_hal_event_t event;
- memset(&event, 0, sizeof(radio_hal_event_t));
- event.type = RADIO_EVENT_EA;
- event.on = active;
- onCallback(&event);
- return Return<void>();
-}
-Return<void> RadioHalHidl::Tuner::newMetadata(uint32_t channel, uint32_t subChannel,
- const ::android::hardware::hidl_vec<MetaData>& metadata)
-{
- ALOGV("%s IN", __FUNCTION__);
- radio_hal_event_t event = {};
- RadioMetadataWrapper metadataWrapper(&event.metadata);
-
- event.type = RADIO_EVENT_METADATA;
- HidlUtils::convertMetaDataFromHal(&event.metadata, metadata, channel, subChannel);
- onCallback(&event);
- return Return<void>();
-}
-
-
-RadioHalHidl::Tuner::Tuner(sp<TunerCallbackInterface> callback, sp<RadioHalHidl> module)
- : TunerInterface(), mHalTuner(NULL), mCallback(callback), mParentModule(module)
-{
- // Make sure the handler we are passing in only deals with const members,
- // as it can be called on an arbitrary thread.
- const auto& self = this;
- HalDeathHandler::getInstance()->registerAtExitHandler(
- this, [&self]() { self->sendHwFailureEvent(); });
-}
-
-
-RadioHalHidl::Tuner::~Tuner()
-{
- HalDeathHandler::getInstance()->unregisterAtExitHandler(this);
-}
-
-void RadioHalHidl::Tuner::setHalTuner(sp<ITuner>& halTuner) {
- if (mHalTuner != 0) {
- mHalTuner->unlinkToDeath(HalDeathHandler::getInstance());
- }
- mHalTuner = halTuner;
- if (mHalTuner != 0) {
- mHalTuner->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
- }
-}
-
-void RadioHalHidl::Tuner::handleHwFailure()
-{
- ALOGV("%s IN", __FUNCTION__);
- sp<RadioHalHidl> parentModule = mParentModule.promote();
- if (parentModule != 0) {
- parentModule->clearService();
- }
- sendHwFailureEvent();
- mHalTuner.clear();
-}
-
-void RadioHalHidl::Tuner::sendHwFailureEvent() const
-{
- radio_hal_event_t event;
- memset(&event, 0, sizeof(radio_hal_event_t));
- event.type = RADIO_EVENT_HW_FAILURE;
- onCallback(&event);
-}
-
-void RadioHalHidl::Tuner::onCallback(radio_hal_event_t *halEvent) const
-{
- if (mCallback != 0) {
- mCallback->onEvent(halEvent);
- }
-}
-
-} // namespace android
diff --git a/services/radio/RadioHalHidl.h b/services/radio/RadioHalHidl.h
deleted file mode 100644
index f98420d..0000000
--- a/services/radio/RadioHalHidl.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_RADIO_HAL_HIDL_H
-#define ANDROID_HARDWARE_RADIO_HAL_HIDL_H
-
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-#include "RadioInterface.h"
-#include "TunerInterface.h"
-#include "TunerCallbackInterface.h"
-#include <android/hardware/broadcastradio/1.0/types.h>
-#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
-#include <android/hardware/broadcastradio/1.0/ITuner.h>
-#include <android/hardware/broadcastradio/1.0/ITunerCallback.h>
-
-namespace android {
-
-using android::hardware::Return;
-using android::hardware::broadcastradio::V1_0::Result;
-using android::hardware::broadcastradio::V1_0::IBroadcastRadio;
-using android::hardware::broadcastradio::V1_0::ITuner;
-using android::hardware::broadcastradio::V1_0::ITunerCallback;
-
-using android::hardware::broadcastradio::V1_0::BandConfig;
-using android::hardware::broadcastradio::V1_0::ProgramInfo;
-using android::hardware::broadcastradio::V1_0::MetaData;
-
-class RadioHalHidl : public RadioInterface
-{
-public:
- RadioHalHidl(radio_class_t classId);
-
- // RadioInterface
- virtual int getProperties(radio_hal_properties_t *properties);
- virtual int openTuner(const radio_hal_band_config_t *config,
- bool audio,
- sp<TunerCallbackInterface> callback,
- sp<TunerInterface>& tuner);
- virtual int closeTuner(sp<TunerInterface>& tuner);
-
- class Tuner : public TunerInterface, public virtual ITunerCallback
- {
- public:
- Tuner(sp<TunerCallbackInterface> callback, sp<RadioHalHidl> module);
-
- // TunerInterface
- virtual int setConfiguration(const radio_hal_band_config_t *config);
- virtual int getConfiguration(radio_hal_band_config_t *config);
- virtual int scan(radio_direction_t direction, bool skip_sub_channel);
- virtual int step(radio_direction_t direction, bool skip_sub_channel);
- virtual int tune(unsigned int channel, unsigned int sub_channel);
- virtual int cancel();
- virtual int getProgramInformation(radio_program_info_t *info);
-
- // ITunerCallback
- virtual Return<void> hardwareFailure();
- virtual Return<void> configChange(Result result, const BandConfig& config);
- virtual Return<void> tuneComplete(Result result, const ProgramInfo& info);
- virtual Return<void> afSwitch(const ProgramInfo& info);
- virtual Return<void> antennaStateChange(bool connected);
- virtual Return<void> trafficAnnouncement(bool active);
- virtual Return<void> emergencyAnnouncement(bool active);
- virtual Return<void> newMetadata(uint32_t channel, uint32_t subChannel,
- const ::android::hardware::hidl_vec<MetaData>& metadata);
-
- void setHalTuner(sp<ITuner>& halTuner);
- sp<ITuner> getHalTuner() { return mHalTuner; }
-
- private:
- virtual ~Tuner();
-
- void onCallback(radio_hal_event_t *halEvent) const;
- void handleHwFailure();
- void sendHwFailureEvent() const;
-
- sp<ITuner> mHalTuner;
- const sp<TunerCallbackInterface> mCallback;
- wp<RadioHalHidl> mParentModule;
- };
-
- sp<IBroadcastRadio> getService();
- void clearService();
-
-private:
- virtual ~RadioHalHidl();
-
- radio_class_t mClassId;
- sp<IBroadcastRadio> mHalModule;
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_RADIO_HAL_HIDL_H
diff --git a/services/radio/RadioHalLegacy.cpp b/services/radio/RadioHalLegacy.cpp
deleted file mode 100644
index d50ccd4..0000000
--- a/services/radio/RadioHalLegacy.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "RadioHalLegacy"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <utils/misc.h>
-#include "RadioHalLegacy.h"
-
-namespace android {
-
-const char *RadioHalLegacy::sClassModuleNames[] = {
- RADIO_HARDWARE_MODULE_ID_FM, /* corresponds to RADIO_CLASS_AM_FM */
- RADIO_HARDWARE_MODULE_ID_SAT, /* corresponds to RADIO_CLASS_SAT */
- RADIO_HARDWARE_MODULE_ID_DT, /* corresponds to RADIO_CLASS_DT */
-};
-
-/* static */
-sp<RadioInterface> RadioInterface::connectModule(radio_class_t classId)
-{
- return new RadioHalLegacy(classId);
-}
-
-RadioHalLegacy::RadioHalLegacy(radio_class_t classId)
- : RadioInterface(), mClassId(classId), mHwDevice(NULL)
-{
-}
-
-void RadioHalLegacy::onFirstRef()
-{
- const hw_module_t *mod;
- int rc;
- ALOGI("%s mClassId %d", __FUNCTION__, mClassId);
-
- mHwDevice = NULL;
-
- if ((mClassId < 0) ||
- (mClassId >= NELEM(sClassModuleNames))) {
- ALOGE("invalid class ID %d", mClassId);
- return;
- }
-
- ALOGI("%s RADIO_HARDWARE_MODULE_ID %s %s",
- __FUNCTION__, RADIO_HARDWARE_MODULE_ID, sClassModuleNames[mClassId]);
-
- rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, sClassModuleNames[mClassId], &mod);
- if (rc != 0) {
- ALOGE("couldn't load radio module %s.%s (%s)",
- RADIO_HARDWARE_MODULE_ID, sClassModuleNames[mClassId], strerror(-rc));
- return;
- }
- rc = radio_hw_device_open(mod, &mHwDevice);
- if (rc != 0) {
- ALOGE("couldn't open radio hw device in %s.%s (%s)",
- RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc));
- mHwDevice = NULL;
- return;
- }
- if (mHwDevice->common.version != RADIO_DEVICE_API_VERSION_CURRENT) {
- ALOGE("wrong radio hw device version %04x", mHwDevice->common.version);
- radio_hw_device_close(mHwDevice);
- mHwDevice = NULL;
- }
-}
-
-RadioHalLegacy::~RadioHalLegacy()
-{
- if (mHwDevice != NULL) {
- radio_hw_device_close(mHwDevice);
- }
-}
-
-int RadioHalLegacy::getProperties(radio_hal_properties_t *properties)
-{
- if (mHwDevice == NULL) {
- return -ENODEV;
- }
-
- int rc = mHwDevice->get_properties(mHwDevice, properties);
- if (rc != 0) {
- ALOGE("could not read implementation properties");
- }
-
- return rc;
-}
-
-int RadioHalLegacy::openTuner(const radio_hal_band_config_t *config,
- bool audio,
- sp<TunerCallbackInterface> callback,
- sp<TunerInterface>& tuner)
-{
- if (mHwDevice == NULL) {
- return -ENODEV;
- }
- sp<Tuner> tunerImpl = new Tuner(callback);
-
- const struct radio_tuner *halTuner;
- int rc = mHwDevice->open_tuner(mHwDevice, config, audio,
- RadioHalLegacy::Tuner::callback, tunerImpl.get(),
- &halTuner);
- if (rc == 0) {
- tunerImpl->setHalTuner(halTuner);
- tuner = tunerImpl;
- }
- return rc;
-}
-
-int RadioHalLegacy::closeTuner(sp<TunerInterface>& tuner)
-{
- if (mHwDevice == NULL) {
- return -ENODEV;
- }
- if (tuner == 0) {
- return -EINVAL;
- }
- sp<Tuner> tunerImpl = (Tuner *)tuner.get();
- return mHwDevice->close_tuner(mHwDevice, tunerImpl->getHalTuner());
-}
-
-int RadioHalLegacy::Tuner::setConfiguration(const radio_hal_band_config_t *config)
-{
- if (mHalTuner == NULL) {
- return -ENODEV;
- }
- return mHalTuner->set_configuration(mHalTuner, config);
-}
-
-int RadioHalLegacy::Tuner::getConfiguration(radio_hal_band_config_t *config)
-{
- if (mHalTuner == NULL) {
- return -ENODEV;
- }
- return mHalTuner->get_configuration(mHalTuner, config);
-}
-
-int RadioHalLegacy::Tuner::scan(radio_direction_t direction, bool skip_sub_channel)
-{
- if (mHalTuner == NULL) {
- return -ENODEV;
- }
- return mHalTuner->scan(mHalTuner, direction, skip_sub_channel);
-}
-
-int RadioHalLegacy::Tuner::step(radio_direction_t direction, bool skip_sub_channel)
-{
- if (mHalTuner == NULL) {
- return -ENODEV;
- }
- return mHalTuner->step(mHalTuner, direction, skip_sub_channel);
-}
-
-int RadioHalLegacy::Tuner::tune(unsigned int channel, unsigned int sub_channel)
-{
- if (mHalTuner == NULL) {
- return -ENODEV;
- }
- return mHalTuner->tune(mHalTuner, channel, sub_channel);
-}
-
-int RadioHalLegacy::Tuner::cancel()
-{
- if (mHalTuner == NULL) {
- return -ENODEV;
- }
- return mHalTuner->cancel(mHalTuner);
-}
-
-int RadioHalLegacy::Tuner::getProgramInformation(radio_program_info_t *info)
-{
- if (mHalTuner == NULL) {
- return -ENODEV;
- }
- return mHalTuner->get_program_information(mHalTuner, info);
-}
-
-void RadioHalLegacy::Tuner::onCallback(radio_hal_event_t *halEvent)
-{
- if (mCallback != 0) {
- mCallback->onEvent(halEvent);
- }
-}
-
-//static
-void RadioHalLegacy::Tuner::callback(radio_hal_event_t *halEvent, void *cookie)
-{
- wp<RadioHalLegacy::Tuner> weak = wp<RadioHalLegacy::Tuner>((RadioHalLegacy::Tuner *)cookie);
- sp<RadioHalLegacy::Tuner> tuner = weak.promote();
- if (tuner != 0) {
- tuner->onCallback(halEvent);
- }
-}
-
-RadioHalLegacy::Tuner::Tuner(sp<TunerCallbackInterface> callback)
- : TunerInterface(), mHalTuner(NULL), mCallback(callback)
-{
-}
-
-
-RadioHalLegacy::Tuner::~Tuner()
-{
-}
-
-
-} // namespace android
diff --git a/services/radio/RadioHalLegacy.h b/services/radio/RadioHalLegacy.h
deleted file mode 100644
index 7d4831b..0000000
--- a/services/radio/RadioHalLegacy.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_RADIO_HAL_LEGACY_H
-#define ANDROID_HARDWARE_RADIO_HAL_LEGACY_H
-
-#include <utils/RefBase.h>
-#include <hardware/radio.h>
-#include "RadioInterface.h"
-#include "TunerInterface.h"
-#include "TunerCallbackInterface.h"
-
-namespace android {
-
-class RadioHalLegacy : public RadioInterface
-{
-public:
- RadioHalLegacy(radio_class_t classId);
-
- // RadioInterface
- virtual int getProperties(radio_hal_properties_t *properties);
- virtual int openTuner(const radio_hal_band_config_t *config,
- bool audio,
- sp<TunerCallbackInterface> callback,
- sp<TunerInterface>& tuner);
- virtual int closeTuner(sp<TunerInterface>& tuner);
-
- // RefBase
- virtual void onFirstRef();
-
- class Tuner : public TunerInterface
- {
- public:
- Tuner(sp<TunerCallbackInterface> callback);
-
- virtual int setConfiguration(const radio_hal_band_config_t *config);
- virtual int getConfiguration(radio_hal_band_config_t *config);
- virtual int scan(radio_direction_t direction, bool skip_sub_channel);
- virtual int step(radio_direction_t direction, bool skip_sub_channel);
- virtual int tune(unsigned int channel, unsigned int sub_channel);
- virtual int cancel();
- virtual int getProgramInformation(radio_program_info_t *info);
-
- static void callback(radio_hal_event_t *halEvent, void *cookie);
- void onCallback(radio_hal_event_t *halEvent);
-
- void setHalTuner(const struct radio_tuner *halTuner) { mHalTuner = halTuner; }
- const struct radio_tuner *getHalTuner() { return mHalTuner; }
-
- private:
- virtual ~Tuner();
-
- const struct radio_tuner *mHalTuner;
- sp<TunerCallbackInterface> mCallback;
- };
-
-protected:
- virtual ~RadioHalLegacy();
-
-private:
- static const char * sClassModuleNames[];
-
- radio_class_t mClassId;
- struct radio_hw_device *mHwDevice;
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_RADIO_HAL_LEGACY_H
diff --git a/services/radio/RadioInterface.h b/services/radio/RadioInterface.h
deleted file mode 100644
index fcfb4d5..0000000
--- a/services/radio/RadioInterface.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_RADIO_INTERFACE_H
-#define ANDROID_HARDWARE_RADIO_INTERFACE_H
-
-#include <utils/RefBase.h>
-#include <system/radio.h>
-#include "TunerInterface.h"
-#include "TunerCallbackInterface.h"
-
-namespace android {
-
-class RadioInterface : public virtual RefBase
-{
-public:
- /* get a sound trigger HAL instance */
- static sp<RadioInterface> connectModule(radio_class_t classId);
-
- /*
- * Retrieve implementation properties.
- *
- * arguments:
- * - properties: where to return the module properties
- *
- * returns:
- * 0 if no error
- * -EINVAL if invalid arguments are passed
- */
- virtual int getProperties(radio_hal_properties_t *properties) = 0;
-
- /*
- * Open a tuner interface for the requested configuration.
- * If no other tuner is opened, this will activate the radio module.
- *
- * arguments:
- * - config: the band configuration to apply
- * - audio: this tuner will be used for live radio listening and should be connected to
- * the radio audio source.
- * - callback: the event callback
- * - cookie: the cookie to pass when calling the callback
- * - tuner: where to return the tuner interface
- *
- * returns:
- * 0 if HW was powered up and configuration could be applied
- * -EINVAL if configuration requested is invalid
- * -ENOSYS if called out of sequence
- *
- * Callback function with event RADIO_EVENT_CONFIG MUST be called once the
- * configuration is applied or a failure occurs or after a time out.
- */
- virtual int openTuner(const radio_hal_band_config_t *config,
- bool audio,
- sp<TunerCallbackInterface> callback,
- sp<TunerInterface>& tuner) = 0;
-
- /*
- * Close a tuner interface.
- * If the last tuner is closed, the radio module is deactivated.
- *
- * arguments:
- * - tuner: the tuner interface to close
- *
- * returns:
- * 0 if powered down successfully.
- * -EINVAL if an invalid argument is passed
- * -ENOSYS if called out of sequence
- */
- virtual int closeTuner(sp<TunerInterface>& tuner) = 0;
-
-protected:
- RadioInterface() {}
- virtual ~RadioInterface() {}
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_RADIO_INTERFACE_H
diff --git a/services/radio/RadioRegions.h b/services/radio/RadioRegions.h
deleted file mode 100644
index d40ee83..0000000
--- a/services/radio/RadioRegions.h
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2015 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_HARDWARE_RADIO_REGIONS_H
-#define ANDROID_HARDWARE_RADIO_REGIONS_H
-
-namespace android {
-
-#define RADIO_BAND_LOWER_FM_ITU1 87500
-#define RADIO_BAND_UPPER_FM_ITU1 108000
-#define RADIO_BAND_SPACING_FM_ITU1 100
-
-#define RADIO_BAND_LOWER_FM_ITU2 87900
-#define RADIO_BAND_UPPER_FM_ITU2 107900
-#define RADIO_BAND_SPACING_FM_ITU2 200
-
-#define RADIO_BAND_LOWER_FM_JAPAN 76000
-#define RADIO_BAND_UPPER_FM_JAPAN 90000
-#define RADIO_BAND_SPACING_FM_JAPAN 100
-
-#define RADIO_BAND_LOWER_FM_OIRT 65800
-#define RADIO_BAND_UPPER_FM_OIRT 74000
-#define RADIO_BAND_SPACING_FM_OIRT 10
-
-#define RADIO_BAND_LOWER_LW 153
-#define RADIO_BAND_UPPER_LW 279
-#define RADIO_BAND_SPACING_LW 9
-
-#define RADIO_BAND_LOWER_MW_IUT1 531
-#define RADIO_BAND_UPPER_MW_ITU1 1611
-#define RADIO_BAND_SPACING_MW_ITU1 9
-
-#define RADIO_BAND_LOWER_MW_IUT2 540
-#define RADIO_BAND_UPPER_MW_ITU2 1610
-#define RADIO_BAND_SPACING_MW_ITU2 10
-
-#define RADIO_BAND_LOWER_SW 2300
-#define RADIO_BAND_UPPER_SW 26100
-#define RADIO_BAND_SPACING_SW 5
-
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
-const radio_band_config_t sKnownRegionConfigs[] = {
- { // FM ITU 1
- RADIO_REGION_ITU_1,
- {
- RADIO_BAND_FM,
- false,
- RADIO_BAND_LOWER_FM_ITU1,
- RADIO_BAND_UPPER_FM_ITU1,
- 1,
- {RADIO_BAND_SPACING_FM_ITU1},
- {
- {
- RADIO_DEEMPHASIS_50,
- true,
- RADIO_RDS_WORLD,
- true,
- true,
- true,
- }
- }
- }
- },
- { // FM Americas
- RADIO_REGION_ITU_2,
- {
- RADIO_BAND_FM,
- false,
- RADIO_BAND_LOWER_FM_ITU2,
- RADIO_BAND_UPPER_FM_ITU2,
- 1,
- {RADIO_BAND_SPACING_FM_ITU2},
- {
- {
- RADIO_DEEMPHASIS_75,
- true,
- RADIO_RDS_US,
- true,
- true,
- true,
- }
- }
- }
- },
- { // FM Japan
- RADIO_REGION_JAPAN,
- {
- RADIO_BAND_FM,
- false,
- RADIO_BAND_LOWER_FM_JAPAN,
- RADIO_BAND_UPPER_FM_JAPAN,
- 1,
- {RADIO_BAND_SPACING_FM_JAPAN},
- {
- {
- RADIO_DEEMPHASIS_50,
- true,
- RADIO_RDS_WORLD,
- true,
- true,
- true,
- }
- }
- }
- },
- { // FM Korea
- RADIO_REGION_KOREA,
- {
- RADIO_BAND_FM,
- false,
- RADIO_BAND_LOWER_FM_ITU1,
- RADIO_BAND_UPPER_FM_ITU1,
- 1,
- {RADIO_BAND_SPACING_FM_ITU1},
- {
- {
- RADIO_DEEMPHASIS_75,
- true,
- RADIO_RDS_WORLD,
- true,
- true,
- true,
- }
- }
- }
- },
- { // FM OIRT
- RADIO_REGION_OIRT,
- {
- RADIO_BAND_FM,
- false,
- RADIO_BAND_LOWER_FM_OIRT,
- RADIO_BAND_UPPER_FM_OIRT,
- 1,
- {RADIO_BAND_SPACING_FM_OIRT},
- {
- {
- RADIO_DEEMPHASIS_50,
- true,
- RADIO_RDS_WORLD,
- true,
- true,
- true,
- }
- }
- }
- },
- { // FM US HD radio
- RADIO_REGION_ITU_2,
- {
- RADIO_BAND_FM_HD,
- false,
- RADIO_BAND_LOWER_FM_ITU2,
- RADIO_BAND_UPPER_FM_ITU2,
- 1,
- {RADIO_BAND_SPACING_FM_ITU2},
- {
- {
- RADIO_DEEMPHASIS_75,
- true,
- RADIO_RDS_US,
- true,
- true,
- true,
- }
- }
- }
- },
- { // AM LW
- RADIO_REGION_ITU_1,
- {
- RADIO_BAND_AM,
- false,
- RADIO_BAND_LOWER_LW,
- RADIO_BAND_UPPER_LW,
- 1,
- {RADIO_BAND_SPACING_LW},
- {
- }
- }
- },
- { // AM SW
- RADIO_REGION_ITU_1,
- {
- RADIO_BAND_AM,
- false,
- RADIO_BAND_LOWER_SW,
- RADIO_BAND_UPPER_SW,
- 1,
- {RADIO_BAND_SPACING_SW},
- {
- }
- }
- },
- { // AM MW ITU1
- RADIO_REGION_ITU_1,
- {
- RADIO_BAND_AM,
- false,
- RADIO_BAND_LOWER_MW_IUT1,
- RADIO_BAND_UPPER_MW_ITU1,
- 1,
- {RADIO_BAND_SPACING_MW_ITU1},
- {
- }
- }
- },
- { // AM MW ITU2
- RADIO_REGION_ITU_2,
- {
- RADIO_BAND_AM,
- false,
- RADIO_BAND_LOWER_MW_IUT2,
- RADIO_BAND_UPPER_MW_ITU2,
- 1,
- {RADIO_BAND_SPACING_MW_ITU2},
- {
- }
- }
- }
-};
-
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_RADIO_REGIONS_H
diff --git a/services/radio/RadioService.cpp b/services/radio/RadioService.cpp
deleted file mode 100644
index beb7c09..0000000
--- a/services/radio/RadioService.cpp
+++ /dev/null
@@ -1,936 +0,0 @@
-/*
- * Copyright (C) 2015 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_TAG "RadioService"
-//#define LOG_NDEBUG 0
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <pthread.h>
-
-#include <system/audio.h>
-#include <system/audio_policy.h>
-#include <system/radio.h>
-#include <system/radio_metadata.h>
-#include <cutils/atomic.h>
-#include <cutils/properties.h>
-#include <hardware/hardware.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <binder/IServiceManager.h>
-#include <binder/MemoryBase.h>
-#include <binder/MemoryHeapBase.h>
-#include <binder/PermissionCache.h>
-#include <hardware/radio.h>
-#include <media/AudioSystem.h>
-#include "RadioService.h"
-#include "RadioRegions.h"
-
-namespace android {
-
-static const char kRadioTunerAudioDeviceName[] = "Radio tuner source";
-
-static const String16 RADIO_PERMISSION("android.permission.ACCESS_FM_RADIO");
-
-RadioService::RadioService()
- : BnRadioService(), mNextUniqueId(1)
-{
- ALOGI("%s", __FUNCTION__);
-}
-
-void RadioService::onFirstRef()
-{
- ALOGI("%s", __FUNCTION__);
-
- sp<RadioInterface> dev = RadioInterface::connectModule(RADIO_CLASS_AM_FM);
-
- if (dev == 0) {
- return;
- }
- struct radio_hal_properties halProperties;
- int rc = dev->getProperties(&halProperties);
- if (rc != 0) {
- ALOGE("could not read implementation properties");
- return;
- }
-
- radio_properties_t properties;
- properties.handle =
- (radio_handle_t)android_atomic_inc(&mNextUniqueId);
- convertProperties(&properties, &halProperties);
-
- ALOGI("loaded default module %s, ver %s, handle %d", properties.product,
- properties.version, properties.handle);
-
- sp<Module> module = new Module(dev, properties);
- mModules.add(properties.handle, module);
-}
-
-RadioService::~RadioService()
-{
-}
-
-status_t RadioService::listModules(struct radio_properties *properties,
- uint32_t *numModules)
-{
- if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
- return PERMISSION_DENIED;
- }
- ALOGV("listModules");
-
- AutoMutex lock(mServiceLock);
- if (numModules == NULL || (*numModules != 0 && properties == NULL)) {
- return BAD_VALUE;
- }
- uint32_t maxModules = *numModules;
- *numModules = mModules.size();
- for (size_t i = 0; i < mModules.size() && i < maxModules; i++) {
- properties[i] = mModules.valueAt(i)->properties();
- }
- return NO_ERROR;
-}
-
-status_t RadioService::attach(radio_handle_t handle,
- const sp<IRadioClient>& client,
- const struct radio_band_config *config,
- bool withAudio,
- sp<IRadio>& radio)
-{
- if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
- return PERMISSION_DENIED;
- }
- ALOGV("%s %d config %p withAudio %d", __FUNCTION__, handle, config, withAudio);
-
- AutoMutex lock(mServiceLock);
- radio.clear();
- if (client == 0) {
- return BAD_VALUE;
- }
- ssize_t index = mModules.indexOfKey(handle);
- if (index < 0) {
- return BAD_VALUE;
- }
- sp<Module> module = mModules.valueAt(index);
-
- if (config == NULL) {
- config = module->getDefaultConfig();
- if (config == NULL) {
- return INVALID_OPERATION;
- }
- }
- ALOGV("%s region %d type %d", __FUNCTION__, config->region, config->band.type);
-
- radio = module->addClient(client, config, withAudio);
-
- if (radio == 0) {
- return NO_INIT;
- }
- return NO_ERROR;
-}
-
-
-static const int kDumpLockRetries = 50;
-static const int kDumpLockSleep = 60000;
-
-static bool tryLock(Mutex& mutex)
-{
- bool locked = false;
- for (int i = 0; i < kDumpLockRetries; ++i) {
- if (mutex.tryLock() == NO_ERROR) {
- locked = true;
- break;
- }
- usleep(kDumpLockSleep);
- }
- return locked;
-}
-
-status_t RadioService::dump(int fd, const Vector<String16>& args __unused) {
- String8 result;
- if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
- result.appendFormat("Permission Denial: can't dump RadioService");
- write(fd, result.string(), result.size());
- } else {
- bool locked = tryLock(mServiceLock);
- // failed to lock - RadioService is probably deadlocked
- if (!locked) {
- result.append("RadioService may be deadlocked\n");
- write(fd, result.string(), result.size());
- }
-
- if (locked) mServiceLock.unlock();
- }
- return NO_ERROR;
-}
-
-status_t RadioService::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
- return BnRadioService::onTransact(code, data, reply, flags);
-}
-
-
-/* static */
-void RadioService::convertProperties(radio_properties_t *properties,
- const radio_hal_properties_t *halProperties)
-{
- memset(properties, 0, sizeof(struct radio_properties));
- properties->class_id = halProperties->class_id;
- strlcpy(properties->implementor, halProperties->implementor,
- RADIO_STRING_LEN_MAX);
- strlcpy(properties->product, halProperties->product,
- RADIO_STRING_LEN_MAX);
- strlcpy(properties->version, halProperties->version,
- RADIO_STRING_LEN_MAX);
- strlcpy(properties->serial, halProperties->serial,
- RADIO_STRING_LEN_MAX);
- properties->num_tuners = halProperties->num_tuners;
- properties->num_audio_sources = halProperties->num_audio_sources;
- properties->supports_capture = halProperties->supports_capture;
-
- for (size_t i = 0; i < ARRAY_SIZE(sKnownRegionConfigs); i++) {
- const radio_hal_band_config_t *band = &sKnownRegionConfigs[i].band;
- size_t j;
- for (j = 0; j < halProperties->num_bands; j++) {
- const radio_hal_band_config_t *halBand = &halProperties->bands[j];
- size_t k;
- if (band->type != halBand->type) continue;
- if (band->lower_limit < halBand->lower_limit) continue;
- if (band->upper_limit > halBand->upper_limit) continue;
- for (k = 0; k < halBand->num_spacings; k++) {
- if (band->spacings[0] == halBand->spacings[k]) break;
- }
- if (k == halBand->num_spacings) continue;
- if (band->type == RADIO_BAND_AM) break;
- if ((band->fm.deemphasis & halBand->fm.deemphasis) == 0) continue;
- if (halBand->fm.rds == 0) break;
- if ((band->fm.rds & halBand->fm.rds) != 0) break;
- }
- if (j == halProperties->num_bands) continue;
-
- ALOGI("convertProperties() Adding band type %d region %d",
- sKnownRegionConfigs[i].band.type , sKnownRegionConfigs[i].region);
-
- memcpy(&properties->bands[properties->num_bands++],
- &sKnownRegionConfigs[i],
- sizeof(radio_band_config_t));
- }
-}
-
-#undef LOG_TAG
-#define LOG_TAG "RadioService::CallbackThread"
-
-RadioService::CallbackThread::CallbackThread(const wp<ModuleClient>& moduleClient)
- : mModuleClient(moduleClient), mMemoryDealer(new MemoryDealer(1024 * 1024, "RadioService"))
-{
-}
-
-RadioService::CallbackThread::~CallbackThread()
-{
- mEventQueue.clear();
-}
-
-void RadioService::CallbackThread::onFirstRef()
-{
- run("RadioService cbk", ANDROID_PRIORITY_URGENT_AUDIO);
-}
-
-bool RadioService::CallbackThread::threadLoop()
-{
- while (!exitPending()) {
- sp<IMemory> eventMemory;
- sp<ModuleClient> moduleClient;
- {
- Mutex::Autolock _l(mCallbackLock);
- while (mEventQueue.isEmpty() && !exitPending()) {
- ALOGV("CallbackThread::threadLoop() sleep");
- mCallbackCond.wait(mCallbackLock);
- ALOGV("CallbackThread::threadLoop() wake up");
- }
- if (exitPending()) {
- break;
- }
- eventMemory = mEventQueue[0];
- mEventQueue.removeAt(0);
- moduleClient = mModuleClient.promote();
- }
- if (moduleClient != 0) {
- moduleClient->onCallbackEvent(eventMemory);
- eventMemory.clear();
- }
- }
- return false;
-}
-
-void RadioService::CallbackThread::exit()
-{
- Mutex::Autolock _l(mCallbackLock);
- requestExit();
- mCallbackCond.broadcast();
-}
-
-sp<IMemory> RadioService::CallbackThread::prepareEvent(radio_hal_event_t *halEvent)
-{
- sp<IMemory> eventMemory;
-
- // The event layout in shared memory is:
- // sizeof(struct radio_event) bytes : the event itself
- // 4 bytes : metadata size or 0
- // N bytes : metadata if present
- uint32_t metadataOffset = sizeof(struct radio_event) + sizeof(uint32_t);
- uint32_t metadataSize = 0;
-
- switch (halEvent->type) {
- case RADIO_EVENT_TUNED:
- case RADIO_EVENT_AF_SWITCH:
- if (radio_metadata_check(halEvent->info.metadata) == 0) {
- metadataSize = (uint32_t)radio_metadata_get_size(halEvent->info.metadata);
- }
- break;
- case RADIO_EVENT_METADATA:
- if (radio_metadata_check(halEvent->metadata) != 0) {
- return eventMemory;
- }
- metadataSize = (uint32_t)radio_metadata_get_size(halEvent->metadata);
- break;
- default:
- break;
- }
-
- eventMemory = mMemoryDealer->allocate(metadataOffset + metadataSize);
- if (eventMemory == 0 || eventMemory->pointer() == NULL) {
- eventMemory.clear();
- return eventMemory;
- }
-
- struct radio_event *event = (struct radio_event *)eventMemory->pointer();
-
- *(uint32_t *)((uint8_t *)event + metadataOffset - sizeof(uint32_t)) = metadataSize;
-
- event->type = halEvent->type;
- event->status = halEvent->status;
-
- switch (event->type) {
- case RADIO_EVENT_CONFIG:
- event->config.band = halEvent->config;
- break;
- case RADIO_EVENT_TUNED:
- case RADIO_EVENT_AF_SWITCH:
- event->info = halEvent->info;
- if (metadataSize != 0) {
- memcpy((uint8_t *)event + metadataOffset, halEvent->info.metadata, metadataSize);
- }
- break;
- case RADIO_EVENT_TA:
- case RADIO_EVENT_EA:
- case RADIO_EVENT_ANTENNA:
- case RADIO_EVENT_CONTROL:
- event->on = halEvent->on;
- break;
- case RADIO_EVENT_METADATA:
- if (metadataSize != 0) {
- memcpy((uint8_t *)event + metadataOffset, halEvent->metadata, metadataSize);
- }
- break;
- case RADIO_EVENT_HW_FAILURE:
- default:
- break;
- }
-
- return eventMemory;
-}
-
-void RadioService::CallbackThread::sendEvent(radio_hal_event_t *event)
- {
- sp<IMemory> eventMemory = prepareEvent(event);
- if (eventMemory == 0) {
- return;
- }
-
- AutoMutex lock(mCallbackLock);
- mEventQueue.add(eventMemory);
- mCallbackCond.signal();
- ALOGV("%s DONE", __FUNCTION__);
-}
-
-
-#undef LOG_TAG
-#define LOG_TAG "RadioService::Module"
-
-RadioService::Module::Module(sp<RadioInterface> hwDevice, radio_properties properties)
- : mHwDevice(hwDevice), mProperties(properties), mMute(true)
-{
-}
-
-RadioService::Module::~Module() {
- mHwDevice.clear();
- mModuleClients.clear();
-}
-
-status_t RadioService::Module::dump(int fd __unused, const Vector<String16>& args __unused) {
- String8 result;
- return NO_ERROR;
-}
-
-sp<RadioService::ModuleClient> RadioService::Module::addClient(const sp<IRadioClient>& client,
- const struct radio_band_config *config,
- bool audio)
-{
- ALOGV("addClient() %p config %p product %s", this, config, mProperties.product);
-
- AutoMutex lock(mLock);
- sp<ModuleClient> moduleClient;
- int ret;
-
- if (mHwDevice == 0) {
- return moduleClient;
- }
-
- for (size_t i = 0; i < mModuleClients.size(); i++) {
- if (mModuleClients[i]->client() == client) {
- // client already connected: reject
- return moduleClient;
- }
- }
- moduleClient = new ModuleClient(this, client, config, audio);
-
- struct radio_hal_band_config halConfig;
- halConfig = config->band;
-
- // Tuner preemption logic:
- // There is a limited amount of tuners and a limited amount of radio audio sources per module.
- // The minimum is one tuner and one audio source.
- // The numbers of tuners and sources are indicated in the module properties.
- // NOTE: current framework implementation only supports one radio audio source.
- // It is possible to open more than one tuner at a time but only one tuner can be connected
- // to the radio audio source (AUDIO_DEVICE_IN_FM_TUNER).
- // The base rule is that a newly connected tuner always wins, i.e. always gets a tuner
- // and can use the audio source if requested.
- // If another client is preempted, it is notified by a callback with RADIO_EVENT_CONTROL
- // indicating loss of control.
- // - If the newly connected client requests the audio source (audio == true):
- // - if an audio source is available
- // no problem
- // - if not:
- // the oldest client in the list using audio is preempted.
- // - If the newly connected client does not request the audio source (audio == false):
- // - if a tuner is available
- // no problem
- // - if not:
- // The oldest client not using audio is preempted first and if none is found the
- // the oldest client using audio is preempted.
- // Each time a tuner using the audio source is opened or closed, the audio policy manager is
- // notified of the connection or disconnection of AUDIO_DEVICE_IN_FM_TUNER.
-
- sp<ModuleClient> oldestTuner;
- sp<ModuleClient> oldestAudio;
- size_t allocatedTuners = 0;
- size_t allocatedAudio = 0;
- for (size_t i = 0; i < mModuleClients.size(); i++) {
- if (mModuleClients[i]->getTuner() != NULL) {
- if (mModuleClients[i]->audio()) {
- if (oldestAudio == 0) {
- oldestAudio = mModuleClients[i];
- }
- allocatedAudio++;
- } else {
- if (oldestTuner == 0) {
- oldestTuner = mModuleClients[i];
- }
- allocatedTuners++;
- }
- }
- }
-
- sp<TunerInterface> halTuner;
- sp<ModuleClient> preemtedClient;
- if (audio) {
- if (allocatedAudio >= mProperties.num_audio_sources) {
- ALOG_ASSERT(oldestAudio != 0, "addClient() allocatedAudio/oldestAudio mismatch");
- preemtedClient = oldestAudio;
- }
- } else {
- if (allocatedAudio + allocatedTuners >= mProperties.num_tuners) {
- if (allocatedTuners != 0) {
- ALOG_ASSERT(oldestTuner != 0, "addClient() allocatedTuners/oldestTuner mismatch");
- preemtedClient = oldestTuner;
- } else {
- ALOG_ASSERT(oldestAudio != 0, "addClient() allocatedAudio/oldestAudio mismatch");
- preemtedClient = oldestAudio;
- }
- }
- }
- if (preemtedClient != 0) {
- halTuner = preemtedClient->getTuner();
- sp<TunerInterface> clear;
- preemtedClient->setTuner(clear);
- mHwDevice->closeTuner(halTuner);
- if (preemtedClient->audio()) {
- notifyDeviceConnection(false, "");
- }
- }
-
- ret = mHwDevice->openTuner(&halConfig, audio,
- moduleClient,
- halTuner);
- if (ret == 0) {
- ALOGV("addClient() setTuner %p", halTuner.get());
- moduleClient->setTuner(halTuner);
- mModuleClients.add(moduleClient);
- if (audio) {
- notifyDeviceConnection(true, "");
- }
- ALOGV("addClient() DONE moduleClient %p", moduleClient.get());
- } else {
- ALOGW("%s open_tuner failed with error %d", __FUNCTION__, ret);
- moduleClient.clear();
- }
-
- return moduleClient;
-}
-
-void RadioService::Module::removeClient(const sp<ModuleClient>& moduleClient) {
- ALOGV("removeClient()");
- AutoMutex lock(mLock);
- int ret;
- ssize_t index = -1;
-
- for (size_t i = 0; i < mModuleClients.size(); i++) {
- if (mModuleClients[i] == moduleClient) {
- index = i;
- break;
- }
- }
- if (index == -1) {
- return;
- }
-
- mModuleClients.removeAt(index);
- sp<TunerInterface> halTuner = moduleClient->getTuner();
- if (halTuner == NULL) {
- return;
- }
-
- if (mHwDevice != 0) {
- mHwDevice->closeTuner(halTuner);
- }
-
- if (moduleClient->audio()) {
- notifyDeviceConnection(false, "");
- }
-
- mMute = true;
-
- if (mModuleClients.isEmpty()) {
- return;
- }
-
- if (mHwDevice == 0) {
- return;
- }
-
- // Tuner reallocation logic:
- // When a client is removed and was controlling a tuner, this tuner will be allocated to a
- // previously preempted client. This client will be notified by a callback with
- // RADIO_EVENT_CONTROL indicating gain of control.
- // - If a preempted client is waiting for an audio source and one becomes available:
- // Allocate the tuner to the most recently added client waiting for an audio source
- // - If not:
- // Allocate the tuner to the most recently added client.
- // Each time a tuner using the audio source is opened or closed, the audio policy manager is
- // notified of the connection or disconnection of AUDIO_DEVICE_IN_FM_TUNER.
-
- sp<ModuleClient> youngestClient;
- sp<ModuleClient> youngestClientAudio;
- size_t allocatedTuners = 0;
- size_t allocatedAudio = 0;
- for (ssize_t i = mModuleClients.size() - 1; i >= 0; i--) {
- if (mModuleClients[i]->getTuner() == NULL) {
- if (mModuleClients[i]->audio()) {
- if (youngestClientAudio == 0) {
- youngestClientAudio = mModuleClients[i];
- }
- } else {
- if (youngestClient == 0) {
- youngestClient = mModuleClients[i];
- }
- }
- } else {
- if (mModuleClients[i]->audio()) {
- allocatedAudio++;
- } else {
- allocatedTuners++;
- }
- }
- }
-
- ALOG_ASSERT(allocatedTuners + allocatedAudio < mProperties.num_tuners,
- "removeClient() removed client but no tuner available");
-
- ALOG_ASSERT(!moduleClient->audio() || allocatedAudio < mProperties.num_audio_sources,
- "removeClient() removed audio client but no tuner with audio available");
-
- if (allocatedAudio < mProperties.num_audio_sources && youngestClientAudio != 0) {
- youngestClient = youngestClientAudio;
- }
-
- ALOG_ASSERT(youngestClient != 0, "removeClient() removed client no candidate found for tuner");
-
- struct radio_hal_band_config halConfig = youngestClient->halConfig();
- ret = mHwDevice->openTuner(&halConfig, youngestClient->audio(),
- moduleClient,
- halTuner);
-
- if (ret == 0) {
- youngestClient->setTuner(halTuner);
- if (youngestClient->audio()) {
- notifyDeviceConnection(true, "");
- }
- }
-}
-
-status_t RadioService::Module::setMute(bool mute)
-{
- Mutex::Autolock _l(mLock);
- if (mute != mMute) {
- mMute = mute;
- //TODO notifify audio policy manager of media activity on radio audio device
- }
- return NO_ERROR;
-}
-
-status_t RadioService::Module::getMute(bool *mute)
-{
- Mutex::Autolock _l(mLock);
- *mute = mMute;
- return NO_ERROR;
-}
-
-
-const struct radio_band_config *RadioService::Module::getDefaultConfig() const
-{
- if (mProperties.num_bands == 0) {
- return NULL;
- }
- return &mProperties.bands[0];
-}
-
-void RadioService::Module::notifyDeviceConnection(bool connected,
- const char *address) {
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_IN_FM_TUNER,
- connected ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE :
- AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- address, kRadioTunerAudioDeviceName);
- IPCThreadState::self()->restoreCallingIdentity(token);
-}
-
-#undef LOG_TAG
-#define LOG_TAG "RadioService::ModuleClient"
-
-RadioService::ModuleClient::ModuleClient(const sp<Module>& module,
- const sp<IRadioClient>& client,
- const struct radio_band_config *config,
- bool audio)
- : mModule(module), mClient(client), mConfig(*config), mAudio(audio), mTuner(0)
-{
-}
-
-void RadioService::ModuleClient::onFirstRef()
-{
- mCallbackThread = new CallbackThread(this);
- IInterface::asBinder(mClient)->linkToDeath(this);
-}
-
-RadioService::ModuleClient::~ModuleClient() {
- if (mClient != 0) {
- IInterface::asBinder(mClient)->unlinkToDeath(this);
- mClient.clear();
- }
- if (mCallbackThread != 0) {
- mCallbackThread->exit();
- }
-}
-
-void RadioService::ModuleClient::onEvent(radio_hal_event_t *halEvent)
-{
- mCallbackThread->sendEvent(halEvent);
-}
-
-status_t RadioService::ModuleClient::dump(int fd __unused,
- const Vector<String16>& args __unused) {
- String8 result;
- return NO_ERROR;
-}
-
-void RadioService::ModuleClient::detach() {
- ALOGV("%s", __FUNCTION__);
- sp<ModuleClient> strongMe = this;
- {
- AutoMutex lock(mLock);
- if (mClient != 0) {
- IInterface::asBinder(mClient)->unlinkToDeath(this);
- mClient.clear();
- }
- }
- sp<Module> module = mModule.promote();
- if (module == 0) {
- return;
- }
- module->removeClient(this);
-}
-
-radio_hal_band_config_t RadioService::ModuleClient::halConfig() const
-{
- AutoMutex lock(mLock);
- ALOGV("%s locked", __FUNCTION__);
- return mConfig.band;
-}
-
-sp<TunerInterface>& RadioService::ModuleClient::getTuner()
-{
- AutoMutex lock(mLock);
- ALOGV("%s locked", __FUNCTION__);
- return mTuner;
-}
-
-void RadioService::ModuleClient::setTuner(sp<TunerInterface>& tuner)
-{
- ALOGV("%s %p", __FUNCTION__, this);
-
- AutoMutex lock(mLock);
- mTuner = tuner;
- ALOGV("%s locked", __FUNCTION__);
-
- radio_hal_event_t event;
- event.type = RADIO_EVENT_CONTROL;
- event.status = 0;
- event.on = mTuner != 0;
- mCallbackThread->sendEvent(&event);
- ALOGV("%s DONE", __FUNCTION__);
-
-}
-
-status_t RadioService::ModuleClient::setConfiguration(const struct radio_band_config *config)
-{
- if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
- return PERMISSION_DENIED;
- }
- AutoMutex lock(mLock);
- status_t status = NO_ERROR;
- ALOGV("%s locked", __FUNCTION__);
-
- if (mTuner != 0) {
- struct radio_hal_band_config halConfig;
- halConfig = config->band;
- status = (status_t)mTuner->setConfiguration(&halConfig);
- if (status == NO_ERROR) {
- mConfig = *config;
- }
- } else {
- mConfig = *config;
- status = INVALID_OPERATION;
- }
-
- return status;
-}
-
-status_t RadioService::ModuleClient::getConfiguration(struct radio_band_config *config)
-{
- if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
- return PERMISSION_DENIED;
- }
- AutoMutex lock(mLock);
- status_t status = NO_ERROR;
- ALOGV("%s locked", __FUNCTION__);
-
- if (mTuner != 0) {
- struct radio_hal_band_config halConfig;
- status = (status_t)mTuner->getConfiguration(&halConfig);
- if (status == NO_ERROR) {
- mConfig.band = halConfig;
- }
- }
- *config = mConfig;
-
- return status;
-}
-
-status_t RadioService::ModuleClient::setMute(bool mute)
-{
- if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
- return PERMISSION_DENIED;
- }
- sp<Module> module;
- {
- Mutex::Autolock _l(mLock);
- ALOGV("%s locked", __FUNCTION__);
- if (mTuner == 0 || !mAudio) {
- return INVALID_OPERATION;
- }
- module = mModule.promote();
- if (module == 0) {
- return NO_INIT;
- }
- }
- module->setMute(mute);
- return NO_ERROR;
-}
-
-status_t RadioService::ModuleClient::getMute(bool *mute)
-{
- if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
- return PERMISSION_DENIED;
- }
- sp<Module> module;
- {
- Mutex::Autolock _l(mLock);
- ALOGV("%s locked", __FUNCTION__);
- module = mModule.promote();
- if (module == 0) {
- return NO_INIT;
- }
- }
- return module->getMute(mute);
-}
-
-status_t RadioService::ModuleClient::scan(radio_direction_t direction, bool skipSubChannel)
-{
- if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
- return PERMISSION_DENIED;
- }
- AutoMutex lock(mLock);
- ALOGV("%s locked", __FUNCTION__);
- status_t status;
- if (mTuner != 0) {
- status = (status_t)mTuner->scan(direction, skipSubChannel);
- } else {
- status = INVALID_OPERATION;
- }
- return status;
-}
-
-status_t RadioService::ModuleClient::step(radio_direction_t direction, bool skipSubChannel)
-{
- if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
- return PERMISSION_DENIED;
- }
- AutoMutex lock(mLock);
- ALOGV("%s locked", __FUNCTION__);
- status_t status;
- if (mTuner != 0) {
- status = (status_t)mTuner->step(direction, skipSubChannel);
- } else {
- status = INVALID_OPERATION;
- }
- return status;
-}
-
-status_t RadioService::ModuleClient::tune(uint32_t channel, uint32_t subChannel)
-{
- if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
- return PERMISSION_DENIED;
- }
- AutoMutex lock(mLock);
- ALOGV("%s locked", __FUNCTION__);
- status_t status;
- if (mTuner != 0) {
- status = (status_t)mTuner->tune(channel, subChannel);
- } else {
- status = INVALID_OPERATION;
- }
- return status;
-}
-
-status_t RadioService::ModuleClient::cancel()
-{
- if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
- return PERMISSION_DENIED;
- }
- AutoMutex lock(mLock);
- ALOGV("%s locked", __FUNCTION__);
- status_t status;
- if (mTuner != 0) {
- status = (status_t)mTuner->cancel();
- } else {
- status = INVALID_OPERATION;
- }
- return status;
-}
-
-status_t RadioService::ModuleClient::getProgramInformation(struct radio_program_info *info)
-{
- if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
- return PERMISSION_DENIED;
- }
- AutoMutex lock(mLock);
- ALOGV("%s locked", __FUNCTION__);
- status_t status;
- if (mTuner != NULL) {
- status = (status_t)mTuner->getProgramInformation(info);
- } else {
- status = INVALID_OPERATION;
- }
-
- return status;
-}
-
-status_t RadioService::ModuleClient::hasControl(bool *hasControl)
-{
- if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
- return PERMISSION_DENIED;
- }
- Mutex::Autolock lock(mLock);
- ALOGV("%s locked", __FUNCTION__);
- *hasControl = mTuner != 0;
- return NO_ERROR;
-}
-
-void RadioService::ModuleClient::onCallbackEvent(const sp<IMemory>& eventMemory)
-{
- if (eventMemory == 0 || eventMemory->pointer() == NULL) {
- return;
- }
-
- sp<IRadioClient> client;
- {
- AutoMutex lock(mLock);
- ALOGV("%s locked", __FUNCTION__);
- radio_event_t *event = (radio_event_t *)eventMemory->pointer();
- switch (event->type) {
- case RADIO_EVENT_CONFIG:
- mConfig.band = event->config.band;
- event->config.region = mConfig.region;
- break;
- default:
- break;
- }
-
- client = mClient;
- }
- if (client != 0) {
- client->onEvent(eventMemory);
- }
-}
-
-
-void RadioService::ModuleClient::binderDied(
- const wp<IBinder> &who __unused) {
- ALOGW("client binder died for client %p", this);
- detach();
-}
-
-}; // namespace android
diff --git a/services/radio/RadioService.h b/services/radio/RadioService.h
deleted file mode 100644
index 444eb7a..0000000
--- a/services/radio/RadioService.h
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2015 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_HARDWARE_RADIO_SERVICE_H
-#define ANDROID_HARDWARE_RADIO_SERVICE_H
-
-#include <utils/Vector.h>
-//#include <binder/AppOpsManager.h>
-#include <binder/MemoryDealer.h>
-#include <binder/BinderService.h>
-#include <binder/IAppOpsCallback.h>
-#include <radio/IRadioService.h>
-#include <radio/IRadio.h>
-#include <radio/IRadioClient.h>
-#include <system/radio.h>
-#include <hardware/radio.h>
-#include "RadioInterface.h"
-#include "TunerInterface.h"
-#include "TunerCallbackInterface.h"
-
-namespace android {
-
-class MemoryHeapBase;
-
-class RadioService :
- public BinderService<RadioService>,
- public BnRadioService
-{
- friend class BinderService<RadioService>;
-
-public:
- class ModuleClient;
- class Module;
-
- static char const* getServiceName() { return "media.radio"; }
-
- RadioService();
- virtual ~RadioService();
-
- // IRadioService
- virtual status_t listModules(struct radio_properties *properties,
- uint32_t *numModules);
-
- virtual status_t attach(radio_handle_t handle,
- const sp<IRadioClient>& client,
- const struct radio_band_config *config,
- bool withAudio,
- sp<IRadio>& radio);
-
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags);
-
- virtual status_t dump(int fd, const Vector<String16>& args);
-
-
- class Module : public virtual RefBase {
- public:
-
- Module(sp<RadioInterface> hwDevice,
- struct radio_properties properties);
-
- virtual ~Module();
-
- sp<ModuleClient> addClient(const sp<IRadioClient>& client,
- const struct radio_band_config *config,
- bool audio);
-
- void removeClient(const sp<ModuleClient>& moduleClient);
-
- status_t setMute(bool mute);
-
- status_t getMute(bool *mute);
-
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- sp<RadioInterface> hwDevice() const { return mHwDevice; }
- const struct radio_properties properties() const { return mProperties; }
- const struct radio_band_config *getDefaultConfig() const ;
-
- private:
-
- void notifyDeviceConnection(bool connected, const char *address);
-
- Mutex mLock; // protects mModuleClients
- sp<RadioInterface> mHwDevice; // HAL hardware device
- const struct radio_properties mProperties; // cached hardware module properties
- Vector< sp<ModuleClient> > mModuleClients; // list of attached clients
- bool mMute; // radio audio source state
- // when unmuted, audio is routed to the
- // output device selected for media use case.
- }; // class Module
-
- class CallbackThread : public Thread {
- public:
-
- explicit CallbackThread(const wp<ModuleClient>& moduleClient);
-
- virtual ~CallbackThread();
-
-
- // Thread virtuals
- virtual bool threadLoop();
-
- // RefBase
- virtual void onFirstRef();
-
- void exit();
-
- void sendEvent(radio_hal_event_t *halEvent);
- sp<IMemory> prepareEvent(radio_hal_event_t *halEvent);
-
- private:
- wp<ModuleClient> mModuleClient; // client module the thread belongs to
- Condition mCallbackCond; // condition signaled when a new event is posted
- Mutex mCallbackLock; // protects mEventQueue
- Vector< sp<IMemory> > mEventQueue; // pending callback events
- sp<MemoryDealer> mMemoryDealer; // shared memory for callback event
- }; // class CallbackThread
-
- class ModuleClient : public BnRadio,
- public IBinder::DeathRecipient,
- public TunerCallbackInterface {
- public:
-
- ModuleClient(const sp<Module>& module,
- const sp<IRadioClient>& client,
- const struct radio_band_config *config,
- bool audio);
-
- virtual ~ModuleClient();
-
- // IRadio
- virtual void detach();
-
- virtual status_t setConfiguration(const struct radio_band_config *config);
-
- virtual status_t getConfiguration(struct radio_band_config *config);
-
- virtual status_t setMute(bool mute);
-
- virtual status_t getMute(bool *mute);
-
- virtual status_t scan(radio_direction_t direction, bool skipSubChannel);
-
- virtual status_t step(radio_direction_t direction, bool skipSubChannel);
-
- virtual status_t tune(unsigned int channel, unsigned int subChannel);
-
- virtual status_t cancel();
-
- virtual status_t getProgramInformation(struct radio_program_info *info);
-
- virtual status_t hasControl(bool *hasControl);
-
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- sp<IRadioClient> client() const { return mClient; }
- wp<Module> module() const { return mModule; }
- radio_hal_band_config_t halConfig() const;
- sp<CallbackThread> callbackThread() const { return mCallbackThread; }
- void setTuner(sp<TunerInterface>& tuner);
- sp<TunerInterface>& getTuner();
- bool audio() const { return mAudio; }
-
- void onCallbackEvent(const sp<IMemory>& event);
-
- virtual void onFirstRef();
-
-
- // IBinder::DeathRecipient implementation
- virtual void binderDied(const wp<IBinder> &who);
-
- // TunerCallbackInterface
- virtual void onEvent(radio_hal_event_t *event);
-
- private:
-
- mutable Mutex mLock; // protects mClient, mConfig and mTuner
- wp<Module> mModule; // The module this client is attached to
- sp<IRadioClient> mClient; // event callback binder interface
- radio_band_config_t mConfig; // current band configuration
- sp<CallbackThread> mCallbackThread; // event callback thread
- const bool mAudio;
- sp<TunerInterface> mTuner; // HAL tuner interface. NULL indicates that
- // this client does not have control on any
- // tuner
- }; // class ModuleClient
-
-
- static void callback(radio_hal_event_t *halEvent, void *cookie);
-
-private:
-
- virtual void onFirstRef();
-
- static void convertProperties(radio_properties_t *properties,
- const radio_hal_properties_t *halProperties);
- Mutex mServiceLock; // protects mModules
- volatile int32_t mNextUniqueId; // for module ID allocation
- DefaultKeyedVector< radio_handle_t, sp<Module> > mModules;
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_RADIO_SERVICE_H
diff --git a/services/radio/TunerCallbackInterface.h b/services/radio/TunerCallbackInterface.h
deleted file mode 100644
index 4973cce..0000000
--- a/services/radio/TunerCallbackInterface.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_TUNER_CALLBACK_INTERFACE_H
-#define ANDROID_HARDWARE_TUNER_CALLBACK_INTERFACE_H
-
-#include <utils/RefBase.h>
-#include <system/radio.h>
-
-namespace android {
-
-class TunerCallbackInterface : public virtual RefBase
-{
-public:
- virtual void onEvent(radio_hal_event_t *event) = 0;
-
-protected:
- TunerCallbackInterface() {}
- virtual ~TunerCallbackInterface() {}
-
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_TUNER_CALLBACK_INTERFACE_H
diff --git a/services/radio/TunerInterface.h b/services/radio/TunerInterface.h
deleted file mode 100644
index 4e657d3..0000000
--- a/services/radio/TunerInterface.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_TUNER_INTERFACE_H
-#define ANDROID_HARDWARE_TUNER_INTERFACE_H
-
-#include <utils/RefBase.h>
-#include <system/radio.h>
-
-namespace android {
-
-class TunerInterface : public virtual RefBase
-{
-public:
- /*
- * Apply current radio band configuration (band, range, channel spacing ...).
- *
- * arguments:
- * - config: the band configuration to apply
- *
- * returns:
- * 0 if configuration could be applied
- * -EINVAL if configuration requested is invalid
- *
- * Automatically cancels pending scan, step or tune.
- *
- * Callback function with event RADIO_EVENT_CONFIG MUST be called once the
- * configuration is applied or a failure occurs or after a time out.
- */
- virtual int setConfiguration(const radio_hal_band_config_t *config) = 0;
-
- /*
- * Retrieve current radio band configuration.
- *
- * arguments:
- * - config: where to return the band configuration
- *
- * returns:
- * 0 if valid configuration is returned
- * -EINVAL if invalid arguments are passed
- */
- virtual int getConfiguration(radio_hal_band_config_t *config) = 0;
-
- /*
- * Start scanning up to next valid station.
- * Must be called when a valid configuration has been applied.
- *
- * arguments:
- * - direction: RADIO_DIRECTION_UP or RADIO_DIRECTION_DOWN
- * - skip_sub_channel: valid for HD radio or digital radios only: ignore sub channels
- * (e.g SPS for HD radio).
- *
- * returns:
- * 0 if scan successfully started
- * -ENOSYS if called out of sequence
- * -ENODEV if another error occurs
- *
- * Automatically cancels pending scan, step or tune.
- *
- * Callback function with event RADIO_EVENT_TUNED MUST be called once
- * locked on a station or after a time out or full frequency scan if
- * no station found. The event status should indicate if a valid station
- * is tuned or not.
- */
- virtual int scan(radio_direction_t direction, bool skip_sub_channel) = 0;
-
- /*
- * Move one channel spacing up or down.
- * Must be called when a valid configuration has been applied.
- *
- * arguments:
- * - direction: RADIO_DIRECTION_UP or RADIO_DIRECTION_DOWN
- * - skip_sub_channel: valid for HD radio or digital radios only: ignore sub channels
- * (e.g SPS for HD radio).
- *
- * returns:
- * 0 if step successfully started
- * -ENOSYS if called out of sequence
- * -ENODEV if another error occurs
- *
- * Automatically cancels pending scan, step or tune.
- *
- * Callback function with event RADIO_EVENT_TUNED MUST be called once
- * step completed or after a time out. The event status should indicate
- * if a valid station is tuned or not.
- */
- virtual int step(radio_direction_t direction, bool skip_sub_channel) = 0;
-
- /*
- * Tune to specified frequency.
- * Must be called when a valid configuration has been applied.
- *
- * arguments:
- * - channel: channel to tune to. A frequency in kHz for AM/FM/HD Radio bands.
- * - sub_channel: valid for HD radio or digital radios only: (e.g SPS number for HD radio).
- *
- * returns:
- * 0 if tune successfully started
- * -ENOSYS if called out of sequence
- * -EINVAL if invalid arguments are passed
- * -ENODEV if another error occurs
- *
- * Automatically cancels pending scan, step or tune.
- *
- * Callback function with event RADIO_EVENT_TUNED MUST be called once
- * tuned or after a time out. The event status should indicate
- * if a valid station is tuned or not.
- */
- virtual int tune(unsigned int channel, unsigned int sub_channel) = 0;
-
- /*
- * Cancel a scan, step or tune operation.
- * Must be called while a scan, step or tune operation is pending
- * (callback not yet sent).
- *
- * returns:
- * 0 if successful
- * -ENOSYS if called out of sequence
- * -ENODEV if another error occurs
- *
- * The callback is not sent.
- */
- virtual int cancel() = 0;
-
- /*
- * Retrieve current station information.
- *
- * arguments:
- * - info: where to return the program info.
- * If info->metadata is NULL. no meta data should be returned.
- * If meta data must be returned, they should be added to or cloned to
- * info->metadata, not passed from a newly created meta data buffer.
- *
- * returns:
- * 0 if tuned and information available
- * -EINVAL if invalid arguments are passed
- * -ENODEV if another error occurs
- */
- virtual int getProgramInformation(radio_program_info_t *info) = 0;
-
-protected:
- TunerInterface() {}
- virtual ~TunerInterface() {}
-
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_TUNER_INTERFACE_H
diff --git a/services/soundtrigger/OWNERS b/services/soundtrigger/OWNERS
new file mode 100644
index 0000000..e83f6b9
--- /dev/null
+++ b/services/soundtrigger/OWNERS
@@ -0,0 +1,2 @@
+elaurent@google.com
+thorntonc@google.com
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 19dd41e..22519a3 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -89,7 +89,8 @@
uint32_t *numModules)
{
ALOGV("listModules");
- if (!captureHotwordAllowed()) {
+ if (!captureHotwordAllowed(IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid())) {
return PERMISSION_DENIED;
}
@@ -110,7 +111,8 @@
sp<ISoundTrigger>& moduleInterface)
{
ALOGV("attach module %d", handle);
- if (!captureHotwordAllowed()) {
+ if (!captureHotwordAllowed(IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid())) {
return PERMISSION_DENIED;
}
@@ -856,7 +858,7 @@
}
const bool supports_stop_all =
- (mHalInterface != 0) && (mHalInterface->stopAllRecognitions() == ENOSYS);
+ (mHalInterface != 0) && (mHalInterface->stopAllRecognitions() != -ENOSYS);
for (size_t i = 0; i < mModels.size(); i++) {
sp<Model> model = mModels.valueAt(i);
@@ -960,7 +962,8 @@
void SoundTriggerHwService::ModuleClient::detach() {
ALOGV("detach()");
- if (!captureHotwordAllowed()) {
+ if (!captureHotwordAllowed(IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid())) {
return;
}
@@ -983,7 +986,8 @@
sound_model_handle_t *handle)
{
ALOGV("loadSoundModel() handle");
- if (!captureHotwordAllowed()) {
+ if (!captureHotwordAllowed(IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid())) {
return PERMISSION_DENIED;
}
@@ -997,7 +1001,8 @@
status_t SoundTriggerHwService::ModuleClient::unloadSoundModel(sound_model_handle_t handle)
{
ALOGV("unloadSoundModel() model handle %d", handle);
- if (!captureHotwordAllowed()) {
+ if (!captureHotwordAllowed(IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid())) {
return PERMISSION_DENIED;
}
@@ -1012,7 +1017,8 @@
const sp<IMemory>& dataMemory)
{
ALOGV("startRecognition() model handle %d", handle);
- if (!captureHotwordAllowed()) {
+ if (!captureHotwordAllowed(IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid())) {
return PERMISSION_DENIED;
}
@@ -1026,7 +1032,8 @@
status_t SoundTriggerHwService::ModuleClient::stopRecognition(sound_model_handle_t handle)
{
ALOGV("stopRecognition() model handle %d", handle);
- if (!captureHotwordAllowed()) {
+ if (!captureHotwordAllowed(IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid())) {
return PERMISSION_DENIED;
}
diff --git a/soundtrigger/OWNERS b/soundtrigger/OWNERS
new file mode 100644
index 0000000..e83f6b9
--- /dev/null
+++ b/soundtrigger/OWNERS
@@ -0,0 +1,2 @@
+elaurent@google.com
+thorntonc@google.com
diff --git a/tools/OWNERS b/tools/OWNERS
new file mode 100644
index 0000000..6dcb035
--- /dev/null
+++ b/tools/OWNERS
@@ -0,0 +1 @@
+gkasten@android.com