Merge "Fix info leak vulnerability of IDrm" into mnc-dev am: 56ffb6e7b1 am: 0708170e10 am: 96ddf53162
am: 58a982d1c7
* commit '58a982d1c7a316d1bb8fade837664a412241ba8a':
Fix info leak vulnerability of IDrm
diff --git a/camera/Android.mk b/camera/Android.mk
index 471cb0d..de23953 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -52,6 +52,7 @@
LOCAL_C_INCLUDES += \
system/media/camera/include \
system/media/private/camera/include \
+ frameworks/native/include/media/openmax \
LOCAL_MODULE:= libcamera_client
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index 9bf3134..1289348 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -72,9 +72,9 @@
}
sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
- int clientUid)
+ int clientUid, int clientPid)
{
- return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
+ return CameraBaseT::connect(cameraId, clientPackageName, clientUid, clientPid);
}
status_t Camera::connectLegacy(int cameraId, int halVersion,
@@ -136,6 +136,15 @@
return c->setPreviewTarget(bufferProducer);
}
+status_t Camera::setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer)
+{
+ ALOGV("setVideoTarget(%p)", bufferProducer.get());
+ sp <ICamera> c = mCamera;
+ if (c == 0) return NO_INIT;
+ ALOGD_IF(bufferProducer == 0, "app passed NULL video surface");
+ return c->setVideoTarget(bufferProducer);
+}
+
// start preview mode
status_t Camera::startPreview()
{
@@ -145,13 +154,12 @@
return c->startPreview();
}
-status_t Camera::storeMetaDataInBuffers(bool enabled)
+status_t Camera::setVideoBufferMode(int32_t videoBufferMode)
{
- ALOGV("storeMetaDataInBuffers: %s",
- enabled? "true": "false");
+ ALOGV("setVideoBufferMode: %d", videoBufferMode);
sp <ICamera> c = mCamera;
if (c == 0) return NO_INIT;
- return c->storeMetaDataInBuffers(enabled);
+ return c->setVideoBufferMode(videoBufferMode);
}
// start recording mode, must call setPreviewTarget first
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index 5d50aa8..9ee7ae5 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -92,7 +92,7 @@
template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
const String16& clientPackageName,
- int clientUid)
+ int clientUid, int clientPid)
{
ALOGV("%s: connect", __FUNCTION__);
sp<TCam> c = new TCam(cameraId);
@@ -103,7 +103,7 @@
if (cs != 0) {
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
- /*out*/ c->mCamera);
+ clientPid, /*out*/ c->mCamera);
}
if (status == OK && c->mCamera != 0) {
IInterface::asBinder(c->mCamera)->linkToDeath(c);
diff --git a/camera/CameraUtils.cpp b/camera/CameraUtils.cpp
index 04244ac..26eebe3 100644
--- a/camera/CameraUtils.cpp
+++ b/camera/CameraUtils.cpp
@@ -18,6 +18,7 @@
//#define LOG_NDEBUG 0
#include <camera/CameraUtils.h>
+#include <media/hardware/HardwareAPI.h>
#include <system/window.h>
#include <system/graphics.h>
@@ -121,5 +122,19 @@
return OK;
}
+// Return whether the image data contains a native handle.
+bool CameraUtils::isNativeHandleMetadata(const sp<IMemory>& imageData) {
+ if (imageData == nullptr) {
+ return false;
+ }
+
+ if (imageData->size() == sizeof(VideoNativeHandleMetadata)) {
+ VideoNativeHandleMetadata *metadata =
+ (VideoNativeHandleMetadata*)(imageData->pointer());
+ return metadata->eType == kMetadataBufferTypeNativeHandleSource;
+ }
+
+ return false;
+}
} /* namespace android */
diff --git a/camera/ICamera.cpp b/camera/ICamera.cpp
index 9943be6..1dd8912 100644
--- a/camera/ICamera.cpp
+++ b/camera/ICamera.cpp
@@ -21,9 +21,11 @@
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
+#include <camera/CameraUtils.h>
#include <camera/ICamera.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
+#include <media/hardware/HardwareAPI.h>
namespace android {
@@ -48,7 +50,8 @@
STOP_RECORDING,
RECORDING_ENABLED,
RELEASE_RECORDING_FRAME,
- STORE_META_DATA_IN_BUFFERS,
+ SET_VIDEO_BUFFER_MODE,
+ SET_VIDEO_BUFFER_TARGET,
};
class BpCamera: public BpInterface<ICamera>
@@ -148,16 +151,31 @@
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
data.writeStrongBinder(IInterface::asBinder(mem));
+
+ native_handle_t *nh = nullptr;
+ if (CameraUtils::isNativeHandleMetadata(mem)) {
+ VideoNativeHandleMetadata *metadata =
+ (VideoNativeHandleMetadata*)(mem->pointer());
+ nh = metadata->pHandle;
+ data.writeNativeHandle(nh);
+ }
+
remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
+
+ if (nh) {
+ // Close the native handle because camera received a dup copy.
+ native_handle_close(nh);
+ native_handle_delete(nh);
+ }
}
- status_t storeMetaDataInBuffers(bool enabled)
+ status_t setVideoBufferMode(int32_t videoBufferMode)
{
- ALOGV("storeMetaDataInBuffers: %s", enabled? "true": "false");
+ ALOGV("setVideoBufferMode: %d", videoBufferMode);
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
- data.writeInt32(enabled);
- remote()->transact(STORE_META_DATA_IN_BUFFERS, data, &reply);
+ data.writeInt32(videoBufferMode);
+ remote()->transact(SET_VIDEO_BUFFER_MODE, data, &reply);
return reply.readInt32();
}
@@ -268,6 +286,17 @@
remote()->transact(UNLOCK, data, &reply);
return reply.readInt32();
}
+
+ status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer)
+ {
+ ALOGV("setVideoTarget");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ sp<IBinder> b(IInterface::asBinder(bufferProducer));
+ data.writeStrongBinder(b);
+ remote()->transact(SET_VIDEO_BUFFER_TARGET, data, &reply);
+ return reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(Camera, "android.hardware.ICamera");
@@ -336,14 +365,22 @@
ALOGV("RELEASE_RECORDING_FRAME");
CHECK_INTERFACE(ICamera, data, reply);
sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder());
+
+ if (CameraUtils::isNativeHandleMetadata(mem)) {
+ VideoNativeHandleMetadata *metadata =
+ (VideoNativeHandleMetadata*)(mem->pointer());
+ metadata->pHandle = data.readNativeHandle();
+ // releaseRecordingFrame will be responsble to close the native handle.
+ }
+
releaseRecordingFrame(mem);
return NO_ERROR;
} break;
- case STORE_META_DATA_IN_BUFFERS: {
- ALOGV("STORE_META_DATA_IN_BUFFERS");
+ case SET_VIDEO_BUFFER_MODE: {
+ ALOGV("SET_VIDEO_BUFFER_MODE");
CHECK_INTERFACE(ICamera, data, reply);
- bool enabled = data.readInt32();
- reply->writeInt32(storeMetaDataInBuffers(enabled));
+ int32_t mode = data.readInt32();
+ reply->writeInt32(setVideoBufferMode(mode));
return NO_ERROR;
} break;
case PREVIEW_ENABLED: {
@@ -415,6 +452,14 @@
reply->writeInt32(unlock());
return NO_ERROR;
} break;
+ case SET_VIDEO_BUFFER_TARGET: {
+ ALOGV("SET_VIDEO_BUFFER_TARGET");
+ CHECK_INTERFACE(ICamera, data, reply);
+ sp<IGraphicBufferProducer> st =
+ interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
+ reply->writeInt32(setVideoTarget(st));
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
index 179a341..4282f9a 100644
--- a/camera/ICameraClient.cpp
+++ b/camera/ICameraClient.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2008, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** 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
+** 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
+** 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.
*/
@@ -20,7 +20,9 @@
#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
+#include <camera/CameraUtils.h>
#include <camera/ICameraClient.h>
+#include <media/hardware/HardwareAPI.h>
namespace android {
@@ -75,6 +77,13 @@
data.writeInt64(timestamp);
data.writeInt32(msgType);
data.writeStrongBinder(IInterface::asBinder(imageData));
+ // If imageData is metadata and it contains a native handle, write the native handle to
+ // parcel.
+ if (CameraUtils::isNativeHandleMetadata(imageData)) {
+ VideoNativeHandleMetadata *metadata =
+ (VideoNativeHandleMetadata*)(imageData->pointer());
+ data.writeNativeHandle(metadata->pHandle);
+ }
remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
}
};
@@ -118,6 +127,19 @@
nsecs_t timestamp = data.readInt64();
int32_t msgType = data.readInt32();
sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
+
+ // If the image data contains a native handle, read the native handle from the parcel
+ // and replace the native handle in the image data. (The native handle in image data is
+ // not serielized/deserialized so it's not valid in the process.)
+ if (CameraUtils::isNativeHandleMetadata(imageData)) {
+ VideoNativeHandleMetadata *metadata =
+ (VideoNativeHandleMetadata*)(imageData->pointer());
+ metadata->pHandle = data.readNativeHandle();
+
+ // The native handle will be freed in
+ // BpCameraRecordingProxyListener::releaseRecordingFrame.
+ }
+
dataCallbackTimestamp(timestamp, msgType, imageData);
return NO_ERROR;
} break;
diff --git a/camera/ICameraRecordingProxy.cpp b/camera/ICameraRecordingProxy.cpp
index 3dc0ffb..d128f5b 100644
--- a/camera/ICameraRecordingProxy.cpp
+++ b/camera/ICameraRecordingProxy.cpp
@@ -16,10 +16,12 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ICameraRecordingProxy"
+#include <camera/CameraUtils.h>
#include <camera/ICameraRecordingProxy.h>
#include <camera/ICameraRecordingProxyListener.h>
#include <binder/IMemory.h>
#include <binder/Parcel.h>
+#include <media/hardware/HardwareAPI.h>
#include <stdint.h>
#include <utils/Log.h>
@@ -64,7 +66,22 @@
Parcel data, reply;
data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor());
data.writeStrongBinder(IInterface::asBinder(mem));
+
+ native_handle_t *nh = nullptr;
+ if (CameraUtils::isNativeHandleMetadata(mem)) {
+ VideoNativeHandleMetadata *metadata =
+ (VideoNativeHandleMetadata*)(mem->pointer());
+ nh = metadata->pHandle;
+ data.writeNativeHandle(nh);
+ }
+
remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
+
+ if (nh) {
+ // Close the native handle because camera received a dup copy.
+ native_handle_close(nh);
+ native_handle_delete(nh);
+ }
}
};
@@ -94,7 +111,16 @@
ALOGV("RELEASE_RECORDING_FRAME");
CHECK_INTERFACE(ICameraRecordingProxy, data, reply);
sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder());
+
+ if (CameraUtils::isNativeHandleMetadata(mem)) {
+ VideoNativeHandleMetadata *metadata =
+ (VideoNativeHandleMetadata*)(mem->pointer());
+ metadata->pHandle = data.readNativeHandle();
+
+ // releaseRecordingFrame will be responsble to close the native handle.
+ }
releaseRecordingFrame(mem);
+
return NO_ERROR;
} break;
diff --git a/camera/ICameraRecordingProxyListener.cpp b/camera/ICameraRecordingProxyListener.cpp
index cf848fc..447174e 100644
--- a/camera/ICameraRecordingProxyListener.cpp
+++ b/camera/ICameraRecordingProxyListener.cpp
@@ -16,9 +16,11 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ICameraRecordingProxyListener"
+#include <camera/CameraUtils.h>
#include <camera/ICameraRecordingProxyListener.h>
#include <binder/IMemory.h>
#include <binder/Parcel.h>
+#include <media/hardware/HardwareAPI.h>
#include <utils/Log.h>
namespace android {
@@ -43,7 +45,22 @@
data.writeInt64(timestamp);
data.writeInt32(msgType);
data.writeStrongBinder(IInterface::asBinder(imageData));
+ native_handle_t* nh = nullptr;
+
+ if (CameraUtils::isNativeHandleMetadata(imageData)) {
+ VideoNativeHandleMetadata *metadata =
+ (VideoNativeHandleMetadata*)(imageData->pointer());
+ nh = metadata->pHandle;
+ data.writeNativeHandle(nh);
+ }
+
remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
+
+ // The native handle is dupped in ICameraClient so we need to free it here.
+ if (nh) {
+ native_handle_close(nh);
+ native_handle_delete(nh);
+ }
}
};
@@ -61,6 +78,15 @@
nsecs_t timestamp = data.readInt64();
int32_t msgType = data.readInt32();
sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
+
+ if (CameraUtils::isNativeHandleMetadata(imageData)) {
+ VideoNativeHandleMetadata *meta = (VideoNativeHandleMetadata*)(imageData->pointer());
+ meta->pHandle = data.readNativeHandle();
+
+ // The native handle will be freed in
+ // BpCameraRecordingProxyListener::releaseRecordingFrame.
+ }
+
dataCallbackTimestamp(timestamp, msgType, imageData);
return NO_ERROR;
} break;
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index b359f57..4a042a6 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -172,7 +172,7 @@
// connect to camera service (android.hardware.Camera)
virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
- const String16 &clientPackageName, int clientUid,
+ const String16 &clientPackageName, int clientUid, int clientPid,
/*out*/
sp<ICamera>& device)
{
@@ -182,6 +182,7 @@
data.writeInt32(cameraId);
data.writeString16(clientPackageName);
data.writeInt32(clientUid);
+ data.writeInt32(clientPid);
status_t status;
status = remote()->transact(BnCameraService::CONNECT, data, &reply);
@@ -396,9 +397,10 @@
int32_t cameraId = data.readInt32();
const String16 clientName = data.readString16();
int32_t clientUid = data.readInt32();
+ int32_t clientPid = data.readInt32();
sp<ICamera> camera;
status_t status = connect(cameraClient, cameraId,
- clientName, clientUid, /*out*/camera);
+ clientName, clientUid, clientPid, /*out*/camera);
reply->writeNoException();
reply->writeInt32(status);
if (camera != NULL) {
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 20a23e0..3505154 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -25,6 +25,7 @@
const int OutputConfiguration::INVALID_ROTATION = -1;
+const int OutputConfiguration::INVALID_SET_ID = -1;
// Read empty strings without printing a false error message.
String16 OutputConfiguration::readMaybeEmptyString16(const Parcel& parcel) {
@@ -45,6 +46,10 @@
return mRotation;
}
+int OutputConfiguration::getSurfaceSetID() const {
+ return mSurfaceSetID;
+}
+
OutputConfiguration::OutputConfiguration(const Parcel& parcel) {
status_t err;
int rotation = 0;
@@ -55,24 +60,36 @@
return;
}
+ int setID = INVALID_SET_ID;
+ if ((err = parcel.readInt32(&setID)) != OK) {
+ ALOGE("%s: Failed to read surface set ID from parcel", __FUNCTION__);
+ mGbp = NULL;
+ mSurfaceSetID = INVALID_SET_ID;
+ return;
+ }
+
String16 name = readMaybeEmptyString16(parcel);
const sp<IGraphicBufferProducer>& gbp =
interface_cast<IGraphicBufferProducer>(parcel.readStrongBinder());
mGbp = gbp;
mRotation = rotation;
+ mSurfaceSetID = setID;
ALOGV("%s: OutputConfiguration: bp = %p, name = %s", __FUNCTION__,
gbp.get(), String8(name).string());
}
-OutputConfiguration::OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation) {
+OutputConfiguration::OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
+ int surfaceSetID) {
mGbp = gbp;
mRotation = rotation;
+ mSurfaceSetID = surfaceSetID;
}
status_t OutputConfiguration::writeToParcel(Parcel& parcel) const {
parcel.writeInt32(mRotation);
+ parcel.writeInt32(mSurfaceSetID);
parcel.writeString16(String16("unknown_name")); // name of surface
sp<IBinder> b(IInterface::asBinder(mGbp));
parcel.writeStrongBinder(b);
diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk
new file mode 100644
index 0000000..4d8339c
--- /dev/null
+++ b/camera/cameraserver/Android.mk
@@ -0,0 +1,37 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ main_cameraserver.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcameraservice \
+ libcutils \
+ libutils \
+ libbinder
+
+LOCAL_C_INCLUDES := \
+ frameworks/av/services/camera/libcameraservice \
+ system/media/camera/include
+
+LOCAL_MODULE:= cameraserver
+LOCAL_32_BIT_ONLY := true
+
+LOCAL_INIT_RC := cameraserver.rc
+
+include $(BUILD_EXECUTABLE)
diff --git a/camera/cameraserver/cameraserver.rc b/camera/cameraserver/cameraserver.rc
new file mode 100644
index 0000000..37e2688
--- /dev/null
+++ b/camera/cameraserver/cameraserver.rc
@@ -0,0 +1,5 @@
+service cameraserver /system/bin/cameraserver
+ class main
+ user cameraserver
+ group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
+ ioprio rt 4
diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp
new file mode 100644
index 0000000..f4be468
--- /dev/null
+++ b/camera/cameraserver/main_cameraserver.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 "cameraserver"
+//#define LOG_NDEBUG 0
+
+// from LOCAL_C_INCLUDES
+#include "CameraService.h"
+
+using namespace android;
+
+int main(int argc __unused, char** argv __unused)
+{
+ signal(SIGPIPE, SIG_IGN);
+
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm = defaultServiceManager();
+ ALOGI("ServiceManager: %p", sm.get());
+ CameraService::instantiate();
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+}
diff --git a/camera/ndk/Android.mk b/camera/ndk/Android.mk
new file mode 100644
index 0000000..8e84e40
--- /dev/null
+++ b/camera/ndk/Android.mk
@@ -0,0 +1,57 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+ifneq ($(TARGET_BUILD_PDK), true)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ NdkCameraManager.cpp \
+ NdkCameraMetadata.cpp \
+ NdkCameraDevice.cpp \
+ NdkCaptureRequest.cpp \
+ NdkCameraCaptureSession.cpp \
+ impl/ACameraManager.cpp \
+ impl/ACameraMetadata.cpp \
+ impl/ACameraDevice.cpp \
+ impl/ACameraCaptureSession.cpp
+
+LOCAL_MODULE:= libcamera2ndk
+
+LOCAL_C_INCLUDES := \
+ system/media/camera/include \
+ frameworks/av/include/camera/ndk \
+ frameworks/av/include/ndk \
+
+LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ liblog \
+ libgui \
+ libutils \
+ libandroid_runtime \
+ libcamera_client \
+ libstagefright_foundation \
+ libcutils \
+
+LOCAL_CLANG := true
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
new file mode 100644
index 0000000..ab93bd6
--- /dev/null
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "NdkCameraCaptureSession"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
+#include <utils/Trace.h>
+
+#include "NdkCameraDevice.h"
+#include <NdkCaptureRequest.h>
+#include <NdkCameraCaptureSession.h>
+#include "impl/ACameraCaptureSession.h"
+
+using namespace android;
+
+EXPORT
+void ACameraCaptureSession_close(ACameraCaptureSession* session) {
+ ATRACE_CALL();
+ if (session != nullptr) {
+ session->closeByApp();
+ }
+ return;
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_getDevice(
+ ACameraCaptureSession* session, ACameraDevice **device) {
+ ATRACE_CALL();
+ if (session == nullptr || device == nullptr) {
+ ALOGE("%s: Error: invalid input: session %p, device %p",
+ __FUNCTION__, session, device);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (session->isClosed()) {
+ ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+ *device = nullptr;
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ *device = session->getDevice();
+ if (*device == nullptr) {
+ // Should not reach here
+ ALOGE("%s: unknown failure: device is null", __FUNCTION__);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_capture(
+ ACameraCaptureSession* session, /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ if (session == nullptr || requests == nullptr || numRequests < 1) {
+ ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
+ __FUNCTION__, session, numRequests, requests);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (session->isClosed()) {
+ ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ return session->capture(cbs, numRequests, requests, captureSequenceId);
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_setRepeatingRequest(
+ ACameraCaptureSession* session, /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ if (session == nullptr || requests == nullptr || numRequests < 1) {
+ ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
+ __FUNCTION__, session, numRequests, requests);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (session->isClosed()) {
+ ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ return session->setRepeatingRequest(cbs, numRequests, requests, captureSequenceId);
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_stopRepeating(ACameraCaptureSession* session) {
+ ATRACE_CALL();
+ if (session == nullptr) {
+ ALOGE("%s: Error: session is null", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (session->isClosed()) {
+ ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+ return session->stopRepeating();
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_abortCaptures(ACameraCaptureSession*) {
+ ATRACE_CALL();
+ return ACAMERA_OK;
+}
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
new file mode 100644
index 0000000..281d3e7
--- /dev/null
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "NdkCameraDevice"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <NdkCameraDevice.h>
+#include "impl/ACameraCaptureSession.h"
+
+using namespace android;
+
+EXPORT
+camera_status_t ACameraDevice_close(ACameraDevice* device) {
+ ATRACE_CALL();
+ if (device == nullptr) {
+ ALOGE("%s: invalid argument! device is null", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ delete device;
+ return ACAMERA_OK;
+}
+
+EXPORT
+const char* ACameraDevice_getId(const ACameraDevice* device) {
+ ATRACE_CALL();
+ if (device == nullptr) {
+ ALOGE("%s: invalid argument! device is null", __FUNCTION__);
+ return nullptr;
+ }
+ return device->getId();
+}
+
+EXPORT
+camera_status_t ACameraDevice_createCaptureRequest(
+ const ACameraDevice* device,
+ ACameraDevice_request_template templateId,
+ ACaptureRequest** request) {
+ ATRACE_CALL();
+ if (device == nullptr || request == nullptr) {
+ ALOGE("%s: invalid argument! device %p request %p",
+ __FUNCTION__, device, request);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ switch (templateId) {
+ case TEMPLATE_PREVIEW:
+ case TEMPLATE_STILL_CAPTURE:
+ case TEMPLATE_RECORD:
+ case TEMPLATE_VIDEO_SNAPSHOT:
+ case TEMPLATE_ZERO_SHUTTER_LAG:
+ case TEMPLATE_MANUAL:
+ break;
+ default:
+ ALOGE("%s: unknown template ID %d", __FUNCTION__, templateId);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return device->createCaptureRequest(templateId, request);
+}
+
+EXPORT
+camera_status_t ACaptureSessionOutputContainer_create(
+ /*out*/ACaptureSessionOutputContainer** out) {
+ ATRACE_CALL();
+ if (out == nullptr) {
+ ALOGE("%s: Error: out null", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ *out = new ACaptureSessionOutputContainer();
+ return ACAMERA_OK;
+}
+
+EXPORT
+void ACaptureSessionOutputContainer_free(ACaptureSessionOutputContainer* container) {
+ ATRACE_CALL();
+ if (container != nullptr) {
+ delete container;
+ }
+ return;
+}
+
+EXPORT
+camera_status_t ACaptureSessionOutput_create(
+ ANativeWindow* window, /*out*/ACaptureSessionOutput** out) {
+ ATRACE_CALL();
+ if (window == nullptr || out == nullptr) {
+ ALOGE("%s: Error: bad argument. window %p, out %p",
+ __FUNCTION__, window, out);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ *out = new ACaptureSessionOutput(window);
+ return ACAMERA_OK;
+}
+
+EXPORT
+void ACaptureSessionOutput_free(ACaptureSessionOutput* output) {
+ ATRACE_CALL();
+ if (output != nullptr) {
+ delete output;
+ }
+ return;
+}
+
+EXPORT
+camera_status_t ACaptureSessionOutputContainer_add(
+ ACaptureSessionOutputContainer* container, const ACaptureSessionOutput* output) {
+ ATRACE_CALL();
+ if (container == nullptr || output == nullptr) {
+ ALOGE("%s: Error: invalid input: container %p, output %p",
+ __FUNCTION__, container, output);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ auto pair = container->mOutputs.insert(*output);
+ if (!pair.second) {
+ ALOGW("%s: output %p already exists!", __FUNCTION__, output);
+ }
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACaptureSessionOutputContainer_remove(
+ ACaptureSessionOutputContainer* container, const ACaptureSessionOutput* output) {
+ ATRACE_CALL();
+ if (container == nullptr || output == nullptr) {
+ ALOGE("%s: Error: invalid input: container %p, output %p",
+ __FUNCTION__, container, output);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ container->mOutputs.erase(*output);
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraDevice_createCaptureSession(
+ ACameraDevice* device,
+ const ACaptureSessionOutputContainer* outputs,
+ const ACameraCaptureSession_stateCallbacks* callbacks,
+ /*out*/ACameraCaptureSession** session) {
+ ATRACE_CALL();
+ if (device == nullptr || outputs == nullptr || callbacks == nullptr || session == nullptr) {
+ ALOGE("%s: Error: invalid input: device %p, outputs %p, callbacks %p, session %p",
+ __FUNCTION__, device, outputs, callbacks, session);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return device->createCaptureSession(outputs, callbacks, session);
+}
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
new file mode 100644
index 0000000..7d9f84b
--- /dev/null
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "NdkCameraManager"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <NdkCameraManager.h>
+#include "impl/ACameraManager.h"
+
+EXPORT
+ACameraManager* ACameraManager_create() {
+ ATRACE_CALL();
+ return new ACameraManager();
+}
+
+EXPORT
+void ACameraManager_delete(ACameraManager* manager) {
+ ATRACE_CALL();
+ if (manager != nullptr) {
+ delete manager;
+ }
+}
+
+EXPORT
+camera_status_t ACameraManager_getCameraIdList(
+ ACameraManager* manager, ACameraIdList** cameraIdList) {
+ ATRACE_CALL();
+ if (manager == nullptr || cameraIdList == nullptr) {
+ ALOGE("%s: invalid argument! manager %p, cameraIdList %p",
+ __FUNCTION__, manager, cameraIdList);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return manager->getCameraIdList(cameraIdList);
+}
+
+EXPORT
+void ACameraManager_deleteCameraIdList(ACameraIdList* cameraIdList) {
+ ATRACE_CALL();
+ if (cameraIdList != nullptr) {
+ ACameraManager::deleteCameraIdList(cameraIdList);
+ }
+}
+
+EXPORT
+camera_status_t ACameraManager_registerAvailabilityCallback(
+ ACameraManager*, const ACameraManager_AvailabilityCallbacks *callback) {
+ ATRACE_CALL();
+ if (callback == nullptr) {
+ ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if (callback->onCameraAvailable == nullptr || callback->onCameraUnavailable == nullptr) {
+ ALOGE("%s: invalid argument! callback %p, "
+ "onCameraAvailable %p, onCameraUnavailable %p",
+ __FUNCTION__, callback,
+ callback->onCameraAvailable, callback->onCameraUnavailable);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ CameraManagerGlobal::getInstance().registerAvailabilityCallback(callback);
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraManager_unregisterAvailabilityCallback(
+ ACameraManager*, const ACameraManager_AvailabilityCallbacks *callback) {
+ ATRACE_CALL();
+ if (callback == nullptr) {
+ ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if (callback->onCameraAvailable == nullptr || callback->onCameraUnavailable == nullptr) {
+ ALOGE("%s: invalid argument! callback %p, "
+ "onCameraAvailable %p, onCameraUnavailable %p",
+ __FUNCTION__, callback,
+ callback->onCameraAvailable, callback->onCameraUnavailable);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ CameraManagerGlobal::getInstance().unregisterAvailabilityCallback(callback);
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraManager_getCameraCharacteristics(
+ ACameraManager* mgr, const char* cameraId, ACameraMetadata** chars){
+ ATRACE_CALL();
+ if (mgr == nullptr || cameraId == nullptr || chars == nullptr) {
+ ALOGE("%s: invalid argument! mgr %p cameraId %p chars %p",
+ __FUNCTION__, mgr, cameraId, chars);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return mgr->getCameraCharacteristics(cameraId, chars);
+}
+
+EXPORT
+camera_status_t ACameraManager_openCamera(
+ ACameraManager* mgr, const char* cameraId,
+ ACameraDevice_StateCallbacks* callback,
+ /*out*/ACameraDevice** device) {
+ ATRACE_CALL();
+ if (mgr == nullptr || cameraId == nullptr || callback == nullptr || device == nullptr) {
+ ALOGE("%s: invalid argument! mgr %p cameraId %p callback %p device %p",
+ __FUNCTION__, mgr, cameraId, callback, device);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return mgr->openCamera(cameraId, callback, device);
+}
diff --git a/camera/ndk/NdkCameraMetadata.cpp b/camera/ndk/NdkCameraMetadata.cpp
new file mode 100644
index 0000000..18718d3
--- /dev/null
+++ b/camera/ndk/NdkCameraMetadata.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "NdkCameraMetadata"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "NdkCameraMetadata.h"
+#include "impl/ACameraMetadata.h"
+
+using namespace android;
+
+EXPORT
+camera_status_t ACameraMetadata_getConstEntry(
+ const ACameraMetadata* acm, uint32_t tag, ACameraMetadata_const_entry* entry) {
+ ATRACE_CALL();
+ if (acm == nullptr || entry == nullptr) {
+ ALOGE("%s: invalid argument! metadata %p, tag 0x%x, entry %p",
+ __FUNCTION__, acm, tag, entry);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return acm->getConstEntry(tag, entry);
+}
+
+EXPORT
+ACameraMetadata* ACameraMetadata_copy(const ACameraMetadata* src) {
+ ATRACE_CALL();
+ if (src == nullptr) {
+ ALOGE("%s: src is null!", __FUNCTION__);
+ return nullptr;
+ }
+ return new ACameraMetadata(*src);
+}
+
+EXPORT
+void ACameraMetadata_free(ACameraMetadata* metadata) {
+ ATRACE_CALL();
+ if (metadata != nullptr) {
+ delete metadata;
+ }
+}
diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
new file mode 100644
index 0000000..4fee09c
--- /dev/null
+++ b/camera/ndk/NdkCaptureRequest.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "NdkCaptureRequest"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "NdkCaptureRequest.h"
+#include "impl/ACameraMetadata.h"
+#include "impl/ACaptureRequest.h"
+
+EXPORT
+camera_status_t ACameraOutputTarget_create(
+ ANativeWindow* window, ACameraOutputTarget** out) {
+ ATRACE_CALL();
+ if (window == nullptr) {
+ ALOGE("%s: Error: input window is null", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ *out = new ACameraOutputTarget(window);
+ return ACAMERA_OK;
+}
+
+EXPORT
+void ACameraOutputTarget_free(ACameraOutputTarget* target) {
+ ATRACE_CALL();
+ if (target != nullptr) {
+ delete target;
+ }
+ return;
+}
+
+EXPORT
+camera_status_t ACaptureRequest_addTarget(
+ ACaptureRequest* req, const ACameraOutputTarget* target) {
+ ATRACE_CALL();
+ if (req == nullptr || req->targets == nullptr || target == nullptr) {
+ ALOGE("%s: Error: invalid input: req %p, req-targets %p, target %p",
+ __FUNCTION__, req, req->targets, target);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ auto pair = req->targets->mOutputs.insert(*target);
+ if (!pair.second) {
+ ALOGW("%s: target %p already exists!", __FUNCTION__, target);
+ }
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACaptureRequest_removeTarget(
+ ACaptureRequest* req, const ACameraOutputTarget* target) {
+ ATRACE_CALL();
+ if (req == nullptr || req->targets == nullptr || target == nullptr) {
+ ALOGE("%s: Error: invalid input: req %p, req-targets %p, target %p",
+ __FUNCTION__, req, req->targets, target);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ req->targets->mOutputs.erase(*target);
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACaptureRequest_getConstEntry(
+ const ACaptureRequest* req, uint32_t tag, ACameraMetadata_const_entry* entry) {
+ ATRACE_CALL();
+ if (req == nullptr || entry == nullptr) {
+ ALOGE("%s: invalid argument! req 0x%p, tag 0x%x, entry 0x%p",
+ __FUNCTION__, req, tag, entry);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return req->settings->getConstEntry(tag, entry);
+}
+
+#define SET_ENTRY(NAME,NDK_TYPE) \
+EXPORT \
+camera_status_t ACaptureRequest_setEntry_##NAME( \
+ ACaptureRequest* req, uint32_t tag, uint32_t count, const NDK_TYPE* data) { \
+ ATRACE_CALL(); \
+ if (req == nullptr || (count > 0 && data == nullptr)) { \
+ ALOGE("%s: invalid argument! req %p, tag 0x%x, count %d, data 0x%p", \
+ __FUNCTION__, req, tag, count, data); \
+ return ACAMERA_ERROR_INVALID_PARAMETER; \
+ } \
+ return req->settings->update(tag, count, data); \
+}
+
+SET_ENTRY(u8,uint8_t)
+SET_ENTRY(i32,int32_t)
+SET_ENTRY(float,float)
+SET_ENTRY(double,double)
+SET_ENTRY(i64,int64_t)
+SET_ENTRY(rational,ACameraMetadata_rational)
+
+#undef SET_ENTRY
+
+EXPORT
+void ACaptureRequest_free(ACaptureRequest* request) {
+ ATRACE_CALL();
+ if (request == nullptr) {
+ return;
+ }
+ delete request->settings;
+ delete request->targets;
+ delete request;
+ return;
+}
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp
new file mode 100644
index 0000000..7f1b75d
--- /dev/null
+++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "ACameraCaptureSession"
+
+#include "ACameraCaptureSession.h"
+
+using namespace android;
+
+ACameraCaptureSession::~ACameraCaptureSession() {
+ ALOGV("~ACameraCaptureSession: %p notify device end of life", this);
+ sp<CameraDevice> dev = getDeviceSp();
+ if (dev != nullptr && !dev->isClosed()) {
+ dev->lockDeviceForSessionOps();
+ {
+ Mutex::Autolock _l(mSessionLock);
+ dev->notifySessionEndOfLifeLocked(this);
+ }
+ dev->unlockDevice();
+ }
+ // Fire onClosed callback
+ (*mUserSessionCallback.onClosed)(mUserSessionCallback.context, this);
+ ALOGV("~ACameraCaptureSession: %p is deleted", this);
+}
+
+void
+ACameraCaptureSession::closeByApp() {
+ sp<CameraDevice> dev = getDeviceSp();
+ if (dev != nullptr) {
+ dev->lockDeviceForSessionOps();
+ }
+
+ {
+ Mutex::Autolock _l(mSessionLock);
+
+ if (!mIsClosed && dev != nullptr) {
+ camera_status_t ret = dev->stopRepeatingLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Stop repeating request failed while closing session %p", this);
+ }
+ }
+ mIsClosed = true;
+ }
+
+ if (dev != nullptr) {
+ dev->unlockDevice();
+ }
+ this->decStrong((void*) ACameraDevice_createCaptureSession);
+}
+
+camera_status_t
+ACameraCaptureSession::stopRepeating() {
+ sp<CameraDevice> dev = getDeviceSp();
+ if (dev == nullptr) {
+ ALOGE("Error: Device associated with session %p has been closed!", this);
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ camera_status_t ret;
+ dev->lockDeviceForSessionOps();
+ {
+ Mutex::Autolock _l(mSessionLock);
+ ret = dev->stopRepeatingLocked();
+ }
+ dev->unlockDevice();
+ return ret;
+}
+
+camera_status_t
+ACameraCaptureSession::setRepeatingRequest(
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ sp<CameraDevice> dev = getDeviceSp();
+ if (dev == nullptr) {
+ ALOGE("Error: Device associated with session %p has been closed!", this);
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ camera_status_t ret;
+ dev->lockDeviceForSessionOps();
+ {
+ Mutex::Autolock _l(mSessionLock);
+ ret = dev->setRepeatingRequestsLocked(
+ this, cbs, numRequests, requests, captureSequenceId);
+ }
+ dev->unlockDevice();
+ return ret;
+}
+
+camera_status_t ACameraCaptureSession::capture(
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ sp<CameraDevice> dev = getDeviceSp();
+ if (dev == nullptr) {
+ ALOGE("Error: Device associated with session %p has been closed!", this);
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+ camera_status_t ret;
+ dev->lockDeviceForSessionOps();
+ {
+ Mutex::Autolock _l(mSessionLock);
+ ret = dev->captureLocked(this, cbs, numRequests, requests, captureSequenceId);
+ }
+ dev->unlockDevice();
+ return ret;
+}
+
+ACameraDevice*
+ACameraCaptureSession::getDevice() {
+ Mutex::Autolock _l(mSessionLock);
+ sp<CameraDevice> dev = getDeviceSp();
+ if (dev == nullptr) {
+ ALOGE("Error: Device associated with session %p has been closed!", this);
+ return nullptr;
+ }
+ return dev->getWrapper();
+}
+
+void
+ACameraCaptureSession::closeByDevice() {
+ Mutex::Autolock _l(mSessionLock);
+ mIsClosed = true;
+}
+
+sp<CameraDevice>
+ACameraCaptureSession::getDeviceSp() {
+ sp<CameraDevice> device = mDevice.promote();
+ if (device == nullptr || device->isClosed()) {
+ ALOGW("Device is closed but session %d is not notified", mId);
+ return nullptr;
+ }
+ return device;
+}
+
+
diff --git a/camera/ndk/impl/ACameraCaptureSession.h b/camera/ndk/impl/ACameraCaptureSession.h
new file mode 100644
index 0000000..1db1b21
--- /dev/null
+++ b/camera/ndk/impl/ACameraCaptureSession.h
@@ -0,0 +1,110 @@
+/*
+ * 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 _ACAMERA_CAPTURE_SESSION_H
+#define _ACAMERA_CAPTURE_SESSION_H
+
+#include <set>
+#include <hardware/camera3.h>
+#include <NdkCameraDevice.h>
+#include "ACameraDevice.h"
+
+using namespace android;
+
+struct ACaptureSessionOutput {
+ ACaptureSessionOutput(ANativeWindow* window) : mWindow(window) {};
+
+ bool operator == (const ACaptureSessionOutput& other) const {
+ return mWindow == other.mWindow;
+ }
+ bool operator != (const ACaptureSessionOutput& other) const {
+ return mWindow != other.mWindow;
+ }
+ bool operator < (const ACaptureSessionOutput& other) const {
+ return mWindow < other.mWindow;
+ }
+ bool operator > (const ACaptureSessionOutput& other) const {
+ return mWindow > other.mWindow;
+ }
+
+ ANativeWindow* mWindow;
+ int mRotation = CAMERA3_STREAM_ROTATION_0;
+};
+
+struct ACaptureSessionOutputContainer {
+ std::set<ACaptureSessionOutput> mOutputs;
+};
+
+/**
+ * ACameraCaptureSession opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraCaptureSession : public RefBase {
+ public:
+ ACameraCaptureSession(
+ int id,
+ const ACaptureSessionOutputContainer* outputs,
+ const ACameraCaptureSession_stateCallbacks* cb,
+ CameraDevice* device) :
+ mId(id), mOutput(*outputs), mUserSessionCallback(*cb),
+ mDevice(device) {}
+
+ // This can be called in app calling close() or after some app callback is finished
+ // Make sure the caller does not hold device or session lock!
+ ~ACameraCaptureSession();
+
+ // No API except Session_Close will work if device is closed
+ // A session will enter closed state when one of the following happens:
+ // 1. Explicitly closed by app
+ // 2. Replaced by a newer session
+ // 3. Device is closed
+ bool isClosed() { Mutex::Autolock _l(mSessionLock); return mIsClosed; }
+
+ // Close the session and mark app no longer need this session.
+ void closeByApp();
+
+ camera_status_t stopRepeating();
+
+ camera_status_t setRepeatingRequest(
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId);
+
+ camera_status_t capture(
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId);
+
+ ACameraDevice* getDevice();
+
+ private:
+ friend class CameraDevice;
+
+ // Close session because app close camera device, camera device got ERROR_DISCONNECTED,
+ // or a new session is replacing this session.
+ void closeByDevice();
+
+ sp<CameraDevice> getDeviceSp();
+
+ const int mId;
+ const ACaptureSessionOutputContainer mOutput;
+ const ACameraCaptureSession_stateCallbacks mUserSessionCallback;
+ const wp<CameraDevice> mDevice;
+ bool mIsClosed = false;
+ bool mIdle = true;
+ Mutex mSessionLock;
+};
+
+#endif // _ACAMERA_CAPTURE_SESSION_H
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
new file mode 100644
index 0000000..5f89fa3
--- /dev/null
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -0,0 +1,1212 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "ACameraDevice"
+
+#include <vector>
+#include <utility>
+#include <inttypes.h>
+#include <gui/Surface.h>
+#include "ACameraDevice.h"
+#include "ACameraMetadata.h"
+#include "ACaptureRequest.h"
+#include "ACameraCaptureSession.h"
+
+using namespace android;
+
+namespace android {
+// Static member definitions
+const char* CameraDevice::kContextKey = "Context";
+const char* CameraDevice::kDeviceKey = "Device";
+const char* CameraDevice::kErrorCodeKey = "ErrorCode";
+const char* CameraDevice::kCallbackFpKey = "Callback";
+const char* CameraDevice::kSessionSpKey = "SessionSp";
+const char* CameraDevice::kCaptureRequestKey = "CaptureRequest";
+const char* CameraDevice::kTimeStampKey = "TimeStamp";
+const char* CameraDevice::kCaptureResultKey = "CaptureResult";
+const char* CameraDevice::kCaptureFailureKey = "CaptureFailure";
+const char* CameraDevice::kSequenceIdKey = "SequenceId";
+const char* CameraDevice::kFrameNumberKey = "FrameNumber";
+
+/**
+ * CameraDevice Implementation
+ */
+CameraDevice::CameraDevice(
+ const char* id,
+ ACameraDevice_StateCallbacks* cb,
+ std::unique_ptr<ACameraMetadata> chars,
+ ACameraDevice* wrapper) :
+ mCameraId(id),
+ mAppCallbacks(*cb),
+ mChars(std::move(chars)),
+ mServiceCallback(new ServiceCallback(this)),
+ mWrapper(wrapper),
+ mInError(false),
+ mError(ACAMERA_OK),
+ mIdle(true) {
+ mClosing = false;
+ // Setup looper thread to perfrom device callbacks to app
+ mCbLooper = new ALooper;
+ mCbLooper->setName("C2N-dev-looper");
+ status_t ret = mCbLooper->start(
+ /*runOnCallingThread*/false,
+ /*canCallJava*/ true,
+ PRIORITY_DEFAULT);
+ mHandler = new CallbackHandler();
+ mCbLooper->registerHandler(mHandler);
+
+ CameraMetadata metadata = mChars->mData;
+ camera_metadata_entry entry = metadata.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
+ if (entry.count != 1) {
+ ALOGW("%s: bad count %zu for partial result count", __FUNCTION__, entry.count);
+ mPartialResultCount = 1;
+ } else {
+ mPartialResultCount = entry.data.i32[0];
+ }
+
+ entry = metadata.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
+ if (entry.count != 2) {
+ ALOGW("%s: bad count %zu for shading map size", __FUNCTION__, entry.count);
+ mShadingMapSize[0] = 0;
+ mShadingMapSize[1] = 0;
+ } else {
+ mShadingMapSize[0] = entry.data.i32[0];
+ mShadingMapSize[1] = entry.data.i32[1];
+ }
+}
+
+// Device close implementaiton
+CameraDevice::~CameraDevice() {
+ Mutex::Autolock _l(mDeviceLock);
+ if (!isClosed()) {
+ disconnectLocked();
+ }
+ if (mCbLooper != nullptr) {
+ mCbLooper->unregisterHandler(mHandler->id());
+ mCbLooper->stop();
+ }
+ mCbLooper.clear();
+ mHandler.clear();
+}
+
+// TODO: cached created request?
+camera_status_t
+CameraDevice::createCaptureRequest(
+ ACameraDevice_request_template templateId,
+ ACaptureRequest** request) const {
+ Mutex::Autolock _l(mDeviceLock);
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+ if (mRemote == nullptr) {
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ CameraMetadata rawRequest;
+ status_t remoteRet = mRemote->createDefaultRequest(templateId, &rawRequest);
+ if (remoteRet == BAD_VALUE) {
+ ALOGW("Create capture request failed! template %d is not supported on this device",
+ templateId);
+ return ACAMERA_ERROR_UNSUPPORTED;
+ } else if (remoteRet != OK) {
+ ALOGE("Create capture request failed! error %d", remoteRet);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ ACaptureRequest* outReq = new ACaptureRequest();
+ outReq->settings = new ACameraMetadata(rawRequest.release(), ACameraMetadata::ACM_REQUEST);
+ outReq->targets = new ACameraOutputTargets();
+ *request = outReq;
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::createCaptureSession(
+ const ACaptureSessionOutputContainer* outputs,
+ const ACameraCaptureSession_stateCallbacks* callbacks,
+ /*out*/ACameraCaptureSession** session) {
+ Mutex::Autolock _l(mDeviceLock);
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+
+ if (mCurrentSession != nullptr) {
+ mCurrentSession->closeByDevice();
+ stopRepeatingLocked();
+ }
+
+ // Create new session
+ ret = configureStreamsLocked(outputs);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Fail to create new session. cannot configure streams");
+ return ret;
+ }
+
+ ACameraCaptureSession* newSession = new ACameraCaptureSession(
+ mNextSessionId++, outputs, callbacks, this);
+
+ bool configureSucceeded = (ret == ACAMERA_OK);
+
+ // set new session as current session
+ newSession->incStrong((void *) ACameraDevice_createCaptureSession);
+ mCurrentSession = newSession;
+ *session = newSession;
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::captureLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ return submitRequestsLocked(
+ session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/false);
+}
+
+camera_status_t
+CameraDevice::setRepeatingRequestsLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ return submitRequestsLocked(
+ session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/true);
+}
+
+camera_status_t
+CameraDevice::submitRequestsLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId,
+ bool isRepeating) {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s submit capture request failed! ret %d", getId(), ret);
+ return ret;
+ }
+
+ // Form List/Vector of capture request
+ List<sp<CaptureRequest> > requestList;
+ Vector<sp<CaptureRequest> > requestsV;
+ requestsV.setCapacity(numRequests);
+ for (int i = 0; i < numRequests; i++) {
+ sp<CaptureRequest> req;
+ ret = allocateCaptureRequest(requests[i], req);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Convert capture request to internal format failure! ret %d", ret);
+ return ret;
+ }
+ if (req->mSurfaceList.empty()) {
+ ALOGE("Capture request without output target cannot be submitted!");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ requestList.push_back(req);
+ requestsV.push_back(req);
+ }
+
+ if (isRepeating) {
+ ret = stopRepeatingLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
+ return ret;
+ }
+ }
+
+ int sequenceId;
+ int64_t lastFrameNumber;
+
+ sequenceId = mRemote->submitRequestList(requestList, isRepeating, &lastFrameNumber);
+ if (sequenceId < 0) {
+ ALOGE("Camera %s submit request remote failure: ret %d", getId(), sequenceId);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+
+ CallbackHolder cbHolder(session, requestsV, isRepeating, cbs);
+ mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
+
+ if (isRepeating) {
+ // stopRepeating above should have cleanup repeating sequence id
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return ACAMERA_ERROR_CAMERA_DEVICE;
+ }
+ mRepeatingSequenceId = sequenceId;
+ } else {
+ mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
+ }
+
+ if (mIdle) {
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+ msg->setPointer(kContextKey, session->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
+ msg->post();
+ }
+ mIdle = false;
+ mBusySession = session;
+
+ if (captureSequenceId) {
+ *captureSequenceId = sequenceId;
+ }
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::allocateCaptureRequest(
+ const ACaptureRequest* request, /*out*/sp<CaptureRequest>& outReq) {
+ camera_status_t ret;
+ sp<CaptureRequest> req(new CaptureRequest());
+ req->mMetadata = request->settings->mData;
+ req->mIsReprocess = false; // NDK does not support reprocessing yet
+
+ for (auto outputTarget : request->targets->mOutputs) {
+ ANativeWindow* anw = outputTarget.mWindow;
+ sp<Surface> surface;
+ ret = getSurfaceFromANativeWindow(anw, surface);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Bad output target in capture request! ret %d", ret);
+ return ret;
+ }
+ req->mSurfaceList.push_back(surface);
+ }
+ outReq = req;
+ return ACAMERA_OK;
+}
+
+ACaptureRequest*
+CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req) {
+ ACaptureRequest* pRequest = new ACaptureRequest();
+ CameraMetadata clone = req->mMetadata;
+ pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
+ pRequest->targets = new ACameraOutputTargets();
+ for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
+ ANativeWindow* anw = static_cast<ANativeWindow*>(req->mSurfaceList[i].get());
+ ACameraOutputTarget outputTarget(anw);
+ pRequest->targets->mOutputs.insert(outputTarget);
+ }
+ return pRequest;
+}
+
+void
+CameraDevice::freeACaptureRequest(ACaptureRequest* req) {
+ if (req == nullptr) {
+ return;
+ }
+ delete req->settings;
+ delete req->targets;
+ delete req;
+}
+
+void
+CameraDevice::notifySessionEndOfLifeLocked(ACameraCaptureSession* session) {
+ if (isClosed()) {
+ // Device is closing already. do nothing
+ return;
+ }
+
+ if (session != mCurrentSession) {
+ // Session has been replaced by other seesion or device is closed
+ return;
+ }
+ mCurrentSession = nullptr;
+
+ // Should not happen
+ if (!session->mIsClosed) {
+ ALOGE("Error: unclosed session %p reaches end of life!", session);
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return;
+ }
+
+ // No new session, unconfigure now
+ camera_status_t ret = configureStreamsLocked(nullptr);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Unconfigure stream failed. Device might still be configured! ret %d", ret);
+ }
+}
+
+void
+CameraDevice::disconnectLocked() {
+ if (mClosing.exchange(true)) {
+ // Already closing, just return
+ ALOGW("Camera device %s is already closing.", getId());
+ return;
+ }
+
+ if (mRemote != nullptr) {
+ mRemote->disconnect();
+ }
+ mRemote = nullptr;
+
+ if (mCurrentSession != nullptr) {
+ mCurrentSession->closeByDevice();
+ mCurrentSession = nullptr;
+ }
+}
+
+camera_status_t
+CameraDevice::stopRepeatingLocked() {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
+ return ret;
+ }
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ int repeatingSequenceId = mRepeatingSequenceId;
+ mRepeatingSequenceId = REQUEST_ID_NONE;
+
+ int64_t lastFrameNumber;
+ status_t remoteRet = mRemote->cancelRequest(repeatingSequenceId, &lastFrameNumber);
+ if (remoteRet != OK) {
+ ALOGE("Stop repeating request fails in remote! ret %d", remoteRet);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
+ }
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::waitUntilIdleLocked() {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Wait until camera %s idle failed! ret %d", getId(), ret);
+ return ret;
+ }
+
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ ALOGE("Camera device %s won't go to idle when there is repeating request!", getId());
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ }
+
+ status_t remoteRet = mRemote->waitUntilIdle();
+ if (remoteRet != OK) {
+ ALOGE("Camera device %s waitUntilIdle failed! ret %d", getId(), remoteRet);
+ // TODO: define a function to convert status_t -> camera_status_t
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::getIGBPfromSessionOutput(
+ const ACaptureSessionOutput& config,
+ sp<IGraphicBufferProducer>& out) {
+ ANativeWindow* anw = config.mWindow;
+ if (anw == nullptr) {
+ ALOGE("Error: output ANativeWindow is null");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ int value;
+ int err = (*anw->query)(anw, NATIVE_WINDOW_CONCRETE_TYPE, &value);
+ if (value != NATIVE_WINDOW_SURFACE) {
+ ALOGE("Error: ANativeWindow is not backed by Surface!");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ const sp<Surface> surface(static_cast<Surface*>(anw));
+ out = surface->getIGraphicBufferProducer();
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::getSurfaceFromANativeWindow(
+ ANativeWindow* anw, sp<Surface>& out) {
+ if (anw == nullptr) {
+ ALOGE("Error: output ANativeWindow is null");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ int value;
+ int err = (*anw->query)(anw, NATIVE_WINDOW_CONCRETE_TYPE, &value);
+ if (value != NATIVE_WINDOW_SURFACE) {
+ ALOGE("Error: ANativeWindow is not backed by Surface!");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ sp<Surface> surface(static_cast<Surface*>(anw));
+ out = surface;
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::configureStreamsLocked(const ACaptureSessionOutputContainer* outputs) {
+ ACaptureSessionOutputContainer emptyOutput;
+ if (outputs == nullptr) {
+ outputs = &emptyOutput;
+ }
+
+ bool success = false;
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+
+ std::set<OutputConfiguration> outputSet;
+ for (auto outConfig : outputs->mOutputs) {
+ sp<IGraphicBufferProducer> iGBP(nullptr);
+ ret = getIGBPfromSessionOutput(outConfig, iGBP);
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+ outputSet.insert(OutputConfiguration(iGBP, outConfig.mRotation));
+ }
+ std::set<OutputConfiguration> addSet = outputSet;
+ std::vector<int> deleteList;
+
+ // Determine which streams need to be created, which to be deleted
+ for (auto& kvPair : mConfiguredOutputs) {
+ int streamId = kvPair.first;
+ OutputConfiguration& outConfig = kvPair.second;
+ if (outputSet.count(outConfig) == 0) {
+ deleteList.push_back(streamId); // Need to delete a no longer needed stream
+ } else {
+ addSet.erase(outConfig); // No need to add already existing stream
+ }
+ }
+
+ ret = stopRepeatingLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera device %s stop repeating failed, ret %d", getId(), ret);
+ return ret;
+ }
+
+ ret = waitUntilIdleLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera device %s wait until idle failed, ret %d", getId(), ret);
+ return ret;
+ }
+
+ // Send onReady to previous session
+ // CurrentSession will be updated after configureStreamLocked, so here
+ // mCurrentSession is the session to be replaced by a new session
+ if (!mIdle && mCurrentSession != nullptr) {
+ if (mBusySession != mCurrentSession) {
+ ALOGE("Current session != busy session");
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return ACAMERA_ERROR_CAMERA_DEVICE;
+ }
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+ msg->setPointer(kContextKey, mBusySession->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, mBusySession);
+ msg->setPointer(kCallbackFpKey, (void*) mBusySession->mUserSessionCallback.onReady);
+ mBusySession.clear();
+ msg->post();
+ }
+ mIdle = true;
+
+ status_t remoteRet = mRemote->beginConfigure();
+ if (remoteRet != ACAMERA_OK) {
+ ALOGE("Camera device %s begin configure failed, ret %d", getId(), remoteRet);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+
+ // delete to-be-deleted streams
+ for (auto streamId : deleteList) {
+ remoteRet = mRemote->deleteStream(streamId);
+ if (remoteRet != ACAMERA_OK) {
+ ALOGE("Camera device %s fails to remove stream %d", getId(), streamId);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ mConfiguredOutputs.erase(streamId);
+ }
+
+ // add new streams
+ for (auto outConfig : addSet) {
+ remoteRet = mRemote->createStream(outConfig);
+ if (remoteRet < 0) {
+ ALOGE("Camera device %s fails to create stream", getId());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ int streamId = remoteRet; // Weird, right?
+ mConfiguredOutputs.insert(std::make_pair(streamId, outConfig));
+ }
+
+ remoteRet = mRemote->endConfigure();
+ if (remoteRet == BAD_VALUE) {
+ ALOGE("Camera device %s cannnot support app output configuration", getId());
+ return ACAMERA_ERROR_STREAM_CONFIGURE_FAIL;
+ } else if (remoteRet != ACAMERA_OK) {
+ ALOGE("Camera device %s end configure failed, ret %d", getId(), remoteRet);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+
+ return ACAMERA_OK;
+}
+
+void
+CameraDevice::setRemoteDevice(sp<ICameraDeviceUser> remote) {
+ Mutex::Autolock _l(mDeviceLock);
+ mRemote = remote;
+}
+
+camera_status_t
+CameraDevice::checkCameraClosedOrErrorLocked() const {
+ if (mRemote == nullptr) {
+ ALOGE("%s: camera device already closed", __FUNCTION__);
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ if (mInError) {// triggered by onDeviceError
+ ALOGE("%s: camera device has encountered a serious error", __FUNCTION__);
+ return mError;
+ }
+ return ACAMERA_OK;
+}
+
+void
+CameraDevice::setCameraDeviceErrorLocked(camera_status_t error) {
+ mInError = true;
+ mError = error;
+ return;
+}
+
+void
+CameraDevice::FrameNumberTracker::updateTracker(int64_t frameNumber, bool isError) {
+ ALOGV("updateTracker frame %" PRId64 " isError %d", frameNumber, isError);
+ if (isError) {
+ mFutureErrorSet.insert(frameNumber);
+ } else if (frameNumber <= mCompletedFrameNumber) {
+ ALOGE("Frame number %" PRId64 " decreased! current fn %" PRId64,
+ frameNumber, mCompletedFrameNumber);
+ return;
+ } else {
+ if (frameNumber != mCompletedFrameNumber + 1) {
+ ALOGE("Frame number out of order. Expect %" PRId64 " but get %" PRId64,
+ mCompletedFrameNumber + 1, frameNumber);
+ // Do not assert as in java implementation
+ }
+ mCompletedFrameNumber = frameNumber;
+ }
+ update();
+}
+
+void
+CameraDevice::FrameNumberTracker::update() {
+ for (auto it = mFutureErrorSet.begin(); it != mFutureErrorSet.end();) {
+ int64_t errorFrameNumber = *it;
+ if (errorFrameNumber == mCompletedFrameNumber + 1) {
+ mCompletedFrameNumber++;
+ it = mFutureErrorSet.erase(it);
+ } else if (errorFrameNumber <= mCompletedFrameNumber) {
+ // This should not happen, but deal with it anyway
+ ALOGE("Completd frame number passed through current frame number!");
+ // erase the old error since it's no longer useful
+ it = mFutureErrorSet.erase(it);
+ } else {
+ // Normal requests hasn't catched up error frames, just break
+ break;
+ }
+ }
+ ALOGV("Update complete frame %" PRId64, mCompletedFrameNumber);
+}
+
+void
+CameraDevice::onCaptureErrorLocked(
+ ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
+ int sequenceId = resultExtras.requestId;
+ int64_t frameNumber = resultExtras.frameNumber;
+ int32_t burstId = resultExtras.burstId;
+
+ // No way to report buffer error now
+ if (errorCode == ICameraDeviceCallbacks::CameraErrorCode::ERROR_CAMERA_BUFFER) {
+ ALOGE("Camera %s Lost output buffer for frame %" PRId64,
+ getId(), frameNumber);
+ return;
+ }
+ // Fire capture failure callback if there is one registered
+ auto it = mSequenceCallbackMap.find(sequenceId);
+ if (it != mSequenceCallbackMap.end()) {
+ CallbackHolder cbh = (*it).second;
+ ACameraCaptureSession_captureCallback_failed onError = cbh.mCallbacks.onCaptureFailed;
+ sp<ACameraCaptureSession> session = cbh.mSession;
+ if ((size_t) burstId >= cbh.mRequests.size()) {
+ ALOGE("%s: Error: request index %d out of bound (size %zu)",
+ __FUNCTION__, burstId, cbh.mRequests.size());
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ return;
+ }
+ sp<CaptureRequest> request = cbh.mRequests[burstId];
+ sp<CameraCaptureFailure> failure(new CameraCaptureFailure());
+ failure->frameNumber = frameNumber;
+ // TODO: refine this when implementing flush
+ failure->reason = CAPTURE_FAILURE_REASON_ERROR;
+ failure->sequenceId = sequenceId;
+ failure->wasImageCaptured = (errorCode ==
+ ICameraDeviceCallbacks::CameraErrorCode::ERROR_CAMERA_RESULT);
+
+ sp<AMessage> msg = new AMessage(kWhatCaptureFail, mHandler);
+ msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) onError);
+ msg->setObject(kCaptureRequestKey, request);
+ msg->setObject(kCaptureFailureKey, failure);
+ msg->post();
+ }
+
+ // Update tracker
+ mFrameNumberTracker.updateTracker(frameNumber, /*isError*/true);
+ checkAndFireSequenceCompleteLocked();
+}
+
+void CameraDevice::CallbackHandler::onMessageReceived(
+ const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatOnDisconnected:
+ case kWhatOnError:
+ case kWhatSessionStateCb:
+ case kWhatCaptureStart:
+ case kWhatCaptureResult:
+ case kWhatCaptureFail:
+ case kWhatCaptureSeqEnd:
+ case kWhatCaptureSeqAbort:
+ ALOGV("%s: Received msg %d", __FUNCTION__, msg->what());
+ break;
+ default:
+ ALOGE("%s:Error: unknown device callback %d", __FUNCTION__, msg->what());
+ return;
+ }
+ // Check the common part of all message
+ void* context;
+ bool found = msg->findPointer(kContextKey, &context);
+ if (!found) {
+ ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+ return;
+ }
+ switch (msg->what()) {
+ case kWhatOnDisconnected:
+ {
+ ACameraDevice* dev;
+ found = msg->findPointer(kDeviceKey, (void**) &dev);
+ if (!found || dev == nullptr) {
+ ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
+ return;
+ }
+ ACameraDevice_StateCallback onDisconnected;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onDisconnected);
+ if (!found) {
+ ALOGE("%s: Cannot find onDisconnected!", __FUNCTION__);
+ return;
+ }
+ if (onDisconnected == nullptr) {
+ return;
+ }
+ (*onDisconnected)(context, dev);
+ break;
+ }
+ case kWhatOnError:
+ {
+ ACameraDevice* dev;
+ found = msg->findPointer(kDeviceKey, (void**) &dev);
+ if (!found || dev == nullptr) {
+ ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
+ return;
+ }
+ ACameraDevice_ErrorStateCallback onError;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onError);
+ if (!found) {
+ ALOGE("%s: Cannot find onError!", __FUNCTION__);
+ return;
+ }
+ int errorCode;
+ found = msg->findInt32(kErrorCodeKey, &errorCode);
+ if (!found) {
+ ALOGE("%s: Cannot find error code!", __FUNCTION__);
+ return;
+ }
+ if (onError == nullptr) {
+ return;
+ }
+ (*onError)(context, dev, errorCode);
+ break;
+ }
+ case kWhatSessionStateCb:
+ case kWhatCaptureStart:
+ case kWhatCaptureResult:
+ case kWhatCaptureFail:
+ case kWhatCaptureSeqEnd:
+ case kWhatCaptureSeqAbort:
+ {
+ sp<RefBase> obj;
+ found = msg->findObject(kSessionSpKey, &obj);
+ if (!found || obj == nullptr) {
+ ALOGE("%s: Cannot find session pointer!", __FUNCTION__);
+ return;
+ }
+ sp<ACameraCaptureSession> session(static_cast<ACameraCaptureSession*>(obj.get()));
+ sp<CaptureRequest> requestSp = nullptr;
+ switch (msg->what()) {
+ case kWhatCaptureStart:
+ case kWhatCaptureResult:
+ case kWhatCaptureFail:
+ found = msg->findObject(kCaptureRequestKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find capture request!", __FUNCTION__);
+ return;
+ }
+ requestSp = static_cast<CaptureRequest*>(obj.get());
+ break;
+ }
+
+ switch (msg->what()) {
+ case kWhatSessionStateCb:
+ {
+ ACameraCaptureSession_stateCallback onState;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onState);
+ if (!found) {
+ ALOGE("%s: Cannot find state callback!", __FUNCTION__);
+ return;
+ }
+ if (onState == nullptr) {
+ return;
+ }
+ (*onState)(context, session.get());
+ break;
+ }
+ case kWhatCaptureStart:
+ {
+ ACameraCaptureSession_captureCallback_start onStart;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onStart);
+ if (!found) {
+ ALOGE("%s: Cannot find capture start callback!", __FUNCTION__);
+ return;
+ }
+ if (onStart == nullptr) {
+ return;
+ }
+ int64_t timestamp;
+ found = msg->findInt64(kTimeStampKey, ×tamp);
+ if (!found) {
+ ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
+ return;
+ }
+ ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ (*onStart)(context, session.get(), request, timestamp);
+ freeACaptureRequest(request);
+ break;
+ }
+ case kWhatCaptureResult:
+ {
+ ACameraCaptureSession_captureCallback_result onResult;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onResult);
+ if (!found) {
+ ALOGE("%s: Cannot find capture result callback!", __FUNCTION__);
+ return;
+ }
+ if (onResult == nullptr) {
+ return;
+ }
+
+ found = msg->findObject(kCaptureResultKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find capture result!", __FUNCTION__);
+ return;
+ }
+ sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
+ ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ (*onResult)(context, session.get(), request, result.get());
+ freeACaptureRequest(request);
+ break;
+ }
+ case kWhatCaptureFail:
+ {
+ ACameraCaptureSession_captureCallback_failed onFail;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onFail);
+ if (!found) {
+ ALOGE("%s: Cannot find capture fail callback!", __FUNCTION__);
+ return;
+ }
+ if (onFail == nullptr) {
+ return;
+ }
+
+ found = msg->findObject(kCaptureFailureKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find capture failure!", __FUNCTION__);
+ return;
+ }
+ sp<CameraCaptureFailure> failureSp(
+ static_cast<CameraCaptureFailure*>(obj.get()));
+ ACameraCaptureFailure* failure =
+ static_cast<ACameraCaptureFailure*>(failureSp.get());
+ ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ (*onFail)(context, session.get(), request, failure);
+ freeACaptureRequest(request);
+ delete failure;
+ break;
+ }
+ case kWhatCaptureSeqEnd:
+ {
+ ACameraCaptureSession_captureCallback_sequenceEnd onSeqEnd;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onSeqEnd);
+ if (!found) {
+ ALOGE("%s: Cannot find sequence end callback!", __FUNCTION__);
+ return;
+ }
+ if (onSeqEnd == nullptr) {
+ return;
+ }
+ int seqId;
+ found = msg->findInt32(kSequenceIdKey, &seqId);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+ int64_t frameNumber;
+ found = msg->findInt64(kFrameNumberKey, &frameNumber);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+ (*onSeqEnd)(context, session.get(), seqId, frameNumber);
+ break;
+ }
+ case kWhatCaptureSeqAbort:
+ {
+ ACameraCaptureSession_captureCallback_sequenceAbort onSeqAbort;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onSeqAbort);
+ if (!found) {
+ ALOGE("%s: Cannot find sequence end callback!", __FUNCTION__);
+ return;
+ }
+ if (onSeqAbort == nullptr) {
+ return;
+ }
+ int seqId;
+ found = msg->findInt32(kSequenceIdKey, &seqId);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+ (*onSeqAbort)(context, session.get(), seqId);
+ break;
+ }
+ }
+ break;
+ }
+ }
+}
+
+CameraDevice::CallbackHolder::CallbackHolder(
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacks* cbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating), mCallbacks(fillCb(cbs)) {}
+
+void
+CameraDevice::checkRepeatingSequenceCompleteLocked(
+ const int sequenceId, const int64_t lastFrameNumber) {
+ ALOGV("Repeating seqId %d lastFrameNumer %" PRId64, sequenceId, lastFrameNumber);
+ if (lastFrameNumber == NO_FRAMES_CAPTURED) {
+ if (mSequenceCallbackMap.count(sequenceId) == 0) {
+ ALOGW("No callback found for sequenceId %d", sequenceId);
+ return;
+ }
+ // remove callback holder from callback map
+ auto cbIt = mSequenceCallbackMap.find(sequenceId);
+ CallbackHolder cbh = cbIt->second;
+ mSequenceCallbackMap.erase(cbIt);
+ // send seq aborted callback
+ sp<AMessage> msg = new AMessage(kWhatCaptureSeqAbort, mHandler);
+ msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setObject(kSessionSpKey, cbh.mSession);
+ msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceAborted);
+ msg->setInt32(kSequenceIdKey, sequenceId);
+ msg->post();
+ } else {
+ // Use mSequenceLastFrameNumberMap to track
+ mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
+
+ // Last frame might have arrived. Check now
+ checkAndFireSequenceCompleteLocked();
+ }
+}
+
+void
+CameraDevice::checkAndFireSequenceCompleteLocked() {
+ int64_t completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
+ //std::map<int, int64_t> mSequenceLastFrameNumberMap;
+ auto it = mSequenceLastFrameNumberMap.begin();
+ while (it != mSequenceLastFrameNumberMap.end()) {
+ int sequenceId = it->first;
+ int64_t lastFrameNumber = it->second;
+ bool seqCompleted = false;
+ bool hasCallback = true;
+
+ if (mRemote == nullptr) {
+ ALOGW("Camera %s closed while checking sequence complete", getId());
+ return;
+ }
+
+ // Check if there is callback for this sequence
+ // This should not happen because we always register callback (with nullptr inside)
+ if (mSequenceCallbackMap.count(sequenceId) == 0) {
+ ALOGW("No callback found for sequenceId %d", sequenceId);
+ hasCallback = false;
+ }
+
+ if (lastFrameNumber <= completedFrameNumber) {
+ ALOGV("seq %d reached last frame %" PRId64 ", completed %" PRId64,
+ sequenceId, lastFrameNumber, completedFrameNumber);
+ seqCompleted = true;
+ }
+
+ if (seqCompleted && hasCallback) {
+ // remove callback holder from callback map
+ auto cbIt = mSequenceCallbackMap.find(sequenceId);
+ CallbackHolder cbh = cbIt->second;
+ mSequenceCallbackMap.erase(cbIt);
+ // send seq complete callback
+ sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler);
+ msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setObject(kSessionSpKey, cbh.mSession);
+ msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceCompleted);
+ msg->setInt32(kSequenceIdKey, sequenceId);
+ msg->setInt64(kFrameNumberKey, lastFrameNumber);
+
+ // Clear the session sp before we send out the message
+ // This will guarantee the rare case where the message is processed
+ // before cbh goes out of scope and causing we call the session
+ // destructor while holding device lock
+ cbh.mSession.clear();
+ msg->post();
+ }
+
+ // No need to track sequence complete if there is no callback registered
+ if (seqCompleted || !hasCallback) {
+ it = mSequenceLastFrameNumberMap.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+/**
+ * Camera service callback implementation
+ */
+void
+CameraDevice::ServiceCallback::onDeviceError(
+ CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
+ ALOGD("Device error received, code %d, frame number %" PRId64 ", request ID %d, subseq ID %d",
+ errorCode, resultExtras.frameNumber, resultExtras.requestId, resultExtras.burstId);
+
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return; // device has been closed
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->mRemote == nullptr) {
+ return; // device has been closed
+ }
+ switch (errorCode) {
+ case ERROR_CAMERA_DISCONNECTED:
+ {
+ // Camera is disconnected, close the session and expect no more callbacks
+ if (dev->mCurrentSession != nullptr) {
+ dev->mCurrentSession->closeByDevice();
+ dev->mCurrentSession = nullptr;
+ }
+ sp<AMessage> msg = new AMessage(kWhatOnDisconnected, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mAppCallbacks.context);
+ msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
+ msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onDisconnected);
+ msg->post();
+ break;
+ }
+ default:
+ ALOGE("Unknown error from camera device: %d", errorCode);
+ // no break
+ case ERROR_CAMERA_DEVICE:
+ case ERROR_CAMERA_SERVICE:
+ {
+ switch (errorCode) {
+ case ERROR_CAMERA_DEVICE:
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ break;
+ case ERROR_CAMERA_SERVICE:
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ break;
+ default:
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_UNKNOWN);
+ break;
+ }
+ sp<AMessage> msg = new AMessage(kWhatOnError, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mAppCallbacks.context);
+ msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
+ msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onError);
+ msg->setInt32(kErrorCodeKey, errorCode);
+ msg->post();
+ break;
+ }
+ case ERROR_CAMERA_REQUEST:
+ case ERROR_CAMERA_RESULT:
+ case ERROR_CAMERA_BUFFER:
+ dev->onCaptureErrorLocked(errorCode, resultExtras);
+ break;
+ }
+}
+
+void
+CameraDevice::ServiceCallback::onDeviceIdle() {
+ ALOGV("Camera is now idle");
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return; // device has been closed
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->isClosed() || dev->mRemote == nullptr) {
+ return;
+ }
+
+ if (dev->mIdle) {
+ // Already in idle state. Possibly other thread did waitUntilIdle
+ return;
+ }
+
+ if (dev->mCurrentSession != nullptr) {
+ ALOGE("onDeviceIdle sending state cb");
+ if (dev->mBusySession != dev->mCurrentSession) {
+ ALOGE("Current session != busy session");
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return;
+ }
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mBusySession->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, dev->mBusySession);
+ msg->setPointer(kCallbackFpKey, (void*) dev->mBusySession->mUserSessionCallback.onReady);
+ // Make sure we clear the sp first so the session destructor can
+ // only happen on handler thread (where we don't hold device/session lock)
+ dev->mBusySession.clear();
+ msg->post();
+ }
+ dev->mIdle = true;
+}
+
+void
+CameraDevice::ServiceCallback::onCaptureStarted(
+ const CaptureResultExtras& resultExtras,
+ int64_t timestamp) {
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return; // device has been closed
+ }
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->isClosed() || dev->mRemote == nullptr) {
+ return;
+ }
+
+ int sequenceId = resultExtras.requestId;
+ int64_t frameNumber = resultExtras.frameNumber;
+ int32_t burstId = resultExtras.burstId;
+
+ auto it = dev->mSequenceCallbackMap.find(sequenceId);
+ if (it != dev->mSequenceCallbackMap.end()) {
+ CallbackHolder cbh = (*it).second;
+ ACameraCaptureSession_captureCallback_start onStart = cbh.mCallbacks.onCaptureStarted;
+ sp<ACameraCaptureSession> session = cbh.mSession;
+ if ((size_t) burstId >= cbh.mRequests.size()) {
+ ALOGE("%s: Error: request index %d out of bound (size %zu)",
+ __FUNCTION__, burstId, cbh.mRequests.size());
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ }
+ sp<CaptureRequest> request = cbh.mRequests[burstId];
+ sp<AMessage> msg = new AMessage(kWhatCaptureStart, dev->mHandler);
+ msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) onStart);
+ msg->setObject(kCaptureRequestKey, request);
+ msg->setInt64(kTimeStampKey, timestamp);
+ msg->post();
+ }
+}
+
+void
+CameraDevice::ServiceCallback::onResultReceived(
+ const CameraMetadata& metadata,
+ const CaptureResultExtras& resultExtras) {
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return; // device has been closed
+ }
+ int sequenceId = resultExtras.requestId;
+ int64_t frameNumber = resultExtras.frameNumber;
+ int32_t burstId = resultExtras.burstId;
+ bool isPartialResult = (resultExtras.partialResultCount < dev->mPartialResultCount);
+
+ if (!isPartialResult) {
+ ALOGV("SeqId %d frame %" PRId64 " result arrive.", sequenceId, frameNumber);
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->mRemote == nullptr) {
+ return; // device has been disconnected
+ }
+
+ if (dev->isClosed()) {
+ if (!isPartialResult) {
+ dev->mFrameNumberTracker.updateTracker(frameNumber, /*isError*/false);
+ }
+ // early return to avoid callback sent to closed devices
+ return;
+ }
+
+ CameraMetadata metadataCopy = metadata;
+ // Copied from java implmentation. Why do we need this?
+ metadataCopy.update(ANDROID_LENS_INFO_SHADING_MAP_SIZE, dev->mShadingMapSize, /*data_count*/2);
+
+ auto it = dev->mSequenceCallbackMap.find(sequenceId);
+ if (it != dev->mSequenceCallbackMap.end()) {
+ CallbackHolder cbh = (*it).second;
+ ACameraCaptureSession_captureCallback_result onResult = isPartialResult ?
+ cbh.mCallbacks.onCaptureProgressed :
+ cbh.mCallbacks.onCaptureCompleted;
+ sp<ACameraCaptureSession> session = cbh.mSession;
+ if ((size_t) burstId >= cbh.mRequests.size()) {
+ ALOGE("%s: Error: request index %d out of bound (size %zu)",
+ __FUNCTION__, burstId, cbh.mRequests.size());
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ }
+ sp<CaptureRequest> request = cbh.mRequests[burstId];
+ sp<ACameraMetadata> result(new ACameraMetadata(
+ metadataCopy.release(), ACameraMetadata::ACM_RESULT));
+
+ sp<AMessage> msg = new AMessage(kWhatCaptureResult, dev->mHandler);
+ msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) onResult);
+ msg->setObject(kCaptureRequestKey, request);
+ msg->setObject(kCaptureResultKey, result);
+ msg->post();
+ }
+
+ if (!isPartialResult) {
+ dev->mFrameNumberTracker.updateTracker(frameNumber, /*isError*/false);
+ dev->checkAndFireSequenceCompleteLocked();
+ }
+}
+
+void
+CameraDevice::ServiceCallback::onPrepared(int) {
+ // Prepare not yet implemented in NDK
+ return;
+}
+
+} // namespace android
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
new file mode 100644
index 0000000..b73e621
--- /dev/null
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -0,0 +1,310 @@
+/*
+ * 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 _ACAMERA_DEVICE_H
+#define _ACAMERA_DEVICE_H
+
+#include <memory>
+#include <map>
+#include <set>
+#include <atomic>
+#include <utils/StrongPointer.h>
+#include <utils/Mutex.h>
+#include <utils/String8.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <camera/CaptureResult.h>
+#include <camera/camera2/ICameraDeviceCallbacks.h>
+#include <camera/camera2/ICameraDeviceUser.h>
+#include <camera/camera2/OutputConfiguration.h>
+#include <camera/camera2/CaptureRequest.h>
+
+#include <NdkCameraDevice.h>
+#include "ACameraMetadata.h"
+
+using namespace android;
+
+namespace android {
+
+// Wrap ACameraCaptureFailure so it can be ref-counter
+struct CameraCaptureFailure : public RefBase, public ACameraCaptureFailure {};
+
+class CameraDevice final : public RefBase {
+ public:
+ CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
+ std::unique_ptr<ACameraMetadata> chars,
+ ACameraDevice* wrapper);
+ ~CameraDevice();
+
+ inline const char* getId() const { return mCameraId.string(); }
+
+ camera_status_t createCaptureRequest(
+ ACameraDevice_request_template templateId,
+ ACaptureRequest** request) const;
+
+ camera_status_t createCaptureSession(
+ const ACaptureSessionOutputContainer* outputs,
+ const ACameraCaptureSession_stateCallbacks* callbacks,
+ /*out*/ACameraCaptureSession** session);
+
+ // Callbacks from camera service
+ class ServiceCallback : public BnCameraDeviceCallbacks {
+ public:
+ ServiceCallback(CameraDevice* device) : mDevice(device) {}
+ void onDeviceError(CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) override;
+ void onDeviceIdle() override;
+ void onCaptureStarted(const CaptureResultExtras& resultExtras,
+ int64_t timestamp) override;
+ void onResultReceived(const CameraMetadata& metadata,
+ const CaptureResultExtras& resultExtras) override;
+ void onPrepared(int streamId) override;
+ private:
+ const wp<CameraDevice> mDevice;
+ };
+ inline sp<ICameraDeviceCallbacks> getServiceCallback() { return mServiceCallback; };
+
+ // Camera device is only functional after remote being set
+ void setRemoteDevice(sp<ICameraDeviceUser> remote);
+
+ inline ACameraDevice* getWrapper() const { return mWrapper; };
+
+ private:
+ friend ACameraCaptureSession;
+ camera_status_t checkCameraClosedOrErrorLocked() const;
+
+ // device goes into fatal error state after this
+ void setCameraDeviceErrorLocked(camera_status_t error);
+
+ void disconnectLocked(); // disconnect from camera service
+
+ camera_status_t stopRepeatingLocked();
+
+ camera_status_t waitUntilIdleLocked();
+
+
+ camera_status_t captureLocked(sp<ACameraCaptureSession> session,
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId);
+
+ camera_status_t setRepeatingRequestsLocked(sp<ACameraCaptureSession> session,
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId);
+
+ camera_status_t submitRequestsLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*out*/int* captureSequenceId,
+ bool isRepeating);
+
+ static camera_status_t allocateCaptureRequest(
+ const ACaptureRequest* request, sp<CaptureRequest>& outReq);
+
+ static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req);
+ static void freeACaptureRequest(ACaptureRequest*);
+
+ // only For session to hold device lock
+ // Always grab device lock before grabbing session lock
+ void lockDeviceForSessionOps() const { mDeviceLock.lock(); };
+ void unlockDevice() const { mDeviceLock.unlock(); };
+
+ // For capture session to notify its end of life
+ void notifySessionEndOfLifeLocked(ACameraCaptureSession* session);
+
+ camera_status_t configureStreamsLocked(const ACaptureSessionOutputContainer* outputs);
+
+ static camera_status_t getIGBPfromSessionOutput(
+ const ACaptureSessionOutput& config, sp<IGraphicBufferProducer>& out);
+
+ static camera_status_t getSurfaceFromANativeWindow(
+ ANativeWindow* anw, sp<Surface>& out);
+
+ mutable Mutex mDeviceLock;
+ const String8 mCameraId; // Camera ID
+ const ACameraDevice_StateCallbacks mAppCallbacks; // Callback to app
+ const std::unique_ptr<ACameraMetadata> mChars; // Camera characteristics
+ const sp<ServiceCallback> mServiceCallback;
+ ACameraDevice* mWrapper;
+
+ // stream id -> OutputConfiguration map
+ std::map<int, OutputConfiguration> mConfiguredOutputs;
+
+ // TODO: maybe a bool will suffice for synchronous implementation?
+ std::atomic_bool mClosing;
+ inline bool isClosed() { return mClosing; }
+
+ bool mInError;
+ camera_status_t mError;
+ void onCaptureErrorLocked(
+ ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras);
+
+ bool mIdle;
+ // This will avoid a busy session being deleted before it's back to idle state
+ sp<ACameraCaptureSession> mBusySession;
+
+ sp<ICameraDeviceUser> mRemote;
+
+ // Looper thread to handle callback to app
+ sp<ALooper> mCbLooper;
+ // definition of handler and message
+ enum {
+ // Device state callbacks
+ kWhatOnDisconnected, // onDisconnected
+ kWhatOnError, // onError
+ // Session state callbacks
+ kWhatSessionStateCb, // onReady, onActive
+ // Capture callbacks
+ kWhatCaptureStart, // onCaptureStarted
+ kWhatCaptureResult, // onCaptureProgressed, onCaptureCompleted
+ kWhatCaptureFail, // onCaptureFailed
+ kWhatCaptureSeqEnd, // onCaptureSequenceCompleted
+ kWhatCaptureSeqAbort // onCaptureSequenceAborted
+ };
+ static const char* kContextKey;
+ static const char* kDeviceKey;
+ static const char* kErrorCodeKey;
+ static const char* kCallbackFpKey;
+ static const char* kSessionSpKey;
+ static const char* kCaptureRequestKey;
+ static const char* kTimeStampKey;
+ static const char* kCaptureResultKey;
+ static const char* kCaptureFailureKey;
+ static const char* kSequenceIdKey;
+ static const char* kFrameNumberKey;
+ class CallbackHandler : public AHandler {
+ public:
+ CallbackHandler() {}
+ void onMessageReceived(const sp<AMessage> &msg) override;
+ };
+ sp<CallbackHandler> mHandler;
+
+ /***********************************
+ * Capture session related members *
+ ***********************************/
+ // The current active session
+ ACameraCaptureSession* mCurrentSession = nullptr;
+
+ int mNextSessionId = 0;
+ // TODO: might need another looper/handler to handle callbacks from service
+
+ static const int REQUEST_ID_NONE = -1;
+ int mRepeatingSequenceId = REQUEST_ID_NONE;
+
+ // sequence id -> last frame number map
+ std::map<int, int64_t> mSequenceLastFrameNumberMap;
+
+ struct CallbackHolder {
+ CallbackHolder(sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacks* cbs);
+
+ static ACameraCaptureSession_captureCallbacks fillCb(
+ ACameraCaptureSession_captureCallbacks* cbs) {
+ if (cbs != nullptr) {
+ return *cbs;
+ }
+ return { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
+ }
+
+ sp<ACameraCaptureSession> mSession;
+ Vector<sp<CaptureRequest> > mRequests;
+ const bool mIsRepeating;
+ ACameraCaptureSession_captureCallbacks mCallbacks;
+ };
+ // sequence id -> callbacks map
+ std::map<int, CallbackHolder> mSequenceCallbackMap;
+
+ static const int64_t NO_FRAMES_CAPTURED = -1;
+ class FrameNumberTracker {
+ public:
+ // TODO: Called in onResultReceived and onCaptureErrorLocked
+ void updateTracker(int64_t frameNumber, bool isError);
+ inline int64_t getCompletedFrameNumber() { return mCompletedFrameNumber; }
+ private:
+ void update();
+ void updateCompletedFrameNumber(int64_t frameNumber);
+
+ int64_t mCompletedFrameNumber = NO_FRAMES_CAPTURED;
+ List<int64_t> mSkippedFrameNumbers;
+ std::set<int64_t> mFutureErrorSet;
+ };
+ FrameNumberTracker mFrameNumberTracker;
+
+ void checkRepeatingSequenceCompleteLocked(const int sequenceId, const int64_t lastFrameNumber);
+ void checkAndFireSequenceCompleteLocked();
+
+ // Misc variables
+ int32_t mShadingMapSize[2]; // const after constructor
+ int32_t mPartialResultCount; // const after constructor
+
+};
+
+} // namespace android;
+
+/**
+ * ACameraDevice opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraDevice {
+ ACameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
+ std::unique_ptr<ACameraMetadata> chars) :
+ mDevice(new CameraDevice(id, cb, std::move(chars), this)) {}
+
+ ~ACameraDevice() {};
+
+ /*******************
+ * NDK public APIs *
+ *******************/
+ inline const char* getId() const { return mDevice->getId(); }
+
+ camera_status_t createCaptureRequest(
+ ACameraDevice_request_template templateId,
+ ACaptureRequest** request) const {
+ return mDevice->createCaptureRequest(templateId, request);
+ }
+
+ camera_status_t createCaptureSession(
+ const ACaptureSessionOutputContainer* outputs,
+ const ACameraCaptureSession_stateCallbacks* callbacks,
+ /*out*/ACameraCaptureSession** session) {
+ return mDevice->createCaptureSession(outputs, callbacks, session);
+ }
+
+ /***********************
+ * Device interal APIs *
+ ***********************/
+ inline sp<ICameraDeviceCallbacks> getServiceCallback() {
+ return mDevice->getServiceCallback();
+ };
+
+ // Camera device is only functional after remote being set
+ inline void setRemoteDevice(sp<ICameraDeviceUser> remote) {
+ mDevice->setRemoteDevice(remote);
+ }
+
+ private:
+ sp<CameraDevice> mDevice;
+};
+
+#endif // _ACAMERA_DEVICE_H
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
new file mode 100644
index 0000000..ed5c3ba
--- /dev/null
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -0,0 +1,479 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "ACameraManager"
+
+#include <memory>
+#include "ACameraManager.h"
+#include "ACameraMetadata.h"
+#include "ACameraDevice.h"
+#include <utils/Vector.h>
+#include <stdlib.h>
+#include <camera/VendorTagDescriptor.h>
+
+using namespace android;
+
+//constants shared between ACameraManager and CameraManagerGlobal
+namespace {
+ const int kMaxCameraIdLen = 32;
+}
+
+namespace android {
+// Static member definitions
+const char* CameraManagerGlobal::kCameraIdKey = "CameraId";
+const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
+const char* CameraManagerGlobal::kContextKey = "CallbackContext";
+Mutex CameraManagerGlobal::sLock;
+CameraManagerGlobal* CameraManagerGlobal::sInstance = nullptr;
+
+CameraManagerGlobal&
+CameraManagerGlobal::getInstance() {
+ Mutex::Autolock _l(sLock);
+ CameraManagerGlobal* instance = sInstance;
+ if (instance == nullptr) {
+ instance = new CameraManagerGlobal();
+ sInstance = instance;
+ }
+ return *instance;
+}
+
+CameraManagerGlobal::~CameraManagerGlobal() {
+ // clear sInstance so next getInstance call knows to create a new one
+ Mutex::Autolock _sl(sLock);
+ sInstance = nullptr;
+ Mutex::Autolock _l(mLock);
+ if (mCameraService != nullptr) {
+ IInterface::asBinder(mCameraService)->unlinkToDeath(mDeathNotifier);
+ mCameraService->removeListener(mCameraServiceListener);
+ }
+ mDeathNotifier.clear();
+ if (mCbLooper != nullptr) {
+ mCbLooper->unregisterHandler(mHandler->id());
+ mCbLooper->stop();
+ }
+ mCbLooper.clear();
+ mHandler.clear();
+ mCameraServiceListener.clear();
+ mCameraService.clear();
+}
+
+sp<ICameraService> CameraManagerGlobal::getCameraService() {
+ Mutex::Autolock _l(mLock);
+ if (mCameraService.get() == nullptr) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16(kCameraServiceName));
+ if (binder != nullptr) {
+ break;
+ }
+ ALOGW("CameraService not published, waiting...");
+ usleep(kCameraServicePollDelay);
+ } while(true);
+ if (mDeathNotifier == nullptr) {
+ mDeathNotifier = new DeathNotifier(this);
+ }
+ binder->linkToDeath(mDeathNotifier);
+ mCameraService = interface_cast<ICameraService>(binder);
+
+ // Setup looper thread to perfrom availiability callbacks
+ if (mCbLooper == nullptr) {
+ mCbLooper = new ALooper;
+ mCbLooper->setName("C2N-mgr-looper");
+ status_t ret = mCbLooper->start(
+ /*runOnCallingThread*/false,
+ /*canCallJava*/ true,
+ PRIORITY_DEFAULT);
+ if (mHandler == nullptr) {
+ mHandler = new CallbackHandler();
+ }
+ mCbLooper->registerHandler(mHandler);
+ }
+
+ // register ICameraServiceListener
+ if (mCameraServiceListener == nullptr) {
+ mCameraServiceListener = new CameraServiceListener(this);
+ }
+ mCameraService->addListener(mCameraServiceListener);
+
+ // setup vendor tags
+ sp<VendorTagDescriptor> desc;
+ status_t ret = mCameraService->getCameraVendorTagDescriptor(/*out*/desc);
+
+ if (ret == OK) {
+ ret = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+ if (ret != OK) {
+ ALOGE("%s: Failed to set vendor tag descriptors, received error %s (%d)",
+ __FUNCTION__, strerror(-ret), ret);
+ }
+ } else if (ret == -EOPNOTSUPP) {
+ ALOGW("%s: Camera HAL too old; does not support vendor tags",
+ __FUNCTION__);
+ VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+ } else {
+ ALOGE("%s: Failed to get vendor tag descriptors, received error %s (%d)",
+ __FUNCTION__, strerror(-ret), ret);
+ }
+ }
+ ALOGE_IF(mCameraService == nullptr, "no CameraService!?");
+ return mCameraService;
+}
+
+void CameraManagerGlobal::DeathNotifier::binderDied(const wp<IBinder>&)
+{
+ ALOGE("Camera service binderDied!");
+ sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ if (cm != nullptr) {
+ AutoMutex lock(cm->mLock);
+ for (auto pair : cm->mDeviceStatusMap) {
+ int32_t cameraId = pair.first;
+ cm->onStatusChangedLocked(
+ ICameraServiceListener::STATUS_NOT_PRESENT, cameraId);
+ }
+ cm->mCameraService.clear();
+ // TODO: consider adding re-connect call here?
+ }
+}
+
+void CameraManagerGlobal::registerAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ auto pair = mCallbacks.insert(cb);
+ // Send initial callbacks if callback is newly registered
+ if (pair.second) {
+ for (auto pair : mDeviceStatusMap) {
+ int32_t cameraId = pair.first;
+ Status status = pair.second;
+
+ sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+ ACameraManager_AvailabilityCallback cb = isStatusAvailable(status) ?
+ callback->onCameraAvailable : callback->onCameraUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cb);
+ msg->setPointer(kContextKey, callback->context);
+ msg->setInt32(kCameraIdKey, cameraId);
+ msg->post();
+ }
+ }
+}
+
+void CameraManagerGlobal::unregisterAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ mCallbacks.erase(cb);
+}
+
+bool CameraManagerGlobal::validStatus(Status status) {
+ switch (status) {
+ case ICameraServiceListener::STATUS_NOT_PRESENT:
+ case ICameraServiceListener::STATUS_PRESENT:
+ case ICameraServiceListener::STATUS_ENUMERATING:
+ case ICameraServiceListener::STATUS_NOT_AVAILABLE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool CameraManagerGlobal::isStatusAvailable(Status status) {
+ switch (status) {
+ case ICameraServiceListener::STATUS_PRESENT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void CameraManagerGlobal::CallbackHandler::sendSingleCallback(
+ int32_t cameraId, void* context,
+ ACameraManager_AvailabilityCallback cb) const {
+ char cameraIdStr[kMaxCameraIdLen];
+ snprintf(cameraIdStr, sizeof(cameraIdStr), "%d", cameraId);
+ (*cb)(context, cameraIdStr);
+}
+
+void CameraManagerGlobal::CallbackHandler::onMessageReceived(
+ const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatSendSingleCallback:
+ {
+ ACameraManager_AvailabilityCallback cb;
+ void* context;
+ int32_t cameraId;
+ bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
+ if (!found) {
+ ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
+ return;
+ }
+ found = msg->findPointer(kContextKey, &context);
+ if (!found) {
+ ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+ return;
+ }
+ found = msg->findInt32(kCameraIdKey, &cameraId);
+ if (!found) {
+ ALOGE("%s: Cannot find camera ID!", __FUNCTION__);
+ return;
+ }
+ sendSingleCallback(cameraId, context, cb);
+ break;
+ }
+ default:
+ ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
+ break;
+ }
+}
+
+void CameraManagerGlobal::CameraServiceListener::onStatusChanged(
+ Status status, int32_t cameraId) {
+ sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ if (cm == nullptr) {
+ ALOGE("Cannot deliver status change. Global camera manager died");
+ return;
+ }
+ cm->onStatusChanged(status, cameraId);
+}
+
+void CameraManagerGlobal::onStatusChanged(
+ Status status, int32_t cameraId) {
+ Mutex::Autolock _l(mLock);
+ onStatusChangedLocked(status, cameraId);
+}
+
+void CameraManagerGlobal::onStatusChangedLocked(
+ Status status, int32_t cameraId) {
+ if (!validStatus(status)) {
+ ALOGE("%s: Invalid status %d", __FUNCTION__, status);
+ return;
+ }
+
+ bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
+ Status oldStatus = firstStatus ?
+ status : // first status
+ mDeviceStatusMap[cameraId];
+
+ if (!firstStatus &&
+ isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
+ // No status update. No need to send callback
+ return;
+ }
+
+ // Iterate through all registered callbacks
+ mDeviceStatusMap[cameraId] = status;
+ for (auto cb : mCallbacks) {
+ sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+ ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
+ cb.mAvailable : cb.mUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cbFp);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->setInt32(kCameraIdKey, cameraId);
+ msg->post();
+ }
+}
+
+} // namespace android
+
+/**
+ * ACameraManger Implementation
+ */
+camera_status_t
+ACameraManager::getOrCreateCameraIdListLocked(ACameraIdList** cameraIdList) {
+ if (mCachedCameraIdList.numCameras == kCameraIdListNotInit) {
+ int numCameras = 0;
+ Vector<char *> cameraIds;
+ sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ if (cs == nullptr) {
+ ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ // Get number of cameras
+ int numAllCameras = cs->getNumberOfCameras(ICameraService::CAMERA_TYPE_ALL);
+ // Filter API2 compatible cameras and push to cameraIds
+ for (int i = 0; i < numAllCameras; i++) {
+ // TODO: Only suppot HALs that supports API2 directly now
+ status_t camera2Support = cs->supportsCameraApi(i, ICameraService::API_VERSION_2);
+ char buf[kMaxCameraIdLen];
+ if (camera2Support == OK) {
+ numCameras++;
+ mCameraIds.insert(i);
+ snprintf(buf, sizeof(buf), "%d", i);
+ size_t cameraIdSize = strlen(buf) + 1;
+ char *cameraId = new char[cameraIdSize];
+ if (!cameraId) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ strlcpy(cameraId, buf, cameraIdSize);
+ cameraIds.push(cameraId);
+ }
+ }
+ mCachedCameraIdList.numCameras = numCameras;
+ mCachedCameraIdList.cameraIds = new const char*[numCameras];
+ if (!mCachedCameraIdList.cameraIds) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ for (int i = 0; i < numCameras; i++) {
+ mCachedCameraIdList.cameraIds[i] = cameraIds[i];
+ }
+ }
+ *cameraIdList = &mCachedCameraIdList;
+ return ACAMERA_OK;
+}
+
+camera_status_t
+ACameraManager::getCameraIdList(ACameraIdList** cameraIdList) {
+ Mutex::Autolock _l(mLock);
+ ACameraIdList* cachedList;
+ camera_status_t ret = getOrCreateCameraIdListLocked(&cachedList);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Get camera ID list failed! err: %d", ret);
+ return ret;
+ }
+
+ int numCameras = cachedList->numCameras;
+ ACameraIdList *out = new ACameraIdList;
+ if (!out) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ out->numCameras = numCameras;
+ out->cameraIds = new const char*[numCameras];
+ if (!out->cameraIds) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ for (int i = 0; i < numCameras; i++) {
+ const char* src = cachedList->cameraIds[i];
+ size_t dstSize = strlen(src) + 1;
+ char* dst = new char[dstSize];
+ if (!dst) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ strlcpy(dst, src, dstSize);
+ out->cameraIds[i] = dst;
+ }
+ *cameraIdList = out;
+ return ACAMERA_OK;
+}
+
+void
+ACameraManager::deleteCameraIdList(ACameraIdList* cameraIdList) {
+ if (cameraIdList != nullptr) {
+ if (cameraIdList->cameraIds != nullptr) {
+ for (int i = 0; i < cameraIdList->numCameras; i ++) {
+ delete[] cameraIdList->cameraIds[i];
+ }
+ delete[] cameraIdList->cameraIds;
+ }
+ delete cameraIdList;
+ }
+}
+
+camera_status_t ACameraManager::getCameraCharacteristics(
+ const char *cameraIdStr, ACameraMetadata **characteristics) {
+ Mutex::Autolock _l(mLock);
+ ACameraIdList* cachedList;
+ // Make sure mCameraIds is initialized
+ camera_status_t ret = getOrCreateCameraIdListLocked(&cachedList);
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: Get camera ID list failed! err: %d", __FUNCTION__, ret);
+ return ret;
+ }
+ int cameraId = atoi(cameraIdStr);
+ if (mCameraIds.count(cameraId) == 0) {
+ ALOGE("%s: Camera ID %s does not exist!", __FUNCTION__, cameraIdStr);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ if (cs == nullptr) {
+ ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ CameraMetadata rawMetadata;
+ status_t serviceRet = cs->getCameraCharacteristics(cameraId, &rawMetadata);
+ if (serviceRet != OK) {
+ ALOGE("Get camera characteristics from camera service failed! Err %d", ret);
+ return ACAMERA_ERROR_UNKNOWN; // should not reach here
+ }
+
+ *characteristics = new ACameraMetadata(
+ rawMetadata.release(), ACameraMetadata::ACM_CHARACTERISTICS);
+ return ACAMERA_OK;
+}
+
+camera_status_t
+ACameraManager::openCamera(
+ const char* cameraId,
+ ACameraDevice_StateCallbacks* callback,
+ /*out*/ACameraDevice** outDevice) {
+ ACameraMetadata* rawChars;
+ camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars);
+ Mutex::Autolock _l(mLock);
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: cannot get camera characteristics for camera %s. err %d",
+ __FUNCTION__, cameraId, ret);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ std::unique_ptr<ACameraMetadata> chars(rawChars);
+ rawChars = nullptr;
+
+ ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(chars));
+
+ sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ if (cs == nullptr) {
+ ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+
+ int id = atoi(cameraId);
+ sp<ICameraDeviceCallbacks> callbacks = device->getServiceCallback();
+ sp<ICameraDeviceUser> deviceRemote;
+ // No way to get package name from native.
+ // Send a zero length package name and let camera service figure it out from UID
+ status_t serviceRet = cs->connectDevice(
+ callbacks, id, String16(""),
+ ICameraService::USE_CALLING_UID, /*out*/deviceRemote);
+
+ if (serviceRet != OK) {
+ ALOGE("%s: connect camera device failed! err %d", __FUNCTION__, serviceRet);
+ // TODO: generate better error message here
+ delete device;
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ if (deviceRemote == nullptr) {
+ ALOGE("%s: connect camera device failed! remote device is null", __FUNCTION__);
+ delete device;
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ device->setRemoteDevice(deviceRemote);
+ *outDevice = device;
+ return ACAMERA_OK;
+}
+
+ACameraManager::~ACameraManager() {
+ Mutex::Autolock _l(mLock);
+ if (mCachedCameraIdList.numCameras != kCameraIdListNotInit) {
+ for (int i = 0; i < mCachedCameraIdList.numCameras; i++) {
+ delete[] mCachedCameraIdList.cameraIds[i];
+ }
+ delete[] mCachedCameraIdList.cameraIds;
+ }
+}
+
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
new file mode 100644
index 0000000..b68685d
--- /dev/null
+++ b/camera/ndk/impl/ACameraManager.h
@@ -0,0 +1,184 @@
+/*
+ * 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 _ACAMERA_MANAGER_H
+#define _ACAMERA_MANAGER_H
+
+#include "NdkCameraManager.h"
+
+#include <camera/CameraMetadata.h>
+#include <camera/ICameraService.h>
+#include <camera/ICameraServiceListener.h>
+#include <binder/IServiceManager.h>
+#include <utils/StrongPointer.h>
+#include <utils/Mutex.h>
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <set>
+#include <map>
+
+using namespace android;
+
+namespace android {
+
+/**
+ * Per-process singleton instance of CameraManger. Shared by all ACameraManager
+ * instances. Created when first ACameraManager is created and destroyed when
+ * all ACameraManager instances are deleted.
+ *
+ * TODO: maybe CameraManagerGlobal is better sutied in libcameraclient?
+ */
+class CameraManagerGlobal final : public RefBase {
+ public:
+ static CameraManagerGlobal& getInstance();
+ sp<ICameraService> getCameraService();
+
+ void registerAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks *callback);
+ void unregisterAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks *callback);
+
+ private:
+ sp<ICameraService> mCameraService;
+ const int kCameraServicePollDelay = 500000; // 0.5s
+ const char* kCameraServiceName = "media.camera";
+ Mutex mLock;
+
+ class DeathNotifier : public IBinder::DeathRecipient {
+ public:
+ DeathNotifier(CameraManagerGlobal* cm) : mCameraManager(cm) {}
+ protected:
+ // IBinder::DeathRecipient implementation
+ virtual void binderDied(const wp<IBinder>& who);
+ private:
+ const wp<CameraManagerGlobal> mCameraManager;
+ };
+ sp<DeathNotifier> mDeathNotifier;
+
+ class CameraServiceListener final : public BnCameraServiceListener {
+ public:
+ CameraServiceListener(CameraManagerGlobal* cm) : mCameraManager(cm) {}
+ virtual void onStatusChanged(Status status, int32_t cameraId);
+
+ // Torch API not implemented yet
+ virtual void onTorchStatusChanged(TorchStatus, const String16&) {};
+ private:
+ const wp<CameraManagerGlobal> mCameraManager;
+ };
+ sp<CameraServiceListener> mCameraServiceListener;
+
+ // Wrapper of ACameraManager_AvailabilityCallbacks so we can store it in std::set
+ struct Callback {
+ Callback(const ACameraManager_AvailabilityCallbacks *callback) :
+ mAvailable(callback->onCameraAvailable),
+ mUnavailable(callback->onCameraUnavailable),
+ mContext(callback->context) {}
+
+ bool operator == (const Callback& other) const {
+ return (mAvailable == other.mAvailable &&
+ mUnavailable == other.mUnavailable &&
+ mContext == other.mContext);
+ }
+ bool operator != (const Callback& other) const {
+ return !(*this == other);
+ }
+ bool operator < (const Callback& other) const {
+ if (*this == other) return false;
+ if (mContext != other.mContext) return mContext < other.mContext;
+ if (mAvailable != other.mAvailable) return mAvailable < other.mAvailable;
+ return mUnavailable < other.mUnavailable;
+ }
+ bool operator > (const Callback& other) const {
+ return (*this != other && !(*this < other));
+ }
+ ACameraManager_AvailabilityCallback mAvailable;
+ ACameraManager_AvailabilityCallback mUnavailable;
+ void* mContext;
+ };
+ std::set<Callback> mCallbacks;
+
+ // definition of handler and message
+ enum {
+ kWhatSendSingleCallback
+ };
+ static const char* kCameraIdKey;
+ static const char* kCallbackFpKey;
+ static const char* kContextKey;
+ class CallbackHandler : public AHandler {
+ public:
+ CallbackHandler() {}
+ void onMessageReceived(const sp<AMessage> &msg) override;
+ private:
+ inline void sendSingleCallback(
+ int32_t cameraId, void* context,
+ ACameraManager_AvailabilityCallback cb) const;
+ };
+ sp<CallbackHandler> mHandler;
+ sp<ALooper> mCbLooper; // Looper thread where callbacks actually happen on
+
+ typedef ICameraServiceListener::Status Status;
+ void onStatusChanged(Status status, int32_t cameraId);
+ void onStatusChangedLocked(Status status, int32_t cameraId);
+ // Utils for status
+ static bool validStatus(Status status);
+ static bool isStatusAvailable(Status status);
+
+ // Map camera_id -> status
+ std::map<int32_t, Status> mDeviceStatusMap;
+
+ // For the singleton instance
+ static Mutex sLock;
+ static CameraManagerGlobal* sInstance;
+ CameraManagerGlobal() {};
+ ~CameraManagerGlobal();
+};
+
+} // namespace android;
+
+/**
+ * ACameraManager opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraManager {
+ ACameraManager() :
+ mCachedCameraIdList({kCameraIdListNotInit, nullptr}),
+ mGlobalManager(&(CameraManagerGlobal::getInstance())) {}
+ ~ACameraManager();
+ camera_status_t getCameraIdList(ACameraIdList** cameraIdList);
+ static void deleteCameraIdList(ACameraIdList* cameraIdList);
+
+ camera_status_t getCameraCharacteristics(
+ const char *cameraId, ACameraMetadata **characteristics);
+ camera_status_t openCamera(const char* cameraId,
+ ACameraDevice_StateCallbacks* callback,
+ /*out*/ACameraDevice** device);
+
+ private:
+ camera_status_t getOrCreateCameraIdListLocked(ACameraIdList** cameraIdList);
+
+ enum {
+ kCameraIdListNotInit = -1
+ };
+ Mutex mLock;
+ std::set<int> mCameraIds; // Init by getOrCreateCameraIdListLocked
+ ACameraIdList mCachedCameraIdList; // Init by getOrCreateCameraIdListLocked
+ sp<CameraManagerGlobal> mGlobalManager;
+};
+
+#endif //_ACAMERA_MANAGER_H
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
new file mode 100644
index 0000000..fbc8d19
--- /dev/null
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -0,0 +1,291 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "ACameraMetadata"
+
+#include "ACameraMetadata.h"
+#include <utils/Vector.h>
+#include <system/graphics.h>
+#include "NdkImage.h"
+
+using namespace android;
+
+/**
+ * ACameraMetadata Implementation
+ */
+ACameraMetadata::ACameraMetadata(camera_metadata_t* buffer, ACAMERA_METADATA_TYPE type) :
+ mData(buffer), mType(type) {
+ if (mType == ACM_CHARACTERISTICS) {
+ filterUnsupportedFeatures();
+ filterStreamConfigurations();
+ }
+ // TODO: filter request/result keys
+}
+
+bool
+ACameraMetadata::isNdkSupportedCapability(int32_t capability) {
+ switch (capability) {
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT:
+ return true;
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO:
+ return false;
+ default:
+ // Newly defined capabilities will be unsupported by default (blacklist)
+ // TODO: Should we do whitelist or blacklist here?
+ ALOGE("%s: Unknonwn capability %d", __FUNCTION__, capability);
+ return false;
+ }
+}
+
+void
+ACameraMetadata::filterUnsupportedFeatures() {
+ // Hide unsupported capabilities (reprocessing)
+ camera_metadata_entry entry = mData.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ if (entry.count == 0 || entry.type != TYPE_BYTE) {
+ ALOGE("%s: malformed available capability key! count %zu, type %d",
+ __FUNCTION__, entry.count, entry.type);
+ return;
+ }
+
+ Vector<uint8_t> capabilities;
+ capabilities.setCapacity(entry.count);
+ for (size_t i = 0; i < entry.count; i++) {
+ uint8_t capability = entry.data.u8[i];
+ if (isNdkSupportedCapability(capability)) {
+ capabilities.push(capability);
+ }
+ }
+ mData.update(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, capabilities);
+}
+
+
+void
+ACameraMetadata::filterStreamConfigurations() {
+ const int STREAM_CONFIGURATION_SIZE = 4;
+ const int STREAM_FORMAT_OFFSET = 0;
+ const int STREAM_WIDTH_OFFSET = 1;
+ const int STREAM_HEIGHT_OFFSET = 2;
+ const int STREAM_IS_INPUT_OFFSET = 3;
+ camera_metadata_entry entry = mData.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ if (entry.count == 0 || entry.count % 4 || entry.type != TYPE_INT32) {
+ ALOGE("%s: malformed available stream configuration key! count %zu, type %d",
+ __FUNCTION__, entry.count, entry.type);
+ return;
+ }
+
+ Vector<int32_t> filteredStreamConfigs;
+ filteredStreamConfigs.setCapacity(entry.count);
+
+ for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+ int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+ int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+ int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+ int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+ if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
+ // Hide input streams
+ continue;
+ }
+ // Translate HAL formats to NDK format
+ if (format == HAL_PIXEL_FORMAT_BLOB) {
+ format = AIMAGE_FORMAT_JPEG;
+ }
+ filteredStreamConfigs.push_back(format);
+ filteredStreamConfigs.push_back(width);
+ filteredStreamConfigs.push_back(height);
+ filteredStreamConfigs.push_back(isInput);
+ }
+
+ mData.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, filteredStreamConfigs);
+
+ entry = mData.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
+ Vector<int32_t> filteredDepthStreamConfigs;
+ filteredDepthStreamConfigs.setCapacity(entry.count);
+
+ for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+ int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+ int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+ int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+ int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+ if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
+ // Hide input streams
+ continue;
+ }
+ // Translate HAL formats to NDK format
+ if (format == HAL_PIXEL_FORMAT_BLOB) {
+ format = AIMAGE_FORMAT_DEPTH_POINT_CLOUD;
+ } else if (format == HAL_PIXEL_FORMAT_Y16) {
+ format = AIMAGE_FORMAT_DEPTH16;
+ }
+
+ filteredDepthStreamConfigs.push_back(format);
+ filteredDepthStreamConfigs.push_back(width);
+ filteredDepthStreamConfigs.push_back(height);
+ filteredDepthStreamConfigs.push_back(isInput);
+ }
+ mData.update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, filteredDepthStreamConfigs);
+}
+
+bool
+ACameraMetadata::isVendorTag(const uint32_t tag) {
+ uint32_t tag_section = tag >> 16;
+ if (tag_section >= VENDOR_SECTION) {
+ return true;
+ }
+ return false;
+}
+
+camera_status_t
+ACameraMetadata::getConstEntry(uint32_t tag, ACameraMetadata_const_entry* entry) const {
+ if (entry == nullptr) {
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ camera_metadata_ro_entry rawEntry = mData.find(tag);
+ if (rawEntry.count == 0) {
+ ALOGE("%s: cannot find metadata tag %d", __FUNCTION__, tag);
+ return ACAMERA_ERROR_METADATA_NOT_FOUND;
+ }
+ entry->tag = tag;
+ entry->type = rawEntry.type;
+ entry->count = rawEntry.count;
+ entry->data.u8 = rawEntry.data.u8;
+ return ACAMERA_OK;
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const uint8_t* data) {
+ return updateImpl<uint8_t>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const int32_t* data) {
+ return updateImpl<int32_t>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const float* data) {
+ return updateImpl<float>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const double* data) {
+ return updateImpl<double>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const int64_t* data) {
+ return updateImpl<int64_t>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const ACameraMetadata_rational* data) {
+ return updateImpl<camera_metadata_rational_t>(tag, count, data);
+}
+
+
+// TODO: some of key below should be hidden from user
+// ex: ACAMERA_REQUEST_ID and ACAMERA_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
+/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+ * The key entries below this point are generated from metadata
+ * definitions in /system/media/camera/docs. Do not modify by hand or
+ * modify the comment blocks at the start or end.
+ *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
+
+bool
+ACameraMetadata::isCaptureRequestTag(const uint32_t tag) {
+ // Skip check for vendor keys
+ if (isVendorTag(tag)) {
+ return true;
+ }
+
+ switch (tag) {
+ case ACAMERA_COLOR_CORRECTION_MODE:
+ case ACAMERA_COLOR_CORRECTION_TRANSFORM:
+ case ACAMERA_COLOR_CORRECTION_GAINS:
+ case ACAMERA_COLOR_CORRECTION_ABERRATION_MODE:
+ case ACAMERA_CONTROL_AE_ANTIBANDING_MODE:
+ case ACAMERA_CONTROL_AE_EXPOSURE_COMPENSATION:
+ case ACAMERA_CONTROL_AE_LOCK:
+ case ACAMERA_CONTROL_AE_MODE:
+ case ACAMERA_CONTROL_AE_REGIONS:
+ case ACAMERA_CONTROL_AE_TARGET_FPS_RANGE:
+ case ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER:
+ case ACAMERA_CONTROL_AF_MODE:
+ case ACAMERA_CONTROL_AF_REGIONS:
+ case ACAMERA_CONTROL_AF_TRIGGER:
+ case ACAMERA_CONTROL_AWB_LOCK:
+ case ACAMERA_CONTROL_AWB_MODE:
+ case ACAMERA_CONTROL_AWB_REGIONS:
+ case ACAMERA_CONTROL_CAPTURE_INTENT:
+ case ACAMERA_CONTROL_EFFECT_MODE:
+ case ACAMERA_CONTROL_MODE:
+ case ACAMERA_CONTROL_SCENE_MODE:
+ case ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE:
+ case ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST:
+ case ACAMERA_EDGE_MODE:
+ case ACAMERA_FLASH_MODE:
+ case ACAMERA_HOT_PIXEL_MODE:
+ case ACAMERA_JPEG_GPS_COORDINATES:
+ case ACAMERA_JPEG_GPS_PROCESSING_METHOD:
+ case ACAMERA_JPEG_GPS_TIMESTAMP:
+ case ACAMERA_JPEG_ORIENTATION:
+ case ACAMERA_JPEG_QUALITY:
+ case ACAMERA_JPEG_THUMBNAIL_QUALITY:
+ case ACAMERA_JPEG_THUMBNAIL_SIZE:
+ case ACAMERA_LENS_APERTURE:
+ case ACAMERA_LENS_FILTER_DENSITY:
+ case ACAMERA_LENS_FOCAL_LENGTH:
+ case ACAMERA_LENS_FOCUS_DISTANCE:
+ case ACAMERA_LENS_OPTICAL_STABILIZATION_MODE:
+ case ACAMERA_NOISE_REDUCTION_MODE:
+ case ACAMERA_REQUEST_ID:
+ case ACAMERA_SCALER_CROP_REGION:
+ case ACAMERA_SENSOR_EXPOSURE_TIME:
+ case ACAMERA_SENSOR_FRAME_DURATION:
+ case ACAMERA_SENSOR_SENSITIVITY:
+ case ACAMERA_SENSOR_TEST_PATTERN_DATA:
+ case ACAMERA_SENSOR_TEST_PATTERN_MODE:
+ case ACAMERA_SHADING_MODE:
+ case ACAMERA_STATISTICS_FACE_DETECT_MODE:
+ case ACAMERA_STATISTICS_HOT_PIXEL_MAP_MODE:
+ case ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE:
+ case ACAMERA_TONEMAP_CURVE_BLUE:
+ case ACAMERA_TONEMAP_CURVE_GREEN:
+ case ACAMERA_TONEMAP_CURVE_RED:
+ case ACAMERA_TONEMAP_MODE:
+ case ACAMERA_TONEMAP_GAMMA:
+ case ACAMERA_TONEMAP_PRESET_CURVE:
+ case ACAMERA_LED_TRANSMIT:
+ case ACAMERA_BLACK_LEVEL_LOCK:
+ case ACAMERA_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+ * End generated code
+ *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/camera/ndk/impl/ACameraMetadata.h b/camera/ndk/impl/ACameraMetadata.h
new file mode 100644
index 0000000..442e1dd
--- /dev/null
+++ b/camera/ndk/impl/ACameraMetadata.h
@@ -0,0 +1,85 @@
+/*
+ * 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 _ACAMERA_METADATA_H
+#define _ACAMERA_METADATA_H
+
+#include <sys/types.h>
+#include <utils/RefBase.h>
+#include <camera/CameraMetadata.h>
+
+#include "NdkCameraMetadata.h"
+
+using namespace android;
+
+/**
+ * ACameraMetadata opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraMetadata : public RefBase {
+ public:
+ typedef enum {
+ ACM_CHARACTERISTICS, // Read only
+ ACM_REQUEST, // Read/Write
+ ACM_RESULT, // Read only
+ } ACAMERA_METADATA_TYPE;
+
+ // Takes ownership of pass-in buffer
+ ACameraMetadata(camera_metadata_t *buffer, ACAMERA_METADATA_TYPE type);
+ // Clone
+ ACameraMetadata(const ACameraMetadata& other) :
+ mData(other.mData), mType(other.mType) {};
+
+ camera_status_t getConstEntry(uint32_t tag, ACameraMetadata_const_entry* entry) const;
+
+ camera_status_t update(uint32_t tag, uint32_t count, const uint8_t* data);
+ camera_status_t update(uint32_t tag, uint32_t count, const int32_t* data);
+ camera_status_t update(uint32_t tag, uint32_t count, const float* data);
+ camera_status_t update(uint32_t tag, uint32_t count, const double* data);
+ camera_status_t update(uint32_t tag, uint32_t count, const int64_t* data);
+ camera_status_t update(uint32_t tag, uint32_t count, const ACameraMetadata_rational* data);
+
+ bool isNdkSupportedCapability(const int32_t capability);
+ inline bool isVendorTag(const uint32_t tag);
+ bool isCaptureRequestTag(const uint32_t tag);
+ void filterUnsupportedFeatures(); // Hide features not yet supported by NDK
+ void filterStreamConfigurations(); // Hide input streams, translate hal format to NDK formats
+
+ template<typename INTERNAL_T, typename NDK_T>
+ camera_status_t updateImpl(uint32_t tag, uint32_t count, const NDK_T* data) {
+ if (mType != ACM_REQUEST) {
+ ALOGE("Error: Write to metadata is only allowed for capture request!");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if (!isCaptureRequestTag(tag)) {
+ ALOGE("Error: tag %d is not writable!", tag);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ // Here we have to use reinterpret_cast because the NDK data type is
+ // exact copy of internal data type but they do not inherit from each other
+ status_t ret = mData.update(tag, reinterpret_cast<const INTERNAL_T*>(data), count);
+ if (ret == OK) {
+ return ACAMERA_OK;
+ } else {
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ CameraMetadata mData;
+ const ACAMERA_METADATA_TYPE mType;
+};
+
+#endif // _ACAMERA_METADATA_H
diff --git a/camera/ndk/impl/ACaptureRequest.h b/camera/ndk/impl/ACaptureRequest.h
new file mode 100644
index 0000000..6bd8406
--- /dev/null
+++ b/camera/ndk/impl/ACaptureRequest.h
@@ -0,0 +1,52 @@
+/*
+ * 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 _ACAPTURE_REQUEST_H
+#define _ACAPTURE_REQUEST_H
+
+#include "NdkCaptureRequest.h"
+#include <set>
+
+using namespace android;
+
+struct ACameraOutputTarget {
+ ACameraOutputTarget(ANativeWindow* window) : mWindow(window) {};
+
+ bool operator == (const ACameraOutputTarget& other) const {
+ return mWindow == other.mWindow;
+ }
+ bool operator != (const ACameraOutputTarget& other) const {
+ return mWindow != other.mWindow;
+ }
+ bool operator < (const ACameraOutputTarget& other) const {
+ return mWindow < other.mWindow;
+ }
+ bool operator > (const ACameraOutputTarget& other) const {
+ return mWindow > other.mWindow;
+ }
+
+ ANativeWindow* mWindow;
+};
+
+struct ACameraOutputTargets {
+ std::set<ACameraOutputTarget> mOutputs;
+};
+
+struct ACaptureRequest {
+ ACameraMetadata* settings;
+ ACameraOutputTargets* targets;
+};
+
+#endif // _ACAPTURE_REQUEST_H
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 572fb72..a36d2f9 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -160,6 +160,7 @@
virtual void onDeviceError(CameraErrorCode errorCode,
const CaptureResultExtras& resultExtras) {
+ (void) resultExtras;
ALOGE("%s: onDeviceError occurred with: %d", __FUNCTION__, static_cast<int>(errorCode));
Mutex::Autolock l(mLock);
mError = true;
@@ -177,6 +178,8 @@
virtual void onCaptureStarted(const CaptureResultExtras& resultExtras,
int64_t timestamp) {
+ (void) resultExtras;
+ (void) timestamp;
Mutex::Autolock l(mLock);
mLastStatus = RUNNING;
mStatusesHit.push_back(mLastStatus);
@@ -186,6 +189,8 @@
virtual void onResultReceived(const CameraMetadata& metadata,
const CaptureResultExtras& resultExtras) {
+ (void) metadata;
+ (void) resultExtras;
Mutex::Autolock l(mLock);
mLastStatus = SENT_RESULT;
mStatusesHit.push_back(mLastStatus);
@@ -193,6 +198,7 @@
}
virtual void onPrepared(int streamId) {
+ (void) streamId;
Mutex::Autolock l(mLock);
mLastStatus = PREPARED;
mStatusesHit.push_back(mLastStatus);
@@ -237,16 +243,36 @@
};
+namespace {
+ Mutex gLock;
+ class DeathNotifier : public IBinder::DeathRecipient
+ {
+ public:
+ DeathNotifier() {}
+
+ virtual void binderDied(const wp<IBinder>& /*who*/) {
+ ALOGV("binderDied");
+ Mutex::Autolock _l(gLock);
+ ALOGW("Camera service died!");
+ }
+ };
+ sp<DeathNotifier> gDeathNotifier;
+}; // anonymous namespace
+
// Exercise basic binder calls for the camera service
TEST(CameraServiceBinderTest, CheckBinderCameraService) {
ProcessState::self()->startThreadPool();
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.camera"));
ASSERT_NOT_NULL(binder);
+ if (gDeathNotifier == NULL) {
+ gDeathNotifier = new DeathNotifier();
+ }
+ binder->linkToDeath(gDeathNotifier);
sp<ICameraService> service = interface_cast<ICameraService>(binder);
- int32_t numCameras = service->getNumberOfCameras();
+ int32_t numCameras = service->getNumberOfCameras(ICameraService::CAMERA_TYPE_ALL);
EXPECT_LE(0, numCameras);
// Check listener binder calls
@@ -465,6 +491,7 @@
callbacks->clearStatus();
int requestId3 = device->submitRequestList(requestList, /*streaming*/false,
/*out*/&lastFrameNumber);
+ EXPECT_LE(0, requestId3);
EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT));
EXPECT_TRUE(callbacks->waitForIdle());
EXPECT_LE(lastFrameNumberPrev, lastFrameNumber);
diff --git a/cmds/screenrecord/FrameOutput.cpp b/cmds/screenrecord/FrameOutput.cpp
index bef74f5..ee7ace6 100644
--- a/cmds/screenrecord/FrameOutput.cpp
+++ b/cmds/screenrecord/FrameOutput.cpp
@@ -74,7 +74,7 @@
GL_TEXTURE_EXTERNAL_OES, true, false);
mGlConsumer->setName(String8("virtual display"));
mGlConsumer->setDefaultBufferSize(width, height);
- mGlConsumer->setDefaultMaxBufferCount(5);
+ producer->setMaxDequeuedBufferCount(4);
mGlConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_TEXTURE);
mGlConsumer->setFrameAvailableListener(this);
diff --git a/cmds/screenrecord/Overlay.cpp b/cmds/screenrecord/Overlay.cpp
index c659170..9fd192c 100644
--- a/cmds/screenrecord/Overlay.cpp
+++ b/cmds/screenrecord/Overlay.cpp
@@ -176,7 +176,7 @@
GL_TEXTURE_EXTERNAL_OES, true, false);
mGlConsumer->setName(String8("virtual display"));
mGlConsumer->setDefaultBufferSize(width, height);
- mGlConsumer->setDefaultMaxBufferCount(5);
+ mProducer->setMaxDequeuedBufferCount(4);
mGlConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_TEXTURE);
mGlConsumer->setFrameAvailableListener(this);
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 20c0094..e5fbba0 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -9,7 +9,7 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia libutils libbinder libstagefright_foundation \
- libjpeg libgui libcutils liblog
+ libjpeg libgui libcutils liblog
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -31,11 +31,11 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- SineSource.cpp \
- record.cpp
+ SineSource.cpp \
+ record.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder libstagefright_foundation
+ libstagefright libmedia liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -55,11 +55,11 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- SineSource.cpp \
- recordvideo.cpp
+ SineSource.cpp \
+ recordvideo.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder libstagefright_foundation
+ libstagefright libmedia liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -80,11 +80,11 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- SineSource.cpp \
- audioloop.cpp
+ SineSource.cpp \
+ audioloop.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder libstagefright_foundation
+ libstagefright libmedia liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -108,7 +108,7 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libgui \
- libstagefright_foundation libmedia libcutils
+ libstagefright_foundation libmedia libcutils
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -128,11 +128,11 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- sf2.cpp \
+ sf2.cpp \
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libstagefright_foundation \
- libmedia libgui libcutils libui
+ libmedia libgui libcutils libui
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -152,12 +152,12 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- codec.cpp \
- SimplePlayer.cpp \
+ codec.cpp \
+ SimplePlayer.cpp \
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libstagefright_foundation \
- libmedia libgui libcutils libui
+ libmedia libgui libcutils libui
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -220,11 +220,11 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- muxer.cpp \
+ muxer.cpp \
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libstagefright_foundation \
- libmedia libgui libcutils libui libc
+ libmedia libgui libcutils libui libc
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index 6e9e6ec..ed44b4d 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -23,13 +23,14 @@
#include <binder/ProcessState.h>
#include <media/mediarecorder.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/AudioSource.h>
+#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/SimpleDecodingSource.h>
#include "SineSource.h"
using namespace android;
@@ -79,8 +80,6 @@
const int32_t kBitRate = outputWBAMR ? 16000 : 8000;
android::ProcessState::self()->startThreadPool();
- OMXClient client;
- CHECK_EQ(client.connect(), (status_t)OK);
sp<MediaSource> source;
if (useMic) {
@@ -95,24 +94,25 @@
source = new SineSource(kSampleRate, channels);
}
- sp<MetaData> meta = new MetaData;
- meta->setCString(
- kKeyMIMEType,
+ sp<AMessage> meta = new AMessage;
+ meta->setString(
+ "mime",
outputWBAMR ? MEDIA_MIMETYPE_AUDIO_AMR_WB
: MEDIA_MIMETYPE_AUDIO_AMR_NB);
- meta->setInt32(kKeyChannelCount, channels);
- meta->setInt32(kKeySampleRate, kSampleRate);
- meta->setInt32(kKeyBitRate, kBitRate);
+ meta->setInt32("channel-count", channels);
+ meta->setInt32("sample-rate", kSampleRate);
+ meta->setInt32("bitrate", kBitRate);
int32_t maxInputSize;
if (source->getFormat()->findInt32(kKeyMaxInputSize, &maxInputSize)) {
- meta->setInt32(kKeyMaxInputSize, maxInputSize);
+ meta->setInt32("max-input-size", maxInputSize);
}
- sp<MediaSource> encoder = OMXCodec::Create(
- client.interface(),
- meta, true /* createEncoder */,
- source);
+ sp<ALooper> looper = new ALooper;
+ looper->setName("audioloop");
+ looper->start();
+
+ sp<IMediaSource> encoder = MediaCodecSource::Create(looper, meta, source);
if (fileOut != NULL) {
// target file specified, write encoded AMR output
@@ -128,17 +128,15 @@
writer->stop();
} else {
// otherwise decode to speaker
- sp<MediaSource> decoder = OMXCodec::Create(
- client.interface(),
- meta, false /* createEncoder */,
- encoder);
+ sp<IMediaSource> decoder = SimpleDecodingSource::Create(encoder);
if (playToSpeaker) {
AudioPlayer *player = new AudioPlayer(NULL);
player->setSource(decoder);
player->start();
sleep(duration);
- source->stop(); // must stop source otherwise delete player will hang
+
+ decoder.clear(); // must clear |decoder| otherwise delete player will hang.
delete player; // there is no player->stop()...
} else {
CHECK_EQ(decoder->start(), (status_t)OK);
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 594c933..f8b2f68 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -18,16 +18,18 @@
#include <binder/ProcessState.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MPEG4Writer.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/SimpleDecodingSource.h>
#include <media/MediaPlayerInterface.h>
using namespace android;
@@ -182,9 +184,6 @@
fprintf(stderr, "input color format must be 0 (YUV420SP) or 1 (YUV420P)\n");
return 1;
}
- OMXClient client;
- CHECK_EQ(client.connect(), (status_t)OK);
-
status_t err = OK;
#if 0
@@ -197,8 +196,7 @@
sp<MetaData> meta = source->getFormat();
- sp<MediaSource> decoder = OMXCodec::Create(
- client.interface(), meta, false /* createEncoder */, source);
+ sp<MediaSource> decoder = SimpleDecodingSource::Create(source);
int width, height;
bool success = meta->findInt32(kKeyWidth, &width);
@@ -210,22 +208,21 @@
sp<MediaSource> decoder = new DummySource(width, height, colorFormat);
#endif
- sp<MetaData> enc_meta = new MetaData;
- // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
- // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
- enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
- enc_meta->setInt32(kKeyWidth, width);
- enc_meta->setInt32(kKeyHeight, height);
- enc_meta->setInt32(kKeySampleRate, kFramerate);
- enc_meta->setInt32(kKeyBitRate, kVideoBitRate);
- enc_meta->setInt32(kKeyStride, width);
- enc_meta->setInt32(kKeySliceHeight, height);
- enc_meta->setInt32(kKeyIFramesInterval, kIFramesIntervalSec);
- enc_meta->setInt32(kKeyColorFormat, colorFormat);
+ sp<AMessage> enc_meta = new AMessage;
+ // enc_meta->setString("mime", MEDIA_MIMETYPE_VIDEO_H263);
+ // enc_meta->setString("mime", MEDIA_MIMETYPE_VIDEO_MPEG4);
+ enc_meta->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
+ enc_meta->setInt32("width", width);
+ enc_meta->setInt32("height", height);
+ enc_meta->setInt32("sample-rate", kFramerate);
+ enc_meta->setInt32("bit-rate", kVideoBitRate);
+ // enc_meta->setInt32("stride", width);
+ // enc_meta->setInt32("slice-height", height);
+ enc_meta->setInt32("i-frame-interval", kIFramesIntervalSec);
+ enc_meta->setInt32("color-format", colorFormat);
sp<MediaSource> encoder =
- OMXCodec::Create(
- client.interface(), enc_meta, true /* createEncoder */, decoder);
+ MediaCodecSource::Create(looper, format, decoder);
#if 1
sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
@@ -260,7 +257,6 @@
#endif
printf("$\n");
- client.disconnect();
#endif
#if 0
@@ -299,9 +295,6 @@
int main(int /* argc */, char ** /* argv */) {
android::ProcessState::self()->startThreadPool();
- OMXClient client;
- CHECK_EQ(client.connect(), (status_t)OK);
-
const int32_t kSampleRate = 22050;
const int32_t kNumChannels = 2;
sp<MediaSource> audioSource = new SineSource(kSampleRate, kNumChannels);
@@ -317,16 +310,20 @@
player->stop();
#endif
- sp<MetaData> encMeta = new MetaData;
- encMeta->setCString(kKeyMIMEType,
+ sp<AMessage> encMeta = new AMessage;
+ encMeta->setString("mime",
0 ? MEDIA_MIMETYPE_AUDIO_AMR_WB : MEDIA_MIMETYPE_AUDIO_AAC);
- encMeta->setInt32(kKeySampleRate, kSampleRate);
- encMeta->setInt32(kKeyChannelCount, kNumChannels);
- encMeta->setInt32(kKeyMaxInputSize, 8192);
- encMeta->setInt32(kKeyBitRate, kAudioBitRate);
+ encMeta->setInt32("sample-rate", kSampleRate);
+ encMeta->setInt32("channel-count", kNumChannels);
+ encMeta->setInt32("max-input-size", 8192);
+ encMeta->setInt32("bitrate", kAudioBitRate);
- sp<MediaSource> encoder =
- OMXCodec::Create(client.interface(), encMeta, true, audioSource);
+ sp<ALooper> looper = new ALooper;
+ looper->setName("record");
+ looper->start();
+
+ sp<IMediaSource> encoder =
+ MediaCodecSource::Create(looper, encMeta, audioSource);
encoder->start();
@@ -348,8 +345,6 @@
encoder->stop();
- client.disconnect();
-
return 0;
}
#endif
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index 2ad40bd..7a3c842 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -23,15 +23,18 @@
#include <binder/ProcessState.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MPEG4Writer.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
#include <media/MediaPlayerInterface.h>
+#include <OMX_Video.h>
+
using namespace android;
// Print usage showing how to use this utility to record videos
@@ -265,44 +268,45 @@
}
}
- OMXClient client;
- CHECK_EQ(client.connect(), (status_t)OK);
-
status_t err = OK;
sp<MediaSource> source =
new DummySource(width, height, nFrames, frameRateFps, colorFormat);
- sp<MetaData> enc_meta = new MetaData;
+ sp<AMessage> enc_meta = new AMessage;
switch (codec) {
case 1:
- enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+ enc_meta->setString("mime", MEDIA_MIMETYPE_VIDEO_MPEG4);
break;
case 2:
- enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
+ enc_meta->setString("mime", MEDIA_MIMETYPE_VIDEO_H263);
break;
default:
- enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+ enc_meta->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
break;
}
- enc_meta->setInt32(kKeyWidth, width);
- enc_meta->setInt32(kKeyHeight, height);
- enc_meta->setInt32(kKeyFrameRate, frameRateFps);
- enc_meta->setInt32(kKeyBitRate, bitRateBps);
- enc_meta->setInt32(kKeyStride, width);
- enc_meta->setInt32(kKeySliceHeight, height);
- enc_meta->setInt32(kKeyIFramesInterval, iFramesIntervalSeconds);
- enc_meta->setInt32(kKeyColorFormat, colorFormat);
+ enc_meta->setInt32("width", width);
+ enc_meta->setInt32("height", height);
+ enc_meta->setInt32("frame-rate", frameRateFps);
+ enc_meta->setInt32("bitrate", bitRateBps);
+ enc_meta->setInt32("stride", width);
+ enc_meta->setInt32("slice-height", height);
+ enc_meta->setInt32("i-frame-interval", iFramesIntervalSeconds);
+ enc_meta->setInt32("color-format", colorFormat);
if (level != -1) {
- enc_meta->setInt32(kKeyVideoLevel, level);
+ enc_meta->setInt32("level", level);
}
if (profile != -1) {
- enc_meta->setInt32(kKeyVideoProfile, profile);
+ enc_meta->setInt32("profile", profile);
}
- sp<MediaSource> encoder =
- OMXCodec::Create(
- client.interface(), enc_meta, true /* createEncoder */, source,
- 0, preferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0);
+ sp<ALooper> looper = new ALooper;
+ looper->setName("recordvideo");
+ looper->start();
+
+ sp<IMediaSource> encoder =
+ MediaCodecSource::Create(
+ looper, enc_meta, source, NULL /* consumer */,
+ preferSoftwareCodec ? MediaCodecSource::FLAG_PREFER_SOFTWARE_CODEC : 0);
int fd = open(fileName, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
if (fd < 0) {
@@ -321,7 +325,6 @@
int64_t end = systemTime();
fprintf(stderr, "$\n");
- client.disconnect();
if (err != OK && err != ERROR_END_OF_STREAM) {
fprintf(stderr, "record failed: %d\n", err);
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 0d64d2f..1a4bf08 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -118,7 +118,7 @@
DataSource::CreateFromURI(
NULL /* httpService */, mURI.c_str());
- sp<MediaExtractor> extractor =
+ sp<IMediaExtractor> extractor =
MediaExtractor::Create(dataSource);
for (size_t i = 0; i < extractor->countTracks(); ++i) {
@@ -264,7 +264,7 @@
sp<Surface> mSurface;
bool mRenderToSurface;
sp<ACodec> mCodec;
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
bool mIsVorbis;
Vector<sp<ABuffer> > mCSD;
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index a9c6eda..ca68722 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -31,20 +31,27 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <media/ICrypto.h>
#include <media/IMediaHTTPService.h>
+#include <media/IMediaCodecService.h>
#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AUtils.h>
#include "include/NuCachedSource2.h"
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/JPEGSource.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/SimpleDecodingSource.h>
+#include <media/stagefright/Utils.h>
#include <media/mediametadataretriever.h>
#include <media/stagefright/foundation/hexdump.h>
@@ -67,6 +74,7 @@
static bool gPlaybackAudio;
static bool gWriteMP4;
static bool gDisplayHistogram;
+static bool showProgress = true;
static String8 gWriteMP4Filename;
static sp<ANativeWindow> gSurface;
@@ -130,7 +138,7 @@
}
}
-static void dumpSource(const sp<MediaSource> &source, const String8 &filename) {
+static void dumpSource(const sp<IMediaSource> &source, const String8 &filename) {
FILE *out = fopen(filename.string(), "wb");
CHECK_EQ((status_t)OK, source->start());
@@ -163,32 +171,26 @@
out = NULL;
}
-static void playSource(OMXClient *client, sp<MediaSource> &source) {
+static void playSource(sp<IMediaSource> &source) {
sp<MetaData> meta = source->getFormat();
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
- sp<MediaSource> rawSource;
+ sp<IMediaSource> rawSource;
if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) {
rawSource = source;
} else {
int flags = 0;
if (gPreferSoftwareCodec) {
- flags |= OMXCodec::kPreferSoftwareCodecs;
+ flags |= MediaCodecList::kPreferSoftwareCodecs;
}
if (gForceToUseHardwareCodec) {
CHECK(!gPreferSoftwareCodec);
- flags |= OMXCodec::kHardwareCodecsOnly;
+ flags |= MediaCodecList::kHardwareCodecsOnly;
}
- rawSource = OMXCodec::Create(
- client->interface(), meta, false /* createEncoder */, source,
- NULL /* matchComponentName */,
- flags,
- gSurface);
-
+ rawSource = SimpleDecodingSource::Create(source, flags, gSurface);
if (rawSource == NULL) {
- fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime);
return;
}
displayAVCProfileLevelIfPossible(meta);
@@ -338,7 +340,7 @@
decodeTimesUs.push(delayDecodeUs);
}
- if ((n++ % 16) == 0) {
+ if (showProgress && (n++ % 16) == 0) {
printf(".");
fflush(stdout);
}
@@ -364,8 +366,10 @@
}
}
- printf("$");
- fflush(stdout);
+ if (showProgress) {
+ printf("$");
+ fflush(stdout);
+ }
options.setSeekTo(0);
}
@@ -397,7 +401,7 @@
////////////////////////////////////////////////////////////////////////////////
struct DetectSyncSource : public MediaSource {
- DetectSyncSource(const sp<MediaSource> &source);
+ DetectSyncSource(const sp<IMediaSource> &source);
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
@@ -414,14 +418,14 @@
OTHER,
};
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
StreamType mStreamType;
bool mSawFirstIDRFrame;
DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource);
};
-DetectSyncSource::DetectSyncSource(const sp<MediaSource> &source)
+DetectSyncSource::DetectSyncSource(const sp<IMediaSource> &source)
: mSource(source),
mStreamType(OTHER),
mSawFirstIDRFrame(false) {
@@ -503,7 +507,7 @@
////////////////////////////////////////////////////////////////////////////////
static void writeSourcesToMP4(
- Vector<sp<MediaSource> > &sources, bool syncInfoPresent) {
+ Vector<sp<IMediaSource> > &sources, bool syncInfoPresent) {
#if 0
sp<MPEG4Writer> writer =
new MPEG4Writer(gWriteMP4Filename.string());
@@ -521,7 +525,7 @@
writer->setMaxFileDuration(60000000ll);
for (size_t i = 0; i < sources.size(); ++i) {
- sp<MediaSource> source = sources.editItemAt(i);
+ sp<IMediaSource> source = sources.editItemAt(i);
CHECK_EQ(writer->addSource(
syncInfoPresent ? source : new DetectSyncSource(source)),
@@ -538,7 +542,7 @@
writer->stop();
}
-static void performSeekTest(const sp<MediaSource> &source) {
+static void performSeekTest(const sp<IMediaSource> &source) {
CHECK_EQ((status_t)OK, source->start());
int64_t durationUs;
@@ -612,49 +616,57 @@
fprintf(stderr, " -k seek test\n");
fprintf(stderr, " -x display a histogram of decoding times/fps "
"(video only)\n");
+ fprintf(stderr, " -q don't show progress indicator\n");
fprintf(stderr, " -S allocate buffers from a surface\n");
fprintf(stderr, " -T allocate buffers from a surface texture\n");
fprintf(stderr, " -d(ump) output_filename (raw stream data to a file)\n");
fprintf(stderr, " -D(ump) output_filename (decoded PCM data to a file)\n");
}
-static void dumpCodecProfiles(const sp<IOMX>& omx, bool queryDecoders) {
+static void dumpCodecProfiles(bool queryDecoders) {
const char *kMimeTypes[] = {
MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AAC,
MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB,
MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
- MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9
+ MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
+ MEDIA_MIMETYPE_VIDEO_DOLBY_VISION
};
const char *codecType = queryDecoders? "decoder" : "encoder";
printf("%s profiles:\n", codecType);
+ sp<IMediaCodecList> list = MediaCodecList::getInstance();
+ size_t numCodecs = list->countCodecs();
+
for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); ++k) {
printf("type '%s':\n", kMimeTypes[k]);
- Vector<CodecCapabilities> results;
- // will retrieve hardware and software codecs
- CHECK_EQ(QueryCodecs(omx, kMimeTypes[k],
- queryDecoders,
- &results), (status_t)OK);
-
- for (size_t i = 0; i < results.size(); ++i) {
+ for (size_t index = 0; index < numCodecs; ++index) {
+ sp<MediaCodecInfo> info = list->getCodecInfo(index);
+ if (info == NULL || info->isEncoder() != !queryDecoders) {
+ continue;
+ }
+ sp<MediaCodecInfo::Capabilities> caps = info->getCapabilitiesFor(kMimeTypes[k]);
+ if (caps == NULL) {
+ continue;
+ }
printf(" %s '%s' supports ",
- codecType, results[i].mComponentName.string());
+ codecType, info->getCodecName());
- if (results[i].mProfileLevels.size() == 0) {
- printf("NOTHING.\n");
- continue;
+ Vector<MediaCodecInfo::ProfileLevel> profileLevels;
+ caps->getSupportedProfileLevels(&profileLevels);
+ if (profileLevels.size() == 0) {
+ printf("NOTHING.\n");
+ continue;
}
- for (size_t j = 0; j < results[i].mProfileLevels.size(); ++j) {
- const CodecProfileLevel &profileLevel =
- results[i].mProfileLevels[j];
+ for (size_t j = 0; j < profileLevels.size(); ++j) {
+ const MediaCodecInfo::ProfileLevel &profileLevel = profileLevels[j];
- printf("%s%" PRIu32 "/%" PRIu32, j > 0 ? ", " : "",
- profileLevel.mProfile, profileLevel.mLevel);
+ printf("%s%u/%u", j > 0 ? ", " : "",
+ profileLevel.mProfile, profileLevel.mLevel);
}
printf("\n");
@@ -687,7 +699,7 @@
sp<ALooper> looper;
int res;
- while ((res = getopt(argc, argv, "han:lm:b:ptsrow:kxSTd:D:")) >= 0) {
+ while ((res = getopt(argc, argv, "haqn:lm:b:ptsrow:kxSTd:D:")) >= 0) {
switch (res) {
case 'a':
{
@@ -695,6 +707,12 @@
break;
}
+ case 'q':
+ {
+ showProgress = false;
+ break;
+ }
+
case 'd':
{
dumpStream = true;
@@ -881,23 +899,14 @@
}
if (dumpProfiles) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.player"));
- sp<IMediaPlayerService> service =
- interface_cast<IMediaPlayerService>(binder);
-
- CHECK(service.get() != NULL);
-
- sp<IOMX> omx = service->getOMX();
- CHECK(omx.get() != NULL);
- dumpCodecProfiles(omx, true /* queryDecoders */);
- dumpCodecProfiles(omx, false /* queryDecoders */);
+ dumpCodecProfiles(true /* queryDecoders */);
+ dumpCodecProfiles(false /* queryDecoders */);
}
if (listComponents) {
sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.player"));
- sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+ sp<IBinder> binder = sm->getService(String16("media.codec"));
+ sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
CHECK(service.get() != NULL);
@@ -954,16 +963,11 @@
false /* isControlledByApp */);
gSurface = new Surface(producer);
}
-
- CHECK_EQ((status_t)OK,
- native_window_api_connect(
- gSurface.get(), NATIVE_WINDOW_API_MEDIA));
}
DataSource::RegisterDefaultSniffers();
- OMXClient client;
- status_t err = client.connect();
+ status_t err = OK;
for (int k = 0; k < argc && err == OK; ++k) {
bool syncInfoPresent = true;
@@ -985,8 +989,8 @@
isJPEG = true;
}
- Vector<sp<MediaSource> > mediaSources;
- sp<MediaSource> mediaSource;
+ Vector<sp<IMediaSource> > mediaSources;
+ sp<IMediaSource> mediaSource;
if (isJPEG) {
mediaSource = new JPEGSource(dataSource);
@@ -1005,7 +1009,7 @@
mediaSources.push(mediaSource);
}
} else {
- sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+ sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
if (extractor == NULL) {
fprintf(stderr, "could not create extractor.\n");
@@ -1016,7 +1020,10 @@
if (meta != NULL) {
const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
+ if (!meta->findCString(kKeyMIMEType, &mime)) {
+ fprintf(stderr, "extractor did not provide MIME type.\n");
+ return -1;
+ }
if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
syncInfoPresent = false;
@@ -1029,7 +1036,7 @@
bool haveAudio = false;
bool haveVideo = false;
for (size_t i = 0; i < numTracks; ++i) {
- sp<MediaSource> source = extractor->getTrack(i);
+ sp<IMediaSource> source = extractor->getTrack(i);
const char *mime;
CHECK(source->getFormat()->findCString(
@@ -1059,6 +1066,9 @@
meta = extractor->getTrackMetaData(
i, MediaExtractor::kIncludeExtensiveMetaData);
+ if (meta == NULL) {
+ break;
+ }
const char *mime;
meta->findCString(kKeyMIMEType, &mime);
@@ -1097,31 +1107,16 @@
} else if (dumpStream) {
dumpSource(mediaSource, dumpStreamFilename);
} else if (dumpPCMStream) {
- OMXClient client;
- CHECK_EQ(client.connect(), (status_t)OK);
-
- sp<MediaSource> decSource =
- OMXCodec::Create(
- client.interface(),
- mediaSource->getFormat(),
- false,
- mediaSource,
- 0,
- 0);
-
+ sp<IMediaSource> decSource = SimpleDecodingSource::Create(mediaSource);
dumpSource(decSource, dumpStreamFilename);
} else if (seekTest) {
performSeekTest(mediaSource);
} else {
- playSource(&client, mediaSource);
+ playSource(mediaSource);
}
}
if ((useSurfaceAlloc || useSurfaceTexAlloc) && !audioOnly) {
- CHECK_EQ((status_t)OK,
- native_window_api_disconnect(
- gSurface.get(), NATIVE_WINDOW_API_MEDIA));
-
gSurface.clear();
if (useSurfaceAlloc) {
@@ -1129,7 +1124,5 @@
}
}
- client.disconnect();
-
return 0;
}
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index 1a40e53..bca3832 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -165,7 +165,7 @@
CHECK(dataSource != NULL);
- sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+ sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
CHECK(extractor != NULL);
mWriter = new MPEG2TSWriter(
diff --git a/drm/drmserver/Android.mk b/drm/drmserver/Android.mk
index 48ea385..3b8bb04 100644
--- a/drm/drmserver/Android.mk
+++ b/drm/drmserver/Android.mk
@@ -36,10 +36,14 @@
$(TOP)/frameworks/av/drm/libdrmframework/include \
$(TOP)/frameworks/av/drm/libdrmframework/plugins/common/include
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
LOCAL_MODULE:= drmserver
LOCAL_MODULE_TAGS := optional
LOCAL_32_BIT_ONLY := true
+LOCAL_INIT_RC := drmserver.rc
+
include $(BUILD_EXECUTABLE)
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index d8aeb0c..e168ba2 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -370,7 +370,7 @@
}
status_t DrmManager::getAllSupportInfo(
- int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) {
+ int /* uniqueId */, int* length, DrmSupportInfo** drmSupportInfoArray) {
Mutex::Autolock _l(mLock);
Vector<String8> plugInPathList = mPlugInManager.getPlugInIdList();
int size = plugInPathList.size();
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 857d73e..814ffcc 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -51,8 +51,7 @@
const char *DrmManagerService::get_perm_label(drm_perm_t perm) {
unsigned int index = perm;
- if (index < 0 ||
- index >= (sizeof(drm_perm_labels) / sizeof(drm_perm_labels[0]))) {
+ if (index >= (sizeof(drm_perm_labels) / sizeof(drm_perm_labels[0]))) {
ALOGE("SELinux: Failed to retrieve permission label(perm=%d).\n", perm);
abort();
}
@@ -338,7 +337,7 @@
return mDrmManager->pread(uniqueId, decryptHandle, buffer, numBytes, offset);
}
-status_t DrmManagerService::dump(int fd, const Vector<String16>& args)
+status_t DrmManagerService::dump(int fd, const Vector<String16>& /* args */)
{
const size_t SIZE = 256;
char buffer[SIZE];
diff --git a/drm/drmserver/drmserver.rc b/drm/drmserver/drmserver.rc
new file mode 100644
index 0000000..42f5fc8
--- /dev/null
+++ b/drm/drmserver/drmserver.rc
@@ -0,0 +1,4 @@
+service drm /system/bin/drmserver
+ class main
+ user drm
+ group drm system inet drmrpc readproc
diff --git a/drm/drmserver/main_drmserver.cpp b/drm/drmserver/main_drmserver.cpp
index 434d561..1ce42e8 100644
--- a/drm/drmserver/main_drmserver.cpp
+++ b/drm/drmserver/main_drmserver.cpp
@@ -26,7 +26,7 @@
using namespace android;
-int main(int argc, char** argv)
+int main()
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
diff --git a/drm/libdrmframework/Android.mk b/drm/libdrmframework/Android.mk
index 33f9d3b..cafcb94 100644
--- a/drm/libdrmframework/Android.mk
+++ b/drm/libdrmframework/Android.mk
@@ -38,6 +38,7 @@
$(TOP)/frameworks/av/drm/libdrmframework/include \
$(TOP)/frameworks/av/include
+LOCAL_CFLAGS += -Werror
LOCAL_MODULE_TAGS := optional
diff --git a/drm/libdrmframework/DrmManagerClientImpl.cpp b/drm/libdrmframework/DrmManagerClientImpl.cpp
index 9457bb6..cbd013e 100644
--- a/drm/libdrmframework/DrmManagerClientImpl.cpp
+++ b/drm/libdrmframework/DrmManagerClientImpl.cpp
@@ -350,7 +350,8 @@
}
}
-void DrmManagerClientImpl::DeathNotifier::binderDied(const wp<IBinder>& who) {
+void DrmManagerClientImpl::DeathNotifier::binderDied(
+ const wp<IBinder>& /* who */) {
Mutex::Autolock lock(sMutex);
DrmManagerClientImpl::sDrmManagerService.clear();
ALOGW("DrmManager server died!");
diff --git a/drm/libdrmframework/NoOpDrmManagerClientImpl.cpp b/drm/libdrmframework/NoOpDrmManagerClientImpl.cpp
index dab583d..1172e80 100644
--- a/drm/libdrmframework/NoOpDrmManagerClientImpl.cpp
+++ b/drm/libdrmframework/NoOpDrmManagerClientImpl.cpp
@@ -18,134 +18,209 @@
namespace android {
-void NoOpDrmManagerClientImpl::remove(int uniqueId) {
+void NoOpDrmManagerClientImpl::remove(int /* uniqueId */) {
}
-void NoOpDrmManagerClientImpl::addClient(int uniqueId) {
+void NoOpDrmManagerClientImpl::addClient(int /* uniqueId */) {
}
-void NoOpDrmManagerClientImpl::removeClient(int uniqueId) {
+void NoOpDrmManagerClientImpl::removeClient(
+ int /* uniqueId */) {
}
status_t NoOpDrmManagerClientImpl::setOnInfoListener(
- int uniqueId, const sp<DrmManagerClient::OnInfoListener>& infoListener) {
+ int /* uniqueId */,
+ const sp<DrmManagerClient::OnInfoListener>& /* infoListener */) {
return UNKNOWN_ERROR;
}
-DrmConstraints* NoOpDrmManagerClientImpl::getConstraints(int uniqueId, const String8* path, const int action) {
+DrmConstraints* NoOpDrmManagerClientImpl::getConstraints(
+ int /* uniqueId */,
+ const String8* /* path */,
+ const int /* action */) {
return NULL;
}
-DrmMetadata* NoOpDrmManagerClientImpl::getMetadata(int uniqueId, const String8* path) {
+DrmMetadata* NoOpDrmManagerClientImpl::getMetadata(
+ int /* uniqueId */,
+ const String8* /* path */) {
return NULL;
}
-bool NoOpDrmManagerClientImpl::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
+bool NoOpDrmManagerClientImpl::canHandle(
+ int /* uniqueId */,
+ const String8& /* path */,
+ const String8& /* mimeType */) {
return false;
}
-DrmInfoStatus* NoOpDrmManagerClientImpl::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+DrmInfoStatus* NoOpDrmManagerClientImpl::processDrmInfo(
+ int /* uniqueId */,
+ const DrmInfo* /* drmInfo */) {
return NULL;
}
-DrmInfo* NoOpDrmManagerClientImpl::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
+DrmInfo* NoOpDrmManagerClientImpl::acquireDrmInfo(
+ int /* uniqueId */,
+ const DrmInfoRequest* /* drmInfoRequest */) {
return NULL;
}
-status_t NoOpDrmManagerClientImpl::saveRights(int uniqueId, const DrmRights& drmRights,
- const String8& rightsPath, const String8& contentPath) {
+status_t NoOpDrmManagerClientImpl::saveRights(
+ int /* uniqueId */,
+ const DrmRights& /* drmRights */,
+ const String8& /* rightsPath */,
+ const String8& /* contentPath */) {
return UNKNOWN_ERROR;
}
-String8 NoOpDrmManagerClientImpl::getOriginalMimeType(int uniqueId, const String8& path, int fd) {
+String8 NoOpDrmManagerClientImpl::getOriginalMimeType(
+ int /* uniqueId */,
+ const String8& /* path */,
+ int /* fd */) {
return String8();
}
-int NoOpDrmManagerClientImpl::getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType) {
+int NoOpDrmManagerClientImpl::getDrmObjectType(
+ int /* uniqueId */,
+ const String8& /* path */,
+ const String8& /* mimeType */) {
return -1;
}
-int NoOpDrmManagerClientImpl::checkRightsStatus(int uniqueId, const String8& path, int action) {
+int NoOpDrmManagerClientImpl::checkRightsStatus(
+ int /* uniqueId */,
+ const String8& /* path */,
+ int /* action */) {
return -1;
}
-status_t NoOpDrmManagerClientImpl::consumeRights(int uniqueId, sp<DecryptHandle> &decryptHandle, int action, bool reserve) {
+status_t NoOpDrmManagerClientImpl::consumeRights(
+ int /* uniqueId */,
+ sp<DecryptHandle> &/* decryptHandle */,
+ int /* action */,
+ bool /* reserve */) {
return UNKNOWN_ERROR;
}
status_t NoOpDrmManagerClientImpl::setPlaybackStatus(
- int uniqueId, sp<DecryptHandle> &decryptHandle, int playbackStatus, int64_t position) {
+ int /* uniqueId */,
+ sp<DecryptHandle> &/* decryptHandle */,
+ int /* playbackStatus */,
+ int64_t /* position */) {
return UNKNOWN_ERROR;
}
bool NoOpDrmManagerClientImpl::validateAction(
- int uniqueId, const String8& path, int action, const ActionDescription& description) {
+ int /* uniqueId */,
+ const String8& /* path */,
+ int /* action */,
+ const ActionDescription& /* description */) {
return false;
}
-status_t NoOpDrmManagerClientImpl::removeRights(int uniqueId, const String8& path) {
+status_t NoOpDrmManagerClientImpl::removeRights(
+ int /* uniqueId */,
+ const String8& /* path */) {
return UNKNOWN_ERROR;
}
-status_t NoOpDrmManagerClientImpl::removeAllRights(int uniqueId) {
+status_t NoOpDrmManagerClientImpl::removeAllRights(
+ int /* uniqueId */) {
return UNKNOWN_ERROR;
}
-int NoOpDrmManagerClientImpl::openConvertSession(int uniqueId, const String8& mimeType) {
+int NoOpDrmManagerClientImpl::openConvertSession(
+ int /* uniqueId */,
+ const String8& /* mimeType */) {
return -1;
}
-DrmConvertedStatus* NoOpDrmManagerClientImpl::convertData(int uniqueId, int convertId, const DrmBuffer* inputData) {
+DrmConvertedStatus* NoOpDrmManagerClientImpl::convertData(
+ int /* uniqueId */,
+ int /* convertId */,
+ const DrmBuffer* /* inputData */) {
return NULL;
}
-DrmConvertedStatus* NoOpDrmManagerClientImpl::closeConvertSession(int uniqueId, int convertId) {
+DrmConvertedStatus* NoOpDrmManagerClientImpl::closeConvertSession(
+ int /* uniqueId */,
+ int /* convertId */) {
return NULL;
}
-status_t NoOpDrmManagerClientImpl::getAllSupportInfo(int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) {
+status_t NoOpDrmManagerClientImpl::getAllSupportInfo(
+ int /* uniqueId */,
+ int* /* length */,
+ DrmSupportInfo** /* drmSupportInfoArray */) {
return UNKNOWN_ERROR;
}
sp<DecryptHandle> NoOpDrmManagerClientImpl::openDecryptSession(
- int uniqueId, int fd, off64_t offset, off64_t length, const char* mime) {
+ int /* uniqueId */,
+ int /* fd */,
+ off64_t /* offset */,
+ off64_t /* length */,
+ const char* /* mime */) {
return NULL;
}
sp<DecryptHandle> NoOpDrmManagerClientImpl::openDecryptSession(
- int uniqueId, const char* uri, const char* mime) {
+ int /* uniqueId */,
+ const char* /* uri */,
+ const char* /* mime */) {
return NULL;
}
-sp<DecryptHandle> NoOpDrmManagerClientImpl::openDecryptSession(int uniqueId, const DrmBuffer& buf,
- const String8& mimeType) {
+sp<DecryptHandle> NoOpDrmManagerClientImpl::openDecryptSession(
+ int /* uniqueId */,
+ const DrmBuffer& /* buf */,
+ const String8& /* mimeType */) {
return NULL;
}
-status_t NoOpDrmManagerClientImpl::closeDecryptSession(int uniqueId, sp<DecryptHandle> &decryptHandle) {
+status_t NoOpDrmManagerClientImpl::closeDecryptSession(
+ int /* uniqueId */,
+ sp<DecryptHandle> &/* decryptHandle */) {
return UNKNOWN_ERROR;
}
-status_t NoOpDrmManagerClientImpl::initializeDecryptUnit(int uniqueId, sp<DecryptHandle> &decryptHandle,
- int decryptUnitId, const DrmBuffer* headerInfo) {
+status_t NoOpDrmManagerClientImpl::initializeDecryptUnit(
+ int /* uniqueId */,
+ sp<DecryptHandle> &/* decryptHandle */,
+ int /* decryptUnitId */,
+ const DrmBuffer* /* headerInfo */) {
return UNKNOWN_ERROR;
}
-status_t NoOpDrmManagerClientImpl::decrypt(int uniqueId, sp<DecryptHandle> &decryptHandle, int decryptUnitId,
- const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+status_t NoOpDrmManagerClientImpl::decrypt(
+ int /* uniqueId */,
+ sp<DecryptHandle> &/* decryptHandle */,
+ int /* decryptUnitId */,
+ const DrmBuffer* /* encBuffer */,
+ DrmBuffer** /* decBuffer */,
+ DrmBuffer* /* IV */) {
return UNKNOWN_ERROR;
}
-status_t NoOpDrmManagerClientImpl::finalizeDecryptUnit(int uniqueId, sp<DecryptHandle> &decryptHandle, int decryptUnitId) {
+status_t NoOpDrmManagerClientImpl::finalizeDecryptUnit(
+ int /* uniqueId */,
+ sp<DecryptHandle> &/* decryptHandle */,
+ int /* decryptUnitId */) {
return UNKNOWN_ERROR;
}
-ssize_t NoOpDrmManagerClientImpl::pread(int uniqueId, sp<DecryptHandle> &decryptHandle,
- void* buffer, ssize_t numBytes, off64_t offset) {
+ssize_t NoOpDrmManagerClientImpl::pread(
+ int /* uniqueId */,
+ sp<DecryptHandle> &/* decryptHandle */,
+ void* /* buffer */,
+ ssize_t /* numBytes */,
+ off64_t /* offset */) {
return -1;
}
-status_t NoOpDrmManagerClientImpl::notify(const DrmInfoEvent& event) {
+status_t NoOpDrmManagerClientImpl::notify(
+ const DrmInfoEvent& /* event */) {
return UNKNOWN_ERROR;
}
diff --git a/drm/libdrmframework/plugins/common/include/DrmEngineBase.h b/drm/libdrmframework/plugins/common/include/DrmEngineBase.h
index fa51c13..417107f 100644
--- a/drm/libdrmframework/plugins/common/include/DrmEngineBase.h
+++ b/drm/libdrmframework/plugins/common/include/DrmEngineBase.h
@@ -398,9 +398,9 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t onOpenDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
- int fd, off64_t offset, off64_t length,
- const char* mime) {
+ int /* uniqueId */, DecryptHandle* /* decryptHandle */,
+ int /* fd */, off64_t /* offset */, off64_t /* length */,
+ const char* /* mime */) {
return DRM_ERROR_CANNOT_HANDLE;
}
@@ -430,8 +430,8 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t onOpenDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
- const char* uri, const char* mime) {
+ int /* uniqueId */, DecryptHandle* /* decryptHandle */,
+ const char* /* uri */, const char* /* mime */) {
return DRM_ERROR_CANNOT_HANDLE;
}
@@ -446,8 +446,10 @@
* @return
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
- virtual status_t onOpenDecryptSession(int uniqueId, DecryptHandle* decryptHandle,
- const DrmBuffer& buf, const String8& mimeType) {
+ virtual status_t onOpenDecryptSession(int /* uniqueId */,
+ DecryptHandle* /* decryptHandle */,
+ const DrmBuffer& /* buf */,
+ const String8& /* mimeType */) {
return DRM_ERROR_CANNOT_HANDLE;
}
diff --git a/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp b/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
index 576ed15..4bd1adb 100644
--- a/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
+++ b/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
@@ -115,7 +115,7 @@
* replacement mimetype otherwise the original mimetype
* is returned.
*
- * If the mimetype is of unsupported group i.e. application/*
+ * If the mimetype is of unsupported group i.e. application / *
* then "unsupported/drm.mimetype" will be returned.
*
* @param mimeType - mimetype in lower case to convert.
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
index f400732..a495616 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
@@ -119,7 +119,7 @@
return drmConstraints;
}
-DrmMetadata* FwdLockEngine::onGetMetadata(int uniqueId, const String8* path) {
+DrmMetadata* FwdLockEngine::onGetMetadata(int /* uniqueId */, const String8* path) {
DrmMetadata* drmMetadata = NULL;
LOG_VERBOSE("FwdLockEngine::onGetMetadata");
@@ -132,7 +132,7 @@
return drmMetadata;
}
-android::status_t FwdLockEngine::onInitialize(int uniqueId) {
+android::status_t FwdLockEngine::onInitialize(int /* uniqueId */) {
LOG_VERBOSE("FwdLockEngine::onInitialize");
if (FwdLockGlue_InitializeKeyEncryption()) {
@@ -146,14 +146,16 @@
}
android::status_t
-FwdLockEngine::onSetOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener) {
+FwdLockEngine::onSetOnInfoListener(
+ int /* uniqueId */,
+ const IDrmEngine::OnInfoListener* /* infoListener */) {
// Not used
LOG_VERBOSE("FwdLockEngine::onSetOnInfoListener");
return DRM_NO_ERROR;
}
-android::status_t FwdLockEngine::onTerminate(int uniqueId) {
+android::status_t FwdLockEngine::onTerminate(int /* uniqueId */) {
LOG_VERBOSE("FwdLockEngine::onTerminate");
return DRM_NO_ERROR;
@@ -207,7 +209,7 @@
return false;
}
-DrmSupportInfo* FwdLockEngine::onGetSupportInfo(int uniqueId) {
+DrmSupportInfo* FwdLockEngine::onGetSupportInfo(int /* uniqueId */) {
DrmSupportInfo* pSupportInfo = new DrmSupportInfo();
LOG_VERBOSE("FwdLockEngine::onGetSupportInfo");
@@ -222,14 +224,14 @@
return pSupportInfo;
}
-bool FwdLockEngine::onCanHandle(int uniqueId, const String8& path) {
+bool FwdLockEngine::onCanHandle(int /* uniqueId */, const String8& path) {
bool result = false;
String8 extString = path.getPathExtension();
return IsFileSuffixSupported(extString);
}
-DrmInfoStatus* FwdLockEngine::onProcessDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+DrmInfoStatus* FwdLockEngine::onProcessDrmInfo(int /* uniqueId */, const DrmInfo* /* drmInfo */) {
DrmInfoStatus *drmInfoStatus = NULL;
// Nothing to process
@@ -242,16 +244,17 @@
}
status_t FwdLockEngine::onSaveRights(
- int uniqueId,
- const DrmRights& drmRights,
- const String8& rightsPath,
- const String8& contentPath) {
+ int /* uniqueId */,
+ const DrmRights& /* drmRights */,
+ const String8& /* rightsPath */,
+ const String8& /* contentPath */) {
// No rights to save. Return
LOG_VERBOSE("FwdLockEngine::onSaveRights");
return DRM_ERROR_UNKNOWN;
}
-DrmInfo* FwdLockEngine::onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
+DrmInfo* FwdLockEngine::onAcquireDrmInfo(
+ int /* uniqueId */, const DrmInfoRequest* /* drmInfoRequest */) {
DrmInfo* drmInfo = NULL;
// Nothing to be done for Forward Lock file
@@ -290,10 +293,10 @@
return result;
}
-status_t FwdLockEngine::onConsumeRights(int uniqueId,
- DecryptHandle* decryptHandle,
- int action,
- bool reserve) {
+status_t FwdLockEngine::onConsumeRights(int /* uniqueId */,
+ DecryptHandle* /* decryptHandle */,
+ int /* action */,
+ bool /* reserve */) {
// No rights consumption
LOG_VERBOSE("FwdLockEngine::onConsumeRights");
return DRM_NO_ERROR;
@@ -302,14 +305,16 @@
bool FwdLockEngine::onValidateAction(int uniqueId,
const String8& path,
int action,
- const ActionDescription& description) {
+ const ActionDescription& /* description */) {
LOG_VERBOSE("FwdLockEngine::onValidateAction");
// For the forwardlock engine checkRights and ValidateAction are the same.
return (onCheckRightsStatus(uniqueId, path, action) == RightsStatus::RIGHTS_VALID);
}
-String8 FwdLockEngine::onGetOriginalMimeType(int uniqueId, const String8& path, int fd) {
+String8 FwdLockEngine::onGetOriginalMimeType(int /* uniqueId */,
+ const String8& /* path */,
+ int fd) {
LOG_VERBOSE("FwdLockEngine::onGetOriginalMimeType");
String8 mimeString = String8("");
int fileDesc = dup(fd);
@@ -354,32 +359,32 @@
return DrmObjectType::UNKNOWN;
}
-status_t FwdLockEngine::onRemoveRights(int uniqueId, const String8& path) {
+status_t FwdLockEngine::onRemoveRights(int /* uniqueId */, const String8& /* path */) {
// No Rights to remove
LOG_VERBOSE("FwdLockEngine::onRemoveRights");
return DRM_NO_ERROR;
}
-status_t FwdLockEngine::onRemoveAllRights(int uniqueId) {
+status_t FwdLockEngine::onRemoveAllRights(int /* uniqueId */) {
// No rights to remove
LOG_VERBOSE("FwdLockEngine::onRemoveAllRights");
return DRM_NO_ERROR;
}
#ifdef USE_64BIT_DRM_API
-status_t FwdLockEngine::onSetPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
- int playbackStatus, int64_t position) {
+status_t FwdLockEngine::onSetPlaybackStatus(int /* uniqueId */, DecryptHandle* /* decryptHandle */,
+ int /* playbackStatus */, int64_t /* position */) {
#else
-status_t FwdLockEngine::onSetPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
- int playbackStatus, int position) {
+status_t FwdLockEngine::onSetPlaybackStatus(int /* uniqueId */, DecryptHandle* /* decryptHandle */,
+ int /* playbackStatus */, int /* position */) {
#endif
// Not used
LOG_VERBOSE("FwdLockEngine::onSetPlaybackStatus");
return DRM_NO_ERROR;
}
-status_t FwdLockEngine::onOpenConvertSession(int uniqueId,
- int convertId) {
+status_t FwdLockEngine::onOpenConvertSession(
+ int /* uniqueId */, int convertId) {
status_t result = DRM_ERROR_UNKNOWN;
LOG_VERBOSE("FwdLockEngine::onOpenConvertSession");
if (!convertSessionMap.isCreated(convertId)) {
@@ -396,7 +401,7 @@
return result;
}
-DrmConvertedStatus* FwdLockEngine::onConvertData(int uniqueId,
+DrmConvertedStatus* FwdLockEngine::onConvertData(int /* uniqueId */,
int convertId,
const DrmBuffer* inputData) {
FwdLockConv_Status_t retStatus = FwdLockConv_Status_InvalidArgument;
@@ -432,7 +437,7 @@
return new DrmConvertedStatus(getConvertedStatus(retStatus), convResult, offset);
}
-DrmConvertedStatus* FwdLockEngine::onCloseConvertSession(int uniqueId,
+DrmConvertedStatus* FwdLockEngine::onCloseConvertSession(int /* uniqueId */,
int convertId) {
FwdLockConv_Status_t retStatus = FwdLockConv_Status_InvalidArgument;
DrmBuffer *convResult = new DrmBuffer(NULL, 0);
@@ -464,17 +469,17 @@
}
#ifdef USE_64BIT_DRM_API
-status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
+status_t FwdLockEngine::onOpenDecryptSession(int /* uniqueId */,
DecryptHandle* decryptHandle,
int fd,
off64_t offset,
- off64_t length) {
+ off64_t /* length */) {
#else
-status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
+status_t FwdLockEngine::onOpenDecryptSession(int /* uniqueId */,
DecryptHandle* decryptHandle,
int fd,
int offset,
- int length) {
+ int /* length */) {
#endif
status_t result = DRM_ERROR_CANNOT_HANDLE;
int fileDesc = -1;
@@ -552,7 +557,7 @@
return result;
}
-status_t FwdLockEngine::onCloseDecryptSession(int uniqueId,
+status_t FwdLockEngine::onCloseDecryptSession(int /* uniqueId */,
DecryptHandle* decryptHandle) {
status_t result = DRM_ERROR_UNKNOWN;
LOG_VERBOSE("FwdLockEngine::onCloseDecryptSession");
@@ -584,37 +589,42 @@
return result;
}
-status_t FwdLockEngine::onInitializeDecryptUnit(int uniqueId,
- DecryptHandle* decryptHandle,
- int decryptUnitId,
- const DrmBuffer* headerInfo) {
+status_t FwdLockEngine::onInitializeDecryptUnit(int /* uniqueId */,
+ DecryptHandle* /* decryptHandle */,
+ int /* decryptUnitId */,
+ const DrmBuffer* /* headerInfo */) {
ALOGE("FwdLockEngine::onInitializeDecryptUnit is not supported for this DRM scheme");
return DRM_ERROR_UNKNOWN;
}
-status_t FwdLockEngine::onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
- const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+status_t FwdLockEngine::onDecrypt(
+ int /* uniqueId */,
+ DecryptHandle* /* decryptHandle */,
+ int /* decryptUnitId */,
+ const DrmBuffer* /* encBuffer */,
+ DrmBuffer** /* decBuffer */,
+ DrmBuffer* /* IV */) {
ALOGE("FwdLockEngine::onDecrypt is not supported for this DRM scheme");
return DRM_ERROR_UNKNOWN;
}
-status_t FwdLockEngine::onDecrypt(int uniqueId,
- DecryptHandle* decryptHandle,
- int decryptUnitId,
- const DrmBuffer* encBuffer,
- DrmBuffer** decBuffer) {
+status_t FwdLockEngine::onDecrypt(int /* uniqueId */,
+ DecryptHandle* /* decryptHandle */,
+ int /* decryptUnitId */,
+ const DrmBuffer* /* encBuffer */,
+ DrmBuffer** /* decBuffer */) {
ALOGE("FwdLockEngine::onDecrypt is not supported for this DRM scheme");
return DRM_ERROR_UNKNOWN;
}
-status_t FwdLockEngine::onFinalizeDecryptUnit(int uniqueId,
- DecryptHandle* decryptHandle,
- int decryptUnitId) {
+status_t FwdLockEngine::onFinalizeDecryptUnit(int /* uniqueId */,
+ DecryptHandle* /* decryptHandle */,
+ int /* decryptUnitId */) {
ALOGE("FwdLockEngine::onFinalizeDecryptUnit is not supported for this DRM scheme");
return DRM_ERROR_UNKNOWN;
}
-ssize_t FwdLockEngine::onRead(int uniqueId,
+ssize_t FwdLockEngine::onRead(int /* uniqueId */,
DecryptHandle* decryptHandle,
void* buffer,
int numBytes) {
@@ -640,10 +650,10 @@
}
#ifdef USE_64BIT_DRM_API
-off64_t FwdLockEngine::onLseek(int uniqueId, DecryptHandle* decryptHandle,
+off64_t FwdLockEngine::onLseek(int /* uniqueId */, DecryptHandle* decryptHandle,
off64_t offset, int whence) {
#else
-off_t FwdLockEngine::onLseek(int uniqueId, DecryptHandle* decryptHandle,
+off_t FwdLockEngine::onLseek(int /* uniqueId */, DecryptHandle* decryptHandle,
off_t offset, int whence) {
#endif
off_t offval = -1;
diff --git a/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
index 53cbf80..ee97976 100644
--- a/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
@@ -33,7 +33,7 @@
// decrypted data. In theory, the output size can be larger than the input
// size, but in practice this will never happen for AES-CTR.
ssize_t CryptoPlugin::decrypt(bool secure, const KeyId keyId, const Iv iv,
- Mode mode, const void* srcPtr,
+ Mode mode, const Pattern &/* pattern */, const void* srcPtr,
const SubSample* subSamples, size_t numSubSamples,
void* dstPtr, AString* errorDetailMsg) {
if (secure) {
diff --git a/drm/mediadrm/plugins/clearkey/CryptoPlugin.h b/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
index fd38f28..de84c36 100644
--- a/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
@@ -44,7 +44,7 @@
virtual ssize_t decrypt(
bool secure, const KeyId keyId, const Iv iv,
- Mode mode, const void* srcPtr,
+ Mode mode, const Pattern &pattern, const void* srcPtr,
const SubSample* subSamples, size_t numSubSamples,
void* dstPtr, android::AString* errorDetailMsg);
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index ba4aefe..9095045 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -105,10 +105,6 @@
return android::ERROR_DRM_CANNOT_HANDLE;
}
- virtual status_t unprovisionDevice() {
- return android::ERROR_DRM_CANNOT_HANDLE;
- }
-
virtual status_t getSecureStops(List<Vector<uint8_t> >& secureStops) {
UNUSED(secureStops);
return android::ERROR_DRM_CANNOT_HANDLE;
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
index 851ad2c..1e80f8e 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
@@ -312,12 +312,6 @@
return OK;
}
- status_t MockDrmPlugin::unprovisionDevice()
- {
- ALOGD("MockDrmPlugin::unprovisionDevice()");
- return OK;
- }
-
status_t MockDrmPlugin::getSecureStop(Vector<uint8_t> const & /* ssid */,
Vector<uint8_t> & secureStop)
{
@@ -798,15 +792,17 @@
ssize_t
MockCryptoPlugin::decrypt(bool secure, const uint8_t key[16], const uint8_t iv[16],
- Mode mode, const void *srcPtr, const SubSample *subSamples,
- size_t numSubSamples, void *dstPtr, AString * /* errorDetailMsg */)
+ Mode mode, const Pattern &pattern, const void *srcPtr,
+ const SubSample *subSamples, size_t numSubSamples,
+ void *dstPtr, AString * /* errorDetailMsg */)
{
- ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, src=%p, "
+ ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, "
+ "pattern:{encryptBlocks=%d, skipBlocks=%d} src=%p, "
"subSamples=%s, dst=%p)",
(int)secure,
arrayToString(key, sizeof(key)).string(),
arrayToString(iv, sizeof(iv)).string(),
- (int)mode, srcPtr,
+ (int)mode, pattern.mEncryptBlocks, pattern.mSkipBlocks, srcPtr,
subSamplesToString(subSamples, numSubSamples).string(),
dstPtr);
return OK;
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
index d0f2ddb..40d4e84 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
@@ -86,8 +86,6 @@
Vector<uint8_t> &certificate,
Vector<uint8_t> &wrappedKey);
- status_t unprovisionDevice();
-
status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
@@ -161,7 +159,7 @@
ssize_t decrypt(bool secure,
const uint8_t key[16], const uint8_t iv[16],
- Mode mode, const void *srcPtr,
+ Mode mode, const Pattern &pattern, const void *srcPtr,
const SubSample *subSamples, size_t numSubSamples,
void *dstPtr, AString *errorDetailMsg);
private:
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 2b60842..f19d296 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -52,7 +52,7 @@
typedef ICamera TCamUser;
typedef ICameraClient TCamCallbacks;
typedef status_t (ICameraService::*TCamConnectService)(const sp<ICameraClient>&,
- int, const String16&, int,
+ int, const String16&, int, int,
/*out*/
sp<ICamera>&);
static TCamConnectService fnConnectService;
@@ -67,12 +67,15 @@
enum {
USE_CALLING_UID = ICameraService::USE_CALLING_UID
};
+ enum {
+ USE_CALLING_PID = ICameraService::USE_CALLING_PID
+ };
// construct a camera client from an existing remote
static sp<Camera> create(const sp<ICamera>& camera);
static sp<Camera> connect(int cameraId,
const String16& clientPackageName,
- int clientUid);
+ int clientUid, int clientPid);
static status_t connectLegacy(int cameraId, int halVersion,
const String16& clientPackageName,
@@ -126,8 +129,15 @@
// send command to camera driver
status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
- // tell camera hal to store meta data or real YUV in video buffers.
- status_t storeMetaDataInBuffers(bool enabled);
+ // Tell camera how to pass video buffers. videoBufferMode is one of VIDEO_BUFFER_MODE_*.
+ // Returns OK if the specified video buffer mode is supported. If videoBufferMode is
+ // VIDEO_BUFFER_MODE_BUFFER_QUEUE, setVideoTarget() must be called before starting
+ // video recording.
+ status_t setVideoBufferMode(int32_t videoBufferMode);
+
+ // Set the video buffer producer for camera to use in VIDEO_BUFFER_MODE_BUFFER_QUEUE
+ // mode.
+ status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
void setListener(const sp<CameraListener>& listener);
void setRecordingProxyListener(const sp<ICameraRecordingProxyListener>& listener);
diff --git a/include/camera/CameraBase.h b/include/camera/CameraBase.h
index 1b93157..d8561ed 100644
--- a/include/camera/CameraBase.h
+++ b/include/camera/CameraBase.h
@@ -61,7 +61,7 @@
static sp<TCam> connect(int cameraId,
const String16& clientPackageName,
- int clientUid);
+ int clientUid, int clientPid);
virtual void disconnect();
void setListener(const sp<TCamListener>& listener);
diff --git a/include/camera/CameraUtils.h b/include/camera/CameraUtils.h
index c06f05d..f596f80 100644
--- a/include/camera/CameraUtils.h
+++ b/include/camera/CameraUtils.h
@@ -17,8 +17,10 @@
#ifndef ANDROID_CAMERA_CLIENT_CAMERAUTILS_H
#define ANDROID_CAMERA_CLIENT_CAMERAUTILS_H
+#include <binder/IMemory.h>
#include <camera/CameraMetadata.h>
#include <utils/Errors.h>
+#include <utils/RefBase.h>
#include <stdint.h>
@@ -39,6 +41,12 @@
*/
static status_t getRotationTransform(const CameraMetadata& staticInfo,
/*out*/int32_t* transform);
+
+ /**
+ * Check if the image data is VideoNativeHandleMetadata, that contains a native handle.
+ */
+ static bool isNativeHandleMetadata(const sp<IMemory>& imageData);
+
private:
CameraUtils();
};
diff --git a/include/camera/ICamera.h b/include/camera/ICamera.h
index b025735..e35c3a4 100644
--- a/include/camera/ICamera.h
+++ b/include/camera/ICamera.h
@@ -36,6 +36,15 @@
* Keep up-to-date with ICamera.aidl in frameworks/base
*/
public:
+ enum {
+ // Pass real YUV data in video buffers through ICameraClient.dataCallbackTimestamp().
+ VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV = 0,
+ // Pass metadata in video buffers through ICameraClient.dataCallbackTimestamp().
+ VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA = 1,
+ // Pass video buffers through IGraphicBufferProducer set with setVideoTarget().
+ VIDEO_BUFFER_MODE_BUFFER_QUEUE = 2,
+ };
+
DECLARE_META_INTERFACE(Camera);
virtual void disconnect() = 0;
@@ -109,8 +118,16 @@
// send command to camera driver
virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
- // tell the camera hal to store meta data or real YUV data in video buffers.
- virtual status_t storeMetaDataInBuffers(bool enabled) = 0;
+
+ // Tell camera how to pass video buffers. videoBufferMode is one of VIDEO_BUFFER_MODE_*.
+ // Returns OK if the specified video buffer mode is supported. If videoBufferMode is
+ // VIDEO_BUFFER_MODE_BUFFER_QUEUE, setVideoTarget() must be called before starting video
+ // recording.
+ virtual status_t setVideoBufferMode(int32_t videoBufferMode) = 0;
+
+ // Set the video buffer producer for camera to use in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
+ virtual status_t setVideoTarget(
+ const sp<IGraphicBufferProducer>& bufferProducer) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index 1b68b5f..d568b4d 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -55,6 +55,10 @@
};
enum {
+ USE_CALLING_PID = -1
+ };
+
+ enum {
USE_CALLING_UID = -1
};
@@ -113,14 +117,17 @@
virtual status_t removeListener(const sp<ICameraServiceListener>& listener)
= 0;
/**
- * clientPackageName and clientUid are used for permissions checking. if
- * clientUid == USE_CALLING_UID, then the calling UID is used instead. Only
- * trusted callers can set a clientUid other than USE_CALLING_UID.
+ * clientPackageName, clientUid, and clientPid are used for permissions checking. If
+ * clientUid == USE_CALLING_UID, then the calling UID is used instead. If
+ * clientPid == USE_CALLING_PID, then the calling PID is used instead. Only
+ * trusted callers can set a clientUid and clientPid other than USE_CALLING_UID and
+ * USE_CALLING_UID respectively.
*/
virtual status_t connect(const sp<ICameraClient>& cameraClient,
int cameraId,
const String16& clientPackageName,
int clientUid,
+ int clientPid,
/*out*/
sp<ICamera>& device) = 0;
diff --git a/include/camera/camera2/CaptureRequest.h b/include/camera/camera2/CaptureRequest.h
index eeab217..1dd15c4 100644
--- a/include/camera/camera2/CaptureRequest.h
+++ b/include/camera/camera2/CaptureRequest.h
@@ -25,7 +25,7 @@
class Surface;
-struct CaptureRequest : public virtual RefBase {
+struct CaptureRequest : public RefBase {
public:
CameraMetadata mMetadata;
diff --git a/include/camera/camera2/OutputConfiguration.h b/include/camera/camera2/OutputConfiguration.h
index 5bcbe15..137d98c 100644
--- a/include/camera/camera2/OutputConfiguration.h
+++ b/include/camera/camera2/OutputConfiguration.h
@@ -17,19 +17,20 @@
#ifndef ANDROID_HARDWARE_CAMERA2_OUTPUTCONFIGURATION_H
#define ANDROID_HARDWARE_CAMERA2_OUTPUTCONFIGURATION_H
-#include <utils/RefBase.h>
#include <gui/IGraphicBufferProducer.h>
namespace android {
class Surface;
-class OutputConfiguration : public virtual RefBase {
+class OutputConfiguration {
public:
static const int INVALID_ROTATION;
+ static const int INVALID_SET_ID;
sp<IGraphicBufferProducer> getGraphicBufferProducer() const;
int getRotation() const;
+ int getSurfaceSetID() const;
/**
* Keep impl up-to-date with OutputConfiguration.java in frameworks/base
@@ -39,12 +40,29 @@
// getRotation will be INVALID_ROTATION if error occurred
OutputConfiguration(const Parcel& parcel);
- OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation);
+ OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
+ int surfaceSetID = INVALID_SET_ID);
+
+ bool operator == (const OutputConfiguration& other) const {
+ return (mGbp == other.mGbp &&
+ mRotation == other.mRotation);
+ }
+ bool operator != (const OutputConfiguration& other) const {
+ return !(*this == other);
+ }
+ bool operator < (const OutputConfiguration& other) const {
+ if (*this == other) return false;
+ if (mGbp != other.mGbp) return mGbp < other.mGbp;
+ return mRotation < other.mRotation;
+ }
+ bool operator > (const OutputConfiguration& other) const {
+ return (*this != other && !(*this < other));
+ }
private:
sp<IGraphicBufferProducer> mGbp;
int mRotation;
-
+ int mSurfaceSetID;
// helper function
static String16 readMaybeEmptyString16(const Parcel& parcel);
};
diff --git a/include/camera/ndk/NdkCameraCaptureSession.h b/include/camera/ndk/NdkCameraCaptureSession.h
new file mode 100644
index 0000000..5d5cae2
--- /dev/null
+++ b/include/camera/ndk/NdkCameraCaptureSession.h
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+#include "NdkCameraError.h"
+#include "NdkCameraMetadata.h"
+
+#ifndef _NDK_CAMERA_CAPTURE_SESSION_H
+#define _NDK_CAMERA_CAPTURE_SESSION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ACameraCaptureSession ACameraCaptureSession;
+
+typedef void (*ACameraCaptureSession_stateCallback)(void* context, ACameraCaptureSession *session);
+
+typedef struct ACameraCaptureSession_stateCallbacks {
+ void* context;
+ ACameraCaptureSession_stateCallback onClosed; // session is unusable after this callback
+ ACameraCaptureSession_stateCallback onReady;
+ ACameraCaptureSession_stateCallback onActive;
+} ACameraCaptureSession_stateCallbacks;
+
+enum {
+ CAPTURE_FAILURE_REASON_FLUSHED = 0,
+ CAPTURE_FAILURE_REASON_ERROR
+};
+
+typedef struct ACameraCaptureFailure {
+ int64_t frameNumber;
+ int reason;
+ int sequenceId;
+ bool wasImageCaptured;
+} ACameraCaptureFailure;
+
+/* Note that the ACaptureRequest* in the callback will be different to what app has submitted,
+ but the contents will still be the same as what app submitted */
+typedef void (*ACameraCaptureSession_captureCallback_start)(
+ void* context, ACameraCaptureSession* session,
+ const ACaptureRequest* request, int64_t timestamp);
+
+typedef void (*ACameraCaptureSession_captureCallback_result)(
+ void* context, ACameraCaptureSession* session,
+ ACaptureRequest* request, const ACameraMetadata* result);
+
+typedef void (*ACameraCaptureSession_captureCallback_failed)(
+ void* context, ACameraCaptureSession* session,
+ ACaptureRequest* request, ACameraCaptureFailure* failure);
+
+typedef void (*ACameraCaptureSession_captureCallback_sequenceEnd)(
+ void* context, ACameraCaptureSession* session,
+ int sequenceId, int64_t frameNumber);
+
+typedef void (*ACameraCaptureSession_captureCallback_sequenceAbort)(
+ void* context, ACameraCaptureSession* session,
+ int sequenceId);
+
+typedef struct ACameraCaptureSession_captureCallbacks {
+ void* context;
+ ACameraCaptureSession_captureCallback_start onCaptureStarted;
+ ACameraCaptureSession_captureCallback_result onCaptureProgressed;
+ ACameraCaptureSession_captureCallback_result onCaptureCompleted;
+ ACameraCaptureSession_captureCallback_failed onCaptureFailed;
+ ACameraCaptureSession_captureCallback_sequenceEnd onCaptureSequenceCompleted;
+ ACameraCaptureSession_captureCallback_sequenceAbort onCaptureSequenceAborted;
+} ACameraCaptureSession_captureCallbacks;
+
+enum {
+ CAPTURE_SEQUENCE_ID_NONE = -1
+};
+
+/*
+ * Close capture session
+ */
+void ACameraCaptureSession_close(ACameraCaptureSession*);
+
+struct ACameraDevice;
+typedef struct ACameraDevice ACameraDevice;
+
+/**
+ * Get the camera device associated with this capture session
+ */
+camera_status_t ACameraCaptureSession_getDevice(
+ ACameraCaptureSession*, ACameraDevice** device);
+
+/**
+ * Send capture request(s)
+ */
+camera_status_t ACameraCaptureSession_capture(
+ ACameraCaptureSession*, /*optional*/ACameraCaptureSession_captureCallbacks*,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId);
+
+/**
+ * Send repeating capture request(s)
+ */
+camera_status_t ACameraCaptureSession_setRepeatingRequest(
+ ACameraCaptureSession*, /*optional*/ACameraCaptureSession_captureCallbacks*,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId);
+
+/**
+ * Stop repeating capture request(s)
+ */
+camera_status_t ACameraCaptureSession_stopRepeating(ACameraCaptureSession*);
+
+/**
+ * Stop all capture requests as soon as possible
+ */
+camera_status_t ACameraCaptureSession_abortCaptures(ACameraCaptureSession*);
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _NDK_CAMERA_CAPTURE_SESSION_H
diff --git a/include/camera/ndk/NdkCameraDevice.h b/include/camera/ndk/NdkCameraDevice.h
new file mode 100644
index 0000000..2008a68
--- /dev/null
+++ b/include/camera/ndk/NdkCameraDevice.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#include <android/native_window.h>
+#include "NdkCameraError.h"
+#include "NdkCaptureRequest.h"
+#include "NdkCameraCaptureSession.h"
+
+#ifndef _NDK_CAMERA_DEVICE_H
+#define _NDK_CAMERA_DEVICE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ACameraDevice ACameraDevice;
+
+// Struct to hold camera state callbacks
+typedef void (*ACameraDevice_StateCallback)(void* context, ACameraDevice* device);
+typedef void (*ACameraDevice_ErrorStateCallback)(void* context, ACameraDevice* device, int error);
+
+typedef struct ACameraDevice_StateCallbacks {
+ void* context;
+ ACameraDevice_StateCallback onDisconnected; // Device is unusable after this callback
+ ACameraDevice_ErrorStateCallback onError; // Device is unusable after this callback
+} ACameraDevice_stateCallbacks;
+
+/**
+ * Close the camera device synchronously. Open is done in ACameraManager_openCamera
+ */
+camera_status_t ACameraDevice_close(ACameraDevice*);
+
+/**
+ * Return the camera id associated with this camera device
+ * The returned pointer is still owned by framework and should not be delete/free by app
+ * The returned pointer should not be used after the device has been closed
+ */
+const char* ACameraDevice_getId(const ACameraDevice*);
+
+typedef enum {
+ TEMPLATE_PREVIEW = 1,
+ TEMPLATE_STILL_CAPTURE,
+ TEMPLATE_RECORD,
+ TEMPLATE_VIDEO_SNAPSHOT,
+ TEMPLATE_ZERO_SHUTTER_LAG,
+ TEMPLATE_MANUAL,
+} ACameraDevice_request_template;
+
+/**
+ * Create/free a default capture request for input template
+ */
+camera_status_t ACameraDevice_createCaptureRequest(
+ const ACameraDevice*, ACameraDevice_request_template, /*out*/ACaptureRequest** request);
+
+/**
+ * APIs for createing capture session
+ */
+typedef struct ACaptureSessionOutputContainer ACaptureSessionOutputContainer;
+
+typedef struct ACaptureSessionOutput ACaptureSessionOutput;
+
+camera_status_t ACaptureSessionOutputContainer_create(/*out*/ACaptureSessionOutputContainer**);
+void ACaptureSessionOutputContainer_free(ACaptureSessionOutputContainer*);
+
+camera_status_t ACaptureSessionOutput_create(ANativeWindow*, /*out*/ACaptureSessionOutput**);
+void ACaptureSessionOutput_free(ACaptureSessionOutput*);
+
+camera_status_t ACaptureSessionOutputContainer_add(
+ ACaptureSessionOutputContainer*, const ACaptureSessionOutput*);
+camera_status_t ACaptureSessionOutputContainer_remove(
+ ACaptureSessionOutputContainer*, const ACaptureSessionOutput*);
+
+/*
+ * Create a new capture session.
+ * If there is a preexisting session, the previous session will be closed automatically.
+ * However, app still needs to call ACameraCaptureSession_close on previous session.
+ * Otherwise the resources hold by previous session won't be freed
+ */
+camera_status_t ACameraDevice_createCaptureSession(
+ ACameraDevice*,
+ const ACaptureSessionOutputContainer* outputs,
+ const ACameraCaptureSession_stateCallbacks* callbacks,
+ /*out*/ACameraCaptureSession** session);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _NDK_CAMERA_DEVICE_H
diff --git a/include/camera/ndk/NdkCameraError.h b/include/camera/ndk/NdkCameraError.h
new file mode 100644
index 0000000..6d671de
--- /dev/null
+++ b/include/camera/ndk/NdkCameraError.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_CAMERA_ERROR_H
+#define _NDK_CAMERA_ERROR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ ACAMERA_OK = 0,
+
+ ACAMERA_ERROR_BASE = -10000,
+ ACAMERA_ERROR_UNKNOWN = ACAMERA_ERROR_BASE,
+ ACAMERA_ERROR_UNSUPPORTED = ACAMERA_ERROR_BASE - 1,
+ ACAMERA_ERROR_INVALID_PARAMETER = ACAMERA_ERROR_BASE - 2,
+ ACAMERA_ERROR_CAMERA_DISCONNECTED = ACAMERA_ERROR_BASE - 3,
+ ACAMERA_ERROR_NOT_ENOUGH_MEMORY = ACAMERA_ERROR_BASE - 4,
+ ACAMERA_ERROR_METADATA_NOT_FOUND = ACAMERA_ERROR_BASE - 5,
+ ACAMERA_ERROR_CAMERA_DEVICE = ACAMERA_ERROR_BASE - 6,
+ ACAMERA_ERROR_CAMERA_SERVICE = ACAMERA_ERROR_BASE - 7,
+ ACAMERA_ERROR_CAMERA_REQUEST = ACAMERA_ERROR_BASE - 8,
+ ACAMERA_ERROR_CAMERA_RESULT = ACAMERA_ERROR_BASE - 9,
+ ACAMERA_ERROR_CAMERA_BUFFER = ACAMERA_ERROR_BASE - 10,
+ ACAMERA_ERROR_SESSION_CLOSED = ACAMERA_ERROR_BASE - 11,
+ ACAMERA_ERROR_SESSION_NOT_DRAINED = ACAMERA_ERROR_BASE - 12,
+ ACAMERA_ERROR_INVALID_OPERATION = ACAMERA_ERROR_BASE - 13,
+ ACAMERA_ERROR_TIMEOUT = ACAMERA_ERROR_BASE - 14,
+ ACAMERA_ERROR_STREAM_CONFIGURE_FAIL = ACAMERA_ERROR_BASE - 15,
+} camera_status_t;
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _NDK_CAMERA_ERROR_H
diff --git a/include/camera/ndk/NdkCameraManager.h b/include/camera/ndk/NdkCameraManager.h
new file mode 100644
index 0000000..adef6ed
--- /dev/null
+++ b/include/camera/ndk/NdkCameraManager.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_CAMERA_MANAGER_H
+#define _NDK_CAMERA_MANAGER_H
+
+#include "NdkCameraError.h"
+#include "NdkCameraMetadata.h"
+#include "NdkCameraDevice.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ACameraManager ACameraManager;
+
+/**
+ * Create CameraManager instance.
+ * The caller must call ACameraManager_delete to free the resources
+ */
+ACameraManager* ACameraManager_create();
+
+/**
+ * delete the ACameraManager and free its resources
+ */
+void ACameraManager_delete(ACameraManager*);
+
+// Struct to hold list of camera devices
+typedef struct ACameraIdList {
+ int numCameras;
+ const char** cameraIds;
+} ACameraIdList;
+
+/**
+ * Create/delete a list of camera devices.
+ * ACameraManager_getCameraIdList will allocate and return an ACameraIdList.
+ * The caller must call ACameraManager_deleteCameraIdList to free the memory
+ */
+camera_status_t ACameraManager_getCameraIdList(ACameraManager*,
+ /*out*/ACameraIdList** cameraIdList);
+void ACameraManager_deleteCameraIdList(ACameraIdList* cameraIdList);
+
+
+// Struct to hold camera availability callbacks
+typedef void (*ACameraManager_AvailabilityCallback)(void* context, const char* cameraId);
+
+typedef struct ACameraManager_AvailabilityListener {
+ void* context; // optional application context.
+ ACameraManager_AvailabilityCallback onCameraAvailable;
+ ACameraManager_AvailabilityCallback onCameraUnavailable;
+} ACameraManager_AvailabilityCallbacks;
+
+/**
+ * register/unregister camera availability callbacks
+ */
+camera_status_t ACameraManager_registerAvailabilityCallback(
+ ACameraManager*, const ACameraManager_AvailabilityCallbacks *callback);
+camera_status_t ACameraManager_unregisterAvailabilityCallback(
+ ACameraManager*, const ACameraManager_AvailabilityCallbacks *callback);
+
+/**
+ * Query the characteristics of a camera.
+ * The caller must call ACameraMetadata_free to free the memory of the output characteristics.
+ */
+camera_status_t ACameraManager_getCameraCharacteristics(
+ ACameraManager*, const char *cameraId,
+ /*out*/ACameraMetadata **characteristics);
+
+/**
+ * Open a camera device synchronously.
+ * The opened camera device will be returned in
+ */
+camera_status_t ACameraManager_openCamera(
+ ACameraManager*, const char* cameraId,
+ ACameraDevice_StateCallbacks* callback,
+ /*out*/ACameraDevice** device);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif //_NDK_CAMERA_MANAGER_H
diff --git a/include/camera/ndk/NdkCameraMetadata.h b/include/camera/ndk/NdkCameraMetadata.h
new file mode 100644
index 0000000..56412ad
--- /dev/null
+++ b/include/camera/ndk/NdkCameraMetadata.h
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_CAMERA_METADATA_H
+#define _NDK_CAMERA_METADATA_H
+
+#include "NdkCameraError.h"
+#include "NdkCameraMetadataTags.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ACameraMetadata ACameraMetadata;
+
+// Keep in sync with system/media/include/system/camera_metadata.h
+enum {
+ // Unsigned 8-bit integer (uint8_t)
+ ACAMERA_TYPE_BYTE = 0,
+ // Signed 32-bit integer (int32_t)
+ ACAMERA_TYPE_INT32 = 1,
+ // 32-bit float (float)
+ ACAMERA_TYPE_FLOAT = 2,
+ // Signed 64-bit integer (int64_t)
+ ACAMERA_TYPE_INT64 = 3,
+ // 64-bit float (double)
+ ACAMERA_TYPE_DOUBLE = 4,
+ // A 64-bit fraction (ACameraMetadata_rational)
+ ACAMERA_TYPE_RATIONAL = 5,
+ // Number of type fields
+ ACAMERA_NUM_TYPES
+};
+
+typedef struct ACameraMetadata_rational {
+ int32_t numerator;
+ int32_t denominator;
+} ACameraMetadata_rational;
+
+typedef struct ACameraMetadata_entry {
+ uint32_t tag;
+ uint8_t type;
+ uint32_t count;
+ union {
+ uint8_t *u8;
+ int32_t *i32;
+ float *f;
+ int64_t *i64;
+ double *d;
+ ACameraMetadata_rational* r;
+ } data;
+} ACameraMetadata_entry;
+
+typedef struct ACameraMetadata_const_entry {
+ uint32_t tag;
+ uint8_t type;
+ uint32_t count;
+ union {
+ const uint8_t *u8;
+ const int32_t *i32;
+ const float *f;
+ const int64_t *i64;
+ const double *d;
+ const ACameraMetadata_rational* r;
+ } data;
+} ACameraMetadata_const_entry;
+
+/*
+ * Get a metadata entry
+ */
+camera_status_t ACameraMetadata_getConstEntry(
+ const ACameraMetadata*, uint32_t tag, ACameraMetadata_const_entry* entry);
+
+// TODO: need an API to list all tags in the metadata. Same for ACaptureRequest
+
+/**
+ * Copy a metadata. Duplicates a metadata structure.
+ * The destination ACameraMetadata must be freed by the application with ACameraMetadata_free
+ * after application is done using it.
+ * Returns NULL when src cannot be copied
+ */
+ACameraMetadata* ACameraMetadata_copy(const ACameraMetadata* src);
+
+/**
+ * Frees a metadata structure.
+ */
+void ACameraMetadata_free(ACameraMetadata*);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif //_NDK_CAMERA_METADATA_H
diff --git a/include/camera/ndk/NdkCameraMetadataTags.h b/include/camera/ndk/NdkCameraMetadataTags.h
new file mode 100644
index 0000000..0c398be
--- /dev/null
+++ b/include/camera/ndk/NdkCameraMetadataTags.h
@@ -0,0 +1,877 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_CAMERA_METADATA_TAGS_H
+#define _NDK_CAMERA_METADATA_TAGS_H
+
+typedef enum acamera_metadata_section {
+ ACAMERA_COLOR_CORRECTION,
+ ACAMERA_CONTROL,
+ ACAMERA_DEMOSAIC,
+ ACAMERA_EDGE,
+ ACAMERA_FLASH,
+ ACAMERA_FLASH_INFO,
+ ACAMERA_HOT_PIXEL,
+ ACAMERA_JPEG,
+ ACAMERA_LENS,
+ ACAMERA_LENS_INFO,
+ ACAMERA_NOISE_REDUCTION,
+ ACAMERA_QUIRKS,
+ ACAMERA_REQUEST,
+ ACAMERA_SCALER,
+ ACAMERA_SENSOR,
+ ACAMERA_SENSOR_INFO,
+ ACAMERA_SHADING,
+ ACAMERA_STATISTICS,
+ ACAMERA_STATISTICS_INFO,
+ ACAMERA_TONEMAP,
+ ACAMERA_LED,
+ ACAMERA_INFO,
+ ACAMERA_BLACK_LEVEL,
+ ACAMERA_SYNC,
+ ACAMERA_REPROCESS,
+ ACAMERA_DEPTH,
+ ACAMERA_SECTION_COUNT,
+
+ ACAMERA_VENDOR = 0x8000
+} acamera_metadata_section_t;
+
+/**
+ * Hierarchy positions in enum space.
+ */
+typedef enum acamera_metadata_section_start {
+ ACAMERA_COLOR_CORRECTION_START = ACAMERA_COLOR_CORRECTION << 16,
+ ACAMERA_CONTROL_START = ACAMERA_CONTROL << 16,
+ ACAMERA_DEMOSAIC_START = ACAMERA_DEMOSAIC << 16,
+ ACAMERA_EDGE_START = ACAMERA_EDGE << 16,
+ ACAMERA_FLASH_START = ACAMERA_FLASH << 16,
+ ACAMERA_FLASH_INFO_START = ACAMERA_FLASH_INFO << 16,
+ ACAMERA_HOT_PIXEL_START = ACAMERA_HOT_PIXEL << 16,
+ ACAMERA_JPEG_START = ACAMERA_JPEG << 16,
+ ACAMERA_LENS_START = ACAMERA_LENS << 16,
+ ACAMERA_LENS_INFO_START = ACAMERA_LENS_INFO << 16,
+ ACAMERA_NOISE_REDUCTION_START = ACAMERA_NOISE_REDUCTION << 16,
+ ACAMERA_QUIRKS_START = ACAMERA_QUIRKS << 16,
+ ACAMERA_REQUEST_START = ACAMERA_REQUEST << 16,
+ ACAMERA_SCALER_START = ACAMERA_SCALER << 16,
+ ACAMERA_SENSOR_START = ACAMERA_SENSOR << 16,
+ ACAMERA_SENSOR_INFO_START = ACAMERA_SENSOR_INFO << 16,
+ ACAMERA_SHADING_START = ACAMERA_SHADING << 16,
+ ACAMERA_STATISTICS_START = ACAMERA_STATISTICS << 16,
+ ACAMERA_STATISTICS_INFO_START = ACAMERA_STATISTICS_INFO << 16,
+ ACAMERA_TONEMAP_START = ACAMERA_TONEMAP << 16,
+ ACAMERA_LED_START = ACAMERA_LED << 16,
+ ACAMERA_INFO_START = ACAMERA_INFO << 16,
+ ACAMERA_BLACK_LEVEL_START = ACAMERA_BLACK_LEVEL << 16,
+ ACAMERA_SYNC_START = ACAMERA_SYNC << 16,
+ ACAMERA_REPROCESS_START = ACAMERA_REPROCESS << 16,
+ ACAMERA_DEPTH_START = ACAMERA_DEPTH << 16,
+ ACAMERA_VENDOR_START = ACAMERA_VENDOR << 16
+} acamera_metadata_section_start_t;
+
+/**
+ * Main enum for camera metadata tags.
+ */
+typedef enum acamera_metadata_tag {
+ ACAMERA_COLOR_CORRECTION_MODE = // byte (enum)
+ ACAMERA_COLOR_CORRECTION_START,
+ ACAMERA_COLOR_CORRECTION_TRANSFORM, // rational[3*3]
+ ACAMERA_COLOR_CORRECTION_GAINS, // float[4]
+ ACAMERA_COLOR_CORRECTION_ABERRATION_MODE, // byte (enum)
+ ACAMERA_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES, // byte[n]
+ ACAMERA_COLOR_CORRECTION_END,
+
+ ACAMERA_CONTROL_AE_ANTIBANDING_MODE = // byte (enum)
+ ACAMERA_CONTROL_START,
+ ACAMERA_CONTROL_AE_EXPOSURE_COMPENSATION, // int32
+ ACAMERA_CONTROL_AE_LOCK, // byte (enum)
+ ACAMERA_CONTROL_AE_MODE, // byte (enum)
+ ACAMERA_CONTROL_AE_REGIONS, // int32[5*area_count]
+ ACAMERA_CONTROL_AE_TARGET_FPS_RANGE, // int32[2]
+ ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER, // byte (enum)
+ ACAMERA_CONTROL_AF_MODE, // byte (enum)
+ ACAMERA_CONTROL_AF_REGIONS, // int32[5*area_count]
+ ACAMERA_CONTROL_AF_TRIGGER, // byte (enum)
+ ACAMERA_CONTROL_AWB_LOCK, // byte (enum)
+ ACAMERA_CONTROL_AWB_MODE, // byte (enum)
+ ACAMERA_CONTROL_AWB_REGIONS, // int32[5*area_count]
+ ACAMERA_CONTROL_CAPTURE_INTENT, // byte (enum)
+ ACAMERA_CONTROL_EFFECT_MODE, // byte (enum)
+ ACAMERA_CONTROL_MODE, // byte (enum)
+ ACAMERA_CONTROL_SCENE_MODE, // byte (enum)
+ ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE, // byte (enum)
+ ACAMERA_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, // byte[n]
+ ACAMERA_CONTROL_AE_AVAILABLE_MODES, // byte[n]
+ ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, // int32[2*n]
+ ACAMERA_CONTROL_AE_COMPENSATION_RANGE, // int32[2]
+ ACAMERA_CONTROL_AE_COMPENSATION_STEP, // rational
+ ACAMERA_CONTROL_AF_AVAILABLE_MODES, // byte[n]
+ ACAMERA_CONTROL_AVAILABLE_EFFECTS, // byte[n]
+ ACAMERA_CONTROL_AVAILABLE_SCENE_MODES, // byte[n]
+ ACAMERA_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, // byte[n]
+ ACAMERA_CONTROL_AWB_AVAILABLE_MODES, // byte[n]
+ ACAMERA_CONTROL_MAX_REGIONS, // int32[3]
+ ACAMERA_CONTROL_RESERVED_29,
+ ACAMERA_CONTROL_RESERVED_30,
+ ACAMERA_CONTROL_AE_STATE, // byte (enum)
+ ACAMERA_CONTROL_AF_STATE, // byte (enum)
+ ACAMERA_CONTROL_RESERVED_33,
+ ACAMERA_CONTROL_AWB_STATE, // byte (enum)
+ ACAMERA_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS, // int32[5*n]
+ ACAMERA_CONTROL_AE_LOCK_AVAILABLE, // byte (enum)
+ ACAMERA_CONTROL_AWB_LOCK_AVAILABLE, // byte (enum)
+ ACAMERA_CONTROL_AVAILABLE_MODES, // byte[n]
+ ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE, // int32[2]
+ ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST, // int32
+ ACAMERA_CONTROL_END,
+
+ ACAMERA_DEMOSAIC_RESERVED_0 =
+ ACAMERA_DEMOSAIC_START,
+ ACAMERA_DEMOSAIC_END,
+
+ ACAMERA_EDGE_MODE = // byte (enum)
+ ACAMERA_EDGE_START,
+ ACAMERA_EDGE_RESERVED_1,
+ ACAMERA_EDGE_AVAILABLE_EDGE_MODES, // byte[n]
+ ACAMERA_EDGE_END,
+
+ ACAMERA_FLASH_RESERVED_0 =
+ ACAMERA_FLASH_START,
+ ACAMERA_FLASH_RESERVED_1,
+ ACAMERA_FLASH_MODE, // byte (enum)
+ ACAMERA_FLASH_RESERVED_3,
+ ACAMERA_FLASH_RESERVED_4,
+ ACAMERA_FLASH_STATE, // byte (enum)
+ ACAMERA_FLASH_END,
+
+ ACAMERA_FLASH_INFO_AVAILABLE = // byte (enum)
+ ACAMERA_FLASH_INFO_START,
+ ACAMERA_FLASH_INFO_RESERVED_1,
+ ACAMERA_FLASH_INFO_END,
+
+ ACAMERA_HOT_PIXEL_MODE = // byte (enum)
+ ACAMERA_HOT_PIXEL_START,
+ ACAMERA_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, // byte[n]
+ ACAMERA_HOT_PIXEL_END,
+
+ ACAMERA_JPEG_GPS_COORDINATES = // double[3]
+ ACAMERA_JPEG_START,
+ ACAMERA_JPEG_GPS_PROCESSING_METHOD, // byte
+ ACAMERA_JPEG_GPS_TIMESTAMP, // int64
+ ACAMERA_JPEG_ORIENTATION, // int32
+ ACAMERA_JPEG_QUALITY, // byte
+ ACAMERA_JPEG_THUMBNAIL_QUALITY, // byte
+ ACAMERA_JPEG_THUMBNAIL_SIZE, // int32[2]
+ ACAMERA_JPEG_AVAILABLE_THUMBNAIL_SIZES, // int32[2*n]
+ ACAMERA_JPEG_RESERVED_8,
+ ACAMERA_JPEG_RESERVED_9,
+ ACAMERA_JPEG_END,
+
+ ACAMERA_LENS_APERTURE = // float
+ ACAMERA_LENS_START,
+ ACAMERA_LENS_FILTER_DENSITY, // float
+ ACAMERA_LENS_FOCAL_LENGTH, // float
+ ACAMERA_LENS_FOCUS_DISTANCE, // float
+ ACAMERA_LENS_OPTICAL_STABILIZATION_MODE, // byte (enum)
+ ACAMERA_LENS_FACING, // byte (enum)
+ ACAMERA_LENS_POSE_ROTATION, // float[4]
+ ACAMERA_LENS_POSE_TRANSLATION, // float[3]
+ ACAMERA_LENS_FOCUS_RANGE, // float[2]
+ ACAMERA_LENS_STATE, // byte (enum)
+ ACAMERA_LENS_INTRINSIC_CALIBRATION, // float[5]
+ ACAMERA_LENS_RADIAL_DISTORTION, // float[6]
+ ACAMERA_LENS_END,
+
+ ACAMERA_LENS_INFO_AVAILABLE_APERTURES = // float[n]
+ ACAMERA_LENS_INFO_START,
+ ACAMERA_LENS_INFO_AVAILABLE_FILTER_DENSITIES, // float[n]
+ ACAMERA_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, // float[n]
+ ACAMERA_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION, // byte[n]
+ ACAMERA_LENS_INFO_HYPERFOCAL_DISTANCE, // float
+ ACAMERA_LENS_INFO_MINIMUM_FOCUS_DISTANCE, // float
+ ACAMERA_LENS_INFO_SHADING_MAP_SIZE, // int32[2]
+ ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION, // byte (enum)
+ ACAMERA_LENS_INFO_END,
+
+ ACAMERA_NOISE_REDUCTION_MODE = // byte (enum)
+ ACAMERA_NOISE_REDUCTION_START,
+ ACAMERA_NOISE_REDUCTION_RESERVED_1,
+ ACAMERA_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES, // byte[n]
+ ACAMERA_NOISE_REDUCTION_END,
+
+ ACAMERA_QUIRKS_RESERVED_0 =
+ ACAMERA_QUIRKS_START,
+ ACAMERA_QUIRKS_RESERVED_1,
+ ACAMERA_QUIRKS_RESERVED_2,
+ ACAMERA_QUIRKS_USE_PARTIAL_RESULT, // Deprecated! DO NOT USE
+ ACAMERA_QUIRKS_PARTIAL_RESULT, // Deprecated! DO NOT USE
+ ACAMERA_QUIRKS_END,
+
+ ACAMERA_REQUEST_FRAME_COUNT = // Deprecated! DO NOT USE
+ ACAMERA_REQUEST_START,
+ ACAMERA_REQUEST_ID, // int32
+ ACAMERA_REQUEST_RESERVED_2,
+ ACAMERA_REQUEST_RESERVED_3,
+ ACAMERA_REQUEST_RESERVED_4,
+ ACAMERA_REQUEST_RESERVED_5,
+ ACAMERA_REQUEST_MAX_NUM_OUTPUT_STREAMS, // int32[3]
+ ACAMERA_REQUEST_RESERVED_7,
+ ACAMERA_REQUEST_MAX_NUM_INPUT_STREAMS, // int32
+ ACAMERA_REQUEST_PIPELINE_DEPTH, // byte
+ ACAMERA_REQUEST_PIPELINE_MAX_DEPTH, // byte
+ ACAMERA_REQUEST_PARTIAL_RESULT_COUNT, // int32
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, // byte[n] (enum)
+ ACAMERA_REQUEST_AVAILABLE_REQUEST_KEYS, // int32[n]
+ ACAMERA_REQUEST_AVAILABLE_RESULT_KEYS, // int32[n]
+ ACAMERA_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, // int32[n]
+ ACAMERA_REQUEST_END,
+
+ ACAMERA_SCALER_CROP_REGION = // int32[4]
+ ACAMERA_SCALER_START,
+ ACAMERA_SCALER_AVAILABLE_FORMATS, // Deprecated! DO NOT USE
+ ACAMERA_SCALER_AVAILABLE_JPEG_MIN_DURATIONS, // Deprecated! DO NOT USE
+ ACAMERA_SCALER_AVAILABLE_JPEG_SIZES, // Deprecated! DO NOT USE
+ ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, // float
+ ACAMERA_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS, // Deprecated! DO NOT USE
+ ACAMERA_SCALER_AVAILABLE_PROCESSED_SIZES, // Deprecated! DO NOT USE
+ ACAMERA_SCALER_RESERVED_7,
+ ACAMERA_SCALER_RESERVED_8,
+ ACAMERA_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP, // int32
+ ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, // int32[n*4] (enum)
+ ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, // int64[4*n]
+ ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS, // int64[4*n]
+ ACAMERA_SCALER_CROPPING_TYPE, // byte (enum)
+ ACAMERA_SCALER_END,
+
+ ACAMERA_SENSOR_EXPOSURE_TIME = // int64
+ ACAMERA_SENSOR_START,
+ ACAMERA_SENSOR_FRAME_DURATION, // int64
+ ACAMERA_SENSOR_SENSITIVITY, // int32
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1, // byte (enum)
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT2, // byte
+ ACAMERA_SENSOR_CALIBRATION_TRANSFORM1, // rational[3*3]
+ ACAMERA_SENSOR_CALIBRATION_TRANSFORM2, // rational[3*3]
+ ACAMERA_SENSOR_COLOR_TRANSFORM1, // rational[3*3]
+ ACAMERA_SENSOR_COLOR_TRANSFORM2, // rational[3*3]
+ ACAMERA_SENSOR_FORWARD_MATRIX1, // rational[3*3]
+ ACAMERA_SENSOR_FORWARD_MATRIX2, // rational[3*3]
+ ACAMERA_SENSOR_RESERVED_11,
+ ACAMERA_SENSOR_BLACK_LEVEL_PATTERN, // int32[4]
+ ACAMERA_SENSOR_MAX_ANALOG_SENSITIVITY, // int32
+ ACAMERA_SENSOR_ORIENTATION, // int32
+ ACAMERA_SENSOR_RESERVED_15,
+ ACAMERA_SENSOR_TIMESTAMP, // int64
+ ACAMERA_SENSOR_RESERVED_17,
+ ACAMERA_SENSOR_NEUTRAL_COLOR_POINT, // rational[3]
+ ACAMERA_SENSOR_NOISE_PROFILE, // double[2*CFA Channels]
+ ACAMERA_SENSOR_RESERVED_20,
+ ACAMERA_SENSOR_RESERVED_21,
+ ACAMERA_SENSOR_GREEN_SPLIT, // float
+ ACAMERA_SENSOR_TEST_PATTERN_DATA, // int32[4]
+ ACAMERA_SENSOR_TEST_PATTERN_MODE, // int32 (enum)
+ ACAMERA_SENSOR_AVAILABLE_TEST_PATTERN_MODES, // int32[n]
+ ACAMERA_SENSOR_ROLLING_SHUTTER_SKEW, // int64
+ ACAMERA_SENSOR_OPTICAL_BLACK_REGIONS, // int32[4*num_regions]
+ ACAMERA_SENSOR_DYNAMIC_BLACK_LEVEL, // float[4]
+ ACAMERA_SENSOR_DYNAMIC_WHITE_LEVEL, // int32
+ ACAMERA_SENSOR_RESERVED_30,
+ ACAMERA_SENSOR_END,
+
+ ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE = // int32[4]
+ ACAMERA_SENSOR_INFO_START,
+ ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE, // int32[2]
+ ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, // byte (enum)
+ ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE, // int64[2]
+ ACAMERA_SENSOR_INFO_MAX_FRAME_DURATION, // int64
+ ACAMERA_SENSOR_INFO_PHYSICAL_SIZE, // float[2]
+ ACAMERA_SENSOR_INFO_PIXEL_ARRAY_SIZE, // int32[2]
+ ACAMERA_SENSOR_INFO_WHITE_LEVEL, // int32
+ ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE, // byte (enum)
+ ACAMERA_SENSOR_INFO_LENS_SHADING_APPLIED, // byte (enum)
+ ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, // int32[4]
+ ACAMERA_SENSOR_INFO_END,
+
+ ACAMERA_SHADING_MODE = // byte (enum)
+ ACAMERA_SHADING_START,
+ ACAMERA_SHADING_RESERVED_1,
+ ACAMERA_SHADING_AVAILABLE_MODES, // byte[n]
+ ACAMERA_SHADING_END,
+
+ ACAMERA_STATISTICS_FACE_DETECT_MODE = // byte (enum)
+ ACAMERA_STATISTICS_START,
+ ACAMERA_STATISTICS_RESERVED_1,
+ ACAMERA_STATISTICS_RESERVED_2,
+ ACAMERA_STATISTICS_HOT_PIXEL_MAP_MODE, // byte (enum)
+ ACAMERA_STATISTICS_FACE_IDS, // int32[n]
+ ACAMERA_STATISTICS_FACE_LANDMARKS, // int32[n*6]
+ ACAMERA_STATISTICS_FACE_RECTANGLES, // int32[n*4]
+ ACAMERA_STATISTICS_FACE_SCORES, // byte[n]
+ ACAMERA_STATISTICS_RESERVED_8,
+ ACAMERA_STATISTICS_RESERVED_9,
+ ACAMERA_STATISTICS_LENS_SHADING_CORRECTION_MAP, // byte
+ ACAMERA_STATISTICS_LENS_SHADING_MAP, // float[4*n*m]
+ ACAMERA_STATISTICS_PREDICTED_COLOR_GAINS, // Deprecated! DO NOT USE
+ ACAMERA_STATISTICS_PREDICTED_COLOR_TRANSFORM, // Deprecated! DO NOT USE
+ ACAMERA_STATISTICS_SCENE_FLICKER, // byte (enum)
+ ACAMERA_STATISTICS_HOT_PIXEL_MAP, // int32[2*n]
+ ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE, // byte (enum)
+ ACAMERA_STATISTICS_END,
+
+ ACAMERA_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES = // byte[n]
+ ACAMERA_STATISTICS_INFO_START,
+ ACAMERA_STATISTICS_INFO_RESERVED_1,
+ ACAMERA_STATISTICS_INFO_MAX_FACE_COUNT, // int32
+ ACAMERA_STATISTICS_INFO_RESERVED_3,
+ ACAMERA_STATISTICS_INFO_RESERVED_4,
+ ACAMERA_STATISTICS_INFO_RESERVED_5,
+ ACAMERA_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES, // byte[n]
+ ACAMERA_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, // byte[n]
+ ACAMERA_STATISTICS_INFO_END,
+
+ ACAMERA_TONEMAP_CURVE_BLUE = // float[n*2]
+ ACAMERA_TONEMAP_START,
+ ACAMERA_TONEMAP_CURVE_GREEN, // float[n*2]
+ ACAMERA_TONEMAP_CURVE_RED, // float[n*2]
+ ACAMERA_TONEMAP_MODE, // byte (enum)
+ ACAMERA_TONEMAP_MAX_CURVE_POINTS, // int32
+ ACAMERA_TONEMAP_AVAILABLE_TONE_MAP_MODES, // byte[n]
+ ACAMERA_TONEMAP_GAMMA, // float
+ ACAMERA_TONEMAP_PRESET_CURVE, // byte (enum)
+ ACAMERA_TONEMAP_END,
+
+ ACAMERA_LED_TRANSMIT = // byte (enum)
+ ACAMERA_LED_START,
+ ACAMERA_LED_AVAILABLE_LEDS, // byte[n] (enum)
+ ACAMERA_LED_END,
+
+ ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL = // byte (enum)
+ ACAMERA_INFO_START,
+ ACAMERA_INFO_END,
+
+ ACAMERA_BLACK_LEVEL_LOCK = // byte (enum)
+ ACAMERA_BLACK_LEVEL_START,
+ ACAMERA_BLACK_LEVEL_END,
+
+ ACAMERA_SYNC_FRAME_NUMBER = // int64 (enum)
+ ACAMERA_SYNC_START,
+ ACAMERA_SYNC_MAX_LATENCY, // int32 (enum)
+ ACAMERA_SYNC_END,
+
+ ACAMERA_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR = // float
+ ACAMERA_REPROCESS_START,
+ ACAMERA_REPROCESS_MAX_CAPTURE_STALL, // int32
+ ACAMERA_REPROCESS_END,
+
+ ACAMERA_DEPTH_RESERVED_0 =
+ ACAMERA_DEPTH_START,
+ ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, // int32[n*4] (enum)
+ ACAMERA_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS, // int64[4*n]
+ ACAMERA_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS, // int64[4*n]
+ ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE, // byte (enum)
+ ACAMERA_DEPTH_END,
+
+} acamera_metadata_tag_t;
+
+/**
+ * Enumeration definitions for the various entries that need them
+ */
+
+// ACAMERA_COLOR_CORRECTION_MODE
+typedef enum acamera_metadata_enum_acamera_color_correction_mode {
+ ACAMERA_COLOR_CORRECTION_MODE_TRANSFORM_MATRIX,
+ ACAMERA_COLOR_CORRECTION_MODE_FAST,
+ ACAMERA_COLOR_CORRECTION_MODE_HIGH_QUALITY,
+} acamera_metadata_enum_android_color_correction_mode_t;
+
+// ACAMERA_COLOR_CORRECTION_ABERRATION_MODE
+typedef enum acamera_metadata_enum_acamera_color_correction_aberration_mode {
+ ACAMERA_COLOR_CORRECTION_ABERRATION_MODE_OFF,
+ ACAMERA_COLOR_CORRECTION_ABERRATION_MODE_FAST,
+ ACAMERA_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY,
+} acamera_metadata_enum_android_color_correction_aberration_mode_t;
+
+
+// ACAMERA_CONTROL_AE_ANTIBANDING_MODE
+typedef enum acamera_metadata_enum_acamera_control_ae_antibanding_mode {
+ ACAMERA_CONTROL_AE_ANTIBANDING_MODE_OFF,
+ ACAMERA_CONTROL_AE_ANTIBANDING_MODE_50HZ,
+ ACAMERA_CONTROL_AE_ANTIBANDING_MODE_60HZ,
+ ACAMERA_CONTROL_AE_ANTIBANDING_MODE_AUTO,
+} acamera_metadata_enum_android_control_ae_antibanding_mode_t;
+
+// ACAMERA_CONTROL_AE_LOCK
+typedef enum acamera_metadata_enum_acamera_control_ae_lock {
+ ACAMERA_CONTROL_AE_LOCK_OFF,
+ ACAMERA_CONTROL_AE_LOCK_ON,
+} acamera_metadata_enum_android_control_ae_lock_t;
+
+// ACAMERA_CONTROL_AE_MODE
+typedef enum acamera_metadata_enum_acamera_control_ae_mode {
+ ACAMERA_CONTROL_AE_MODE_OFF,
+ ACAMERA_CONTROL_AE_MODE_ON,
+ ACAMERA_CONTROL_AE_MODE_ON_AUTO_FLASH,
+ ACAMERA_CONTROL_AE_MODE_ON_ALWAYS_FLASH,
+ ACAMERA_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE,
+} acamera_metadata_enum_android_control_ae_mode_t;
+
+// ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER
+typedef enum acamera_metadata_enum_acamera_control_ae_precapture_trigger {
+ ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE,
+ ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER_START,
+ ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL,
+} acamera_metadata_enum_android_control_ae_precapture_trigger_t;
+
+// ACAMERA_CONTROL_AF_MODE
+typedef enum acamera_metadata_enum_acamera_control_af_mode {
+ ACAMERA_CONTROL_AF_MODE_OFF,
+ ACAMERA_CONTROL_AF_MODE_AUTO,
+ ACAMERA_CONTROL_AF_MODE_MACRO,
+ ACAMERA_CONTROL_AF_MODE_CONTINUOUS_VIDEO,
+ ACAMERA_CONTROL_AF_MODE_CONTINUOUS_PICTURE,
+ ACAMERA_CONTROL_AF_MODE_EDOF,
+} acamera_metadata_enum_android_control_af_mode_t;
+
+// ACAMERA_CONTROL_AF_TRIGGER
+typedef enum acamera_metadata_enum_acamera_control_af_trigger {
+ ACAMERA_CONTROL_AF_TRIGGER_IDLE,
+ ACAMERA_CONTROL_AF_TRIGGER_START,
+ ACAMERA_CONTROL_AF_TRIGGER_CANCEL,
+} acamera_metadata_enum_android_control_af_trigger_t;
+
+// ACAMERA_CONTROL_AWB_LOCK
+typedef enum acamera_metadata_enum_acamera_control_awb_lock {
+ ACAMERA_CONTROL_AWB_LOCK_OFF,
+ ACAMERA_CONTROL_AWB_LOCK_ON,
+} acamera_metadata_enum_android_control_awb_lock_t;
+
+// ACAMERA_CONTROL_AWB_MODE
+typedef enum acamera_metadata_enum_acamera_control_awb_mode {
+ ACAMERA_CONTROL_AWB_MODE_OFF,
+ ACAMERA_CONTROL_AWB_MODE_AUTO,
+ ACAMERA_CONTROL_AWB_MODE_INCANDESCENT,
+ ACAMERA_CONTROL_AWB_MODE_FLUORESCENT,
+ ACAMERA_CONTROL_AWB_MODE_WARM_FLUORESCENT,
+ ACAMERA_CONTROL_AWB_MODE_DAYLIGHT,
+ ACAMERA_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT,
+ ACAMERA_CONTROL_AWB_MODE_TWILIGHT,
+ ACAMERA_CONTROL_AWB_MODE_SHADE,
+} acamera_metadata_enum_android_control_awb_mode_t;
+
+// ACAMERA_CONTROL_CAPTURE_INTENT
+typedef enum acamera_metadata_enum_acamera_control_capture_intent {
+ ACAMERA_CONTROL_CAPTURE_INTENT_CUSTOM,
+ ACAMERA_CONTROL_CAPTURE_INTENT_PREVIEW,
+ ACAMERA_CONTROL_CAPTURE_INTENT_STILL_CAPTURE,
+ ACAMERA_CONTROL_CAPTURE_INTENT_VIDEO_RECORD,
+ ACAMERA_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT,
+ ACAMERA_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG,
+ ACAMERA_CONTROL_CAPTURE_INTENT_MANUAL,
+} acamera_metadata_enum_android_control_capture_intent_t;
+
+// ACAMERA_CONTROL_EFFECT_MODE
+typedef enum acamera_metadata_enum_acamera_control_effect_mode {
+ ACAMERA_CONTROL_EFFECT_MODE_OFF,
+ ACAMERA_CONTROL_EFFECT_MODE_MONO,
+ ACAMERA_CONTROL_EFFECT_MODE_NEGATIVE,
+ ACAMERA_CONTROL_EFFECT_MODE_SOLARIZE,
+ ACAMERA_CONTROL_EFFECT_MODE_SEPIA,
+ ACAMERA_CONTROL_EFFECT_MODE_POSTERIZE,
+ ACAMERA_CONTROL_EFFECT_MODE_WHITEBOARD,
+ ACAMERA_CONTROL_EFFECT_MODE_BLACKBOARD,
+ ACAMERA_CONTROL_EFFECT_MODE_AQUA,
+} acamera_metadata_enum_android_control_effect_mode_t;
+
+// ACAMERA_CONTROL_MODE
+typedef enum acamera_metadata_enum_acamera_control_mode {
+ ACAMERA_CONTROL_MODE_OFF,
+ ACAMERA_CONTROL_MODE_AUTO,
+ ACAMERA_CONTROL_MODE_USE_SCENE_MODE,
+ ACAMERA_CONTROL_MODE_OFF_KEEP_STATE,
+} acamera_metadata_enum_android_control_mode_t;
+
+// ACAMERA_CONTROL_SCENE_MODE
+typedef enum acamera_metadata_enum_acamera_control_scene_mode {
+ ACAMERA_CONTROL_SCENE_MODE_DISABLED = 0,
+ ACAMERA_CONTROL_SCENE_MODE_FACE_PRIORITY,
+ ACAMERA_CONTROL_SCENE_MODE_ACTION,
+ ACAMERA_CONTROL_SCENE_MODE_PORTRAIT,
+ ACAMERA_CONTROL_SCENE_MODE_LANDSCAPE,
+ ACAMERA_CONTROL_SCENE_MODE_NIGHT,
+ ACAMERA_CONTROL_SCENE_MODE_NIGHT_PORTRAIT,
+ ACAMERA_CONTROL_SCENE_MODE_THEATRE,
+ ACAMERA_CONTROL_SCENE_MODE_BEACH,
+ ACAMERA_CONTROL_SCENE_MODE_SNOW,
+ ACAMERA_CONTROL_SCENE_MODE_SUNSET,
+ ACAMERA_CONTROL_SCENE_MODE_STEADYPHOTO,
+ ACAMERA_CONTROL_SCENE_MODE_FIREWORKS,
+ ACAMERA_CONTROL_SCENE_MODE_SPORTS,
+ ACAMERA_CONTROL_SCENE_MODE_PARTY,
+ ACAMERA_CONTROL_SCENE_MODE_CANDLELIGHT,
+ ACAMERA_CONTROL_SCENE_MODE_BARCODE,
+ ACAMERA_CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO,
+ ACAMERA_CONTROL_SCENE_MODE_HDR,
+ ACAMERA_CONTROL_SCENE_MODE_FACE_PRIORITY_LOW_LIGHT,
+} acamera_metadata_enum_android_control_scene_mode_t;
+
+// ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE
+typedef enum acamera_metadata_enum_acamera_control_video_stabilization_mode {
+ ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+ ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE_ON,
+} acamera_metadata_enum_android_control_video_stabilization_mode_t;
+
+// ACAMERA_CONTROL_AE_STATE
+typedef enum acamera_metadata_enum_acamera_control_ae_state {
+ ACAMERA_CONTROL_AE_STATE_INACTIVE,
+ ACAMERA_CONTROL_AE_STATE_SEARCHING,
+ ACAMERA_CONTROL_AE_STATE_CONVERGED,
+ ACAMERA_CONTROL_AE_STATE_LOCKED,
+ ACAMERA_CONTROL_AE_STATE_FLASH_REQUIRED,
+ ACAMERA_CONTROL_AE_STATE_PRECAPTURE,
+} acamera_metadata_enum_android_control_ae_state_t;
+
+// ACAMERA_CONTROL_AF_STATE
+typedef enum acamera_metadata_enum_acamera_control_af_state {
+ ACAMERA_CONTROL_AF_STATE_INACTIVE,
+ ACAMERA_CONTROL_AF_STATE_PASSIVE_SCAN,
+ ACAMERA_CONTROL_AF_STATE_PASSIVE_FOCUSED,
+ ACAMERA_CONTROL_AF_STATE_ACTIVE_SCAN,
+ ACAMERA_CONTROL_AF_STATE_FOCUSED_LOCKED,
+ ACAMERA_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED,
+ ACAMERA_CONTROL_AF_STATE_PASSIVE_UNFOCUSED,
+} acamera_metadata_enum_android_control_af_state_t;
+
+// ACAMERA_CONTROL_AWB_STATE
+typedef enum acamera_metadata_enum_acamera_control_awb_state {
+ ACAMERA_CONTROL_AWB_STATE_INACTIVE,
+ ACAMERA_CONTROL_AWB_STATE_SEARCHING,
+ ACAMERA_CONTROL_AWB_STATE_CONVERGED,
+ ACAMERA_CONTROL_AWB_STATE_LOCKED,
+} acamera_metadata_enum_android_control_awb_state_t;
+
+// ACAMERA_CONTROL_AE_LOCK_AVAILABLE
+typedef enum acamera_metadata_enum_acamera_control_ae_lock_available {
+ ACAMERA_CONTROL_AE_LOCK_AVAILABLE_FALSE,
+ ACAMERA_CONTROL_AE_LOCK_AVAILABLE_TRUE,
+} acamera_metadata_enum_android_control_ae_lock_available_t;
+
+// ACAMERA_CONTROL_AWB_LOCK_AVAILABLE
+typedef enum acamera_metadata_enum_acamera_control_awb_lock_available {
+ ACAMERA_CONTROL_AWB_LOCK_AVAILABLE_FALSE,
+ ACAMERA_CONTROL_AWB_LOCK_AVAILABLE_TRUE,
+} acamera_metadata_enum_android_control_awb_lock_available_t;
+
+
+
+// ACAMERA_EDGE_MODE
+typedef enum acamera_metadata_enum_acamera_edge_mode {
+ ACAMERA_EDGE_MODE_OFF,
+ ACAMERA_EDGE_MODE_FAST,
+ ACAMERA_EDGE_MODE_HIGH_QUALITY,
+ ACAMERA_EDGE_MODE_ZERO_SHUTTER_LAG,
+} acamera_metadata_enum_android_edge_mode_t;
+
+
+// ACAMERA_FLASH_MODE
+typedef enum acamera_metadata_enum_acamera_flash_mode {
+ ACAMERA_FLASH_MODE_OFF,
+ ACAMERA_FLASH_MODE_SINGLE,
+ ACAMERA_FLASH_MODE_TORCH,
+} acamera_metadata_enum_android_flash_mode_t;
+
+// ACAMERA_FLASH_STATE
+typedef enum acamera_metadata_enum_acamera_flash_state {
+ ACAMERA_FLASH_STATE_UNAVAILABLE,
+ ACAMERA_FLASH_STATE_CHARGING,
+ ACAMERA_FLASH_STATE_READY,
+ ACAMERA_FLASH_STATE_FIRED,
+ ACAMERA_FLASH_STATE_PARTIAL,
+} acamera_metadata_enum_android_flash_state_t;
+
+
+// ACAMERA_FLASH_INFO_AVAILABLE
+typedef enum acamera_metadata_enum_acamera_flash_info_available {
+ ACAMERA_FLASH_INFO_AVAILABLE_FALSE,
+ ACAMERA_FLASH_INFO_AVAILABLE_TRUE,
+} acamera_metadata_enum_android_flash_info_available_t;
+
+
+// ACAMERA_HOT_PIXEL_MODE
+typedef enum acamera_metadata_enum_acamera_hot_pixel_mode {
+ ACAMERA_HOT_PIXEL_MODE_OFF,
+ ACAMERA_HOT_PIXEL_MODE_FAST,
+ ACAMERA_HOT_PIXEL_MODE_HIGH_QUALITY,
+} acamera_metadata_enum_android_hot_pixel_mode_t;
+
+
+
+// ACAMERA_LENS_OPTICAL_STABILIZATION_MODE
+typedef enum acamera_metadata_enum_acamera_lens_optical_stabilization_mode {
+ ACAMERA_LENS_OPTICAL_STABILIZATION_MODE_OFF,
+ ACAMERA_LENS_OPTICAL_STABILIZATION_MODE_ON,
+} acamera_metadata_enum_android_lens_optical_stabilization_mode_t;
+
+// ACAMERA_LENS_FACING
+typedef enum acamera_metadata_enum_acamera_lens_facing {
+ ACAMERA_LENS_FACING_FRONT,
+ ACAMERA_LENS_FACING_BACK,
+ ACAMERA_LENS_FACING_EXTERNAL,
+} acamera_metadata_enum_android_lens_facing_t;
+
+// ACAMERA_LENS_STATE
+typedef enum acamera_metadata_enum_acamera_lens_state {
+ ACAMERA_LENS_STATE_STATIONARY,
+ ACAMERA_LENS_STATE_MOVING,
+} acamera_metadata_enum_android_lens_state_t;
+
+
+// ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION
+typedef enum acamera_metadata_enum_acamera_lens_info_focus_distance_calibration {
+ ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED,
+ ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE,
+ ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED,
+} acamera_metadata_enum_android_lens_info_focus_distance_calibration_t;
+
+
+// ACAMERA_NOISE_REDUCTION_MODE
+typedef enum acamera_metadata_enum_acamera_noise_reduction_mode {
+ ACAMERA_NOISE_REDUCTION_MODE_OFF,
+ ACAMERA_NOISE_REDUCTION_MODE_FAST,
+ ACAMERA_NOISE_REDUCTION_MODE_HIGH_QUALITY,
+ ACAMERA_NOISE_REDUCTION_MODE_MINIMAL,
+ ACAMERA_NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG,
+} acamera_metadata_enum_android_noise_reduction_mode_t;
+
+
+// ACAMERA_QUIRKS_PARTIAL_RESULT
+typedef enum acamera_metadata_enum_acamera_quirks_partial_result {
+ ACAMERA_QUIRKS_PARTIAL_RESULT_FINAL,
+ ACAMERA_QUIRKS_PARTIAL_RESULT_PARTIAL,
+} acamera_metadata_enum_android_quirks_partial_result_t;
+
+
+// ACAMERA_REQUEST_AVAILABLE_CAPABILITIES
+typedef enum acamera_metadata_enum_acamera_request_available_capabilities {
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR,
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING,
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_RAW,
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING,
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS,
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE,
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING,
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT,
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO,
+} acamera_metadata_enum_android_request_available_capabilities_t;
+
+
+// ACAMERA_SCALER_AVAILABLE_FORMATS
+typedef enum acamera_metadata_enum_acamera_scaler_available_formats {
+ ACAMERA_SCALER_AVAILABLE_FORMATS_RAW16 = 0x20,
+ ACAMERA_SCALER_AVAILABLE_FORMATS_RAW_OPAQUE = 0x24,
+ ACAMERA_SCALER_AVAILABLE_FORMATS_YV12 = 0x32315659,
+ ACAMERA_SCALER_AVAILABLE_FORMATS_YCrCb_420_SP = 0x11,
+ ACAMERA_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED = 0x22,
+ ACAMERA_SCALER_AVAILABLE_FORMATS_YCbCr_420_888 = 0x23,
+ ACAMERA_SCALER_AVAILABLE_FORMATS_BLOB = 0x21,
+} acamera_metadata_enum_android_scaler_available_formats_t;
+
+// ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+typedef enum acamera_metadata_enum_acamera_scaler_available_stream_configurations {
+ ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+ ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
+} acamera_metadata_enum_android_scaler_available_stream_configurations_t;
+
+// ACAMERA_SCALER_CROPPING_TYPE
+typedef enum acamera_metadata_enum_acamera_scaler_cropping_type {
+ ACAMERA_SCALER_CROPPING_TYPE_CENTER_ONLY,
+ ACAMERA_SCALER_CROPPING_TYPE_FREEFORM,
+} acamera_metadata_enum_android_scaler_cropping_type_t;
+
+
+// ACAMERA_SENSOR_REFERENCE_ILLUMINANT1
+typedef enum acamera_metadata_enum_acamera_sensor_reference_illuminant1 {
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT = 1,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_FLUORESCENT = 2,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_TUNGSTEN = 3,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_FLASH = 4,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_FINE_WEATHER = 9,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_CLOUDY_WEATHER = 10,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_SHADE = 11,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT_FLUORESCENT = 12,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_DAY_WHITE_FLUORESCENT = 13,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_COOL_WHITE_FLUORESCENT = 14,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_WHITE_FLUORESCENT = 15,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_A = 17,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_B = 18,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_C = 19,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_D55 = 20,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_D65 = 21,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_D75 = 22,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_D50 = 23,
+ ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN = 24,
+} acamera_metadata_enum_android_sensor_reference_illuminant1_t;
+
+// ACAMERA_SENSOR_TEST_PATTERN_MODE
+typedef enum acamera_metadata_enum_acamera_sensor_test_pattern_mode {
+ ACAMERA_SENSOR_TEST_PATTERN_MODE_OFF,
+ ACAMERA_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR,
+ ACAMERA_SENSOR_TEST_PATTERN_MODE_COLOR_BARS,
+ ACAMERA_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY,
+ ACAMERA_SENSOR_TEST_PATTERN_MODE_PN9,
+ ACAMERA_SENSOR_TEST_PATTERN_MODE_CUSTOM1 = 256,
+} acamera_metadata_enum_android_sensor_test_pattern_mode_t;
+
+
+// ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
+typedef enum acamera_metadata_enum_acamera_sensor_info_color_filter_arrangement {
+ ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB,
+ ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG,
+ ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG,
+ ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR,
+ ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB,
+} acamera_metadata_enum_android_sensor_info_color_filter_arrangement_t;
+
+// ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE
+typedef enum acamera_metadata_enum_acamera_sensor_info_timestamp_source {
+ ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN,
+ ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME,
+} acamera_metadata_enum_android_sensor_info_timestamp_source_t;
+
+// ACAMERA_SENSOR_INFO_LENS_SHADING_APPLIED
+typedef enum acamera_metadata_enum_acamera_sensor_info_lens_shading_applied {
+ ACAMERA_SENSOR_INFO_LENS_SHADING_APPLIED_FALSE,
+ ACAMERA_SENSOR_INFO_LENS_SHADING_APPLIED_TRUE,
+} acamera_metadata_enum_android_sensor_info_lens_shading_applied_t;
+
+
+// ACAMERA_SHADING_MODE
+typedef enum acamera_metadata_enum_acamera_shading_mode {
+ ACAMERA_SHADING_MODE_OFF,
+ ACAMERA_SHADING_MODE_FAST,
+ ACAMERA_SHADING_MODE_HIGH_QUALITY,
+} acamera_metadata_enum_android_shading_mode_t;
+
+
+// ACAMERA_STATISTICS_FACE_DETECT_MODE
+typedef enum acamera_metadata_enum_acamera_statistics_face_detect_mode {
+ ACAMERA_STATISTICS_FACE_DETECT_MODE_OFF,
+ ACAMERA_STATISTICS_FACE_DETECT_MODE_SIMPLE,
+ ACAMERA_STATISTICS_FACE_DETECT_MODE_FULL,
+} acamera_metadata_enum_android_statistics_face_detect_mode_t;
+
+// ACAMERA_STATISTICS_HOT_PIXEL_MAP_MODE
+typedef enum acamera_metadata_enum_acamera_statistics_hot_pixel_map_mode {
+ ACAMERA_STATISTICS_HOT_PIXEL_MAP_MODE_OFF,
+ ACAMERA_STATISTICS_HOT_PIXEL_MAP_MODE_ON,
+} acamera_metadata_enum_android_statistics_hot_pixel_map_mode_t;
+
+// ACAMERA_STATISTICS_SCENE_FLICKER
+typedef enum acamera_metadata_enum_acamera_statistics_scene_flicker {
+ ACAMERA_STATISTICS_SCENE_FLICKER_NONE,
+ ACAMERA_STATISTICS_SCENE_FLICKER_50HZ,
+ ACAMERA_STATISTICS_SCENE_FLICKER_60HZ,
+} acamera_metadata_enum_android_statistics_scene_flicker_t;
+
+// ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE
+typedef enum acamera_metadata_enum_acamera_statistics_lens_shading_map_mode {
+ ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE_OFF,
+ ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE_ON,
+} acamera_metadata_enum_android_statistics_lens_shading_map_mode_t;
+
+
+
+// ACAMERA_TONEMAP_MODE
+typedef enum acamera_metadata_enum_acamera_tonemap_mode {
+ ACAMERA_TONEMAP_MODE_CONTRAST_CURVE,
+ ACAMERA_TONEMAP_MODE_FAST,
+ ACAMERA_TONEMAP_MODE_HIGH_QUALITY,
+ ACAMERA_TONEMAP_MODE_GAMMA_VALUE,
+ ACAMERA_TONEMAP_MODE_PRESET_CURVE,
+} acamera_metadata_enum_android_tonemap_mode_t;
+
+// ACAMERA_TONEMAP_PRESET_CURVE
+typedef enum acamera_metadata_enum_acamera_tonemap_preset_curve {
+ ACAMERA_TONEMAP_PRESET_CURVE_SRGB,
+ ACAMERA_TONEMAP_PRESET_CURVE_REC709,
+} acamera_metadata_enum_android_tonemap_preset_curve_t;
+
+
+// ACAMERA_LED_TRANSMIT
+typedef enum acamera_metadata_enum_acamera_led_transmit {
+ ACAMERA_LED_TRANSMIT_OFF,
+ ACAMERA_LED_TRANSMIT_ON,
+} acamera_metadata_enum_android_led_transmit_t;
+
+// ACAMERA_LED_AVAILABLE_LEDS
+typedef enum acamera_metadata_enum_acamera_led_available_leds {
+ ACAMERA_LED_AVAILABLE_LEDS_TRANSMIT,
+} acamera_metadata_enum_android_led_available_leds_t;
+
+
+// ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL
+typedef enum acamera_metadata_enum_acamera_info_supported_hardware_level {
+ ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
+ ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
+ ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
+} acamera_metadata_enum_android_info_supported_hardware_level_t;
+
+
+// ACAMERA_BLACK_LEVEL_LOCK
+typedef enum acamera_metadata_enum_acamera_black_level_lock {
+ ACAMERA_BLACK_LEVEL_LOCK_OFF,
+ ACAMERA_BLACK_LEVEL_LOCK_ON,
+} acamera_metadata_enum_android_black_level_lock_t;
+
+
+// ACAMERA_SYNC_FRAME_NUMBER
+typedef enum acamera_metadata_enum_acamera_sync_frame_number {
+ ACAMERA_SYNC_FRAME_NUMBER_CONVERGING = -1,
+ ACAMERA_SYNC_FRAME_NUMBER_UNKNOWN = -2,
+} acamera_metadata_enum_android_sync_frame_number_t;
+
+// ACAMERA_SYNC_MAX_LATENCY
+typedef enum acamera_metadata_enum_acamera_sync_max_latency {
+ ACAMERA_SYNC_MAX_LATENCY_PER_FRAME_CONTROL = 0,
+ ACAMERA_SYNC_MAX_LATENCY_UNKNOWN = -1,
+} acamera_metadata_enum_android_sync_max_latency_t;
+
+
+
+// ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS
+typedef enum acamera_metadata_enum_acamera_depth_available_depth_stream_configurations {
+ ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT,
+ ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_INPUT,
+} acamera_metadata_enum_android_depth_available_depth_stream_configurations_t;
+
+// ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE
+typedef enum acamera_metadata_enum_acamera_depth_depth_is_exclusive {
+ ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE_FALSE,
+ ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE_TRUE,
+} acamera_metadata_enum_android_depth_depth_is_exclusive_t;
+
+
+
+#endif //_NDK_CAMERA_METADATA_TAGS_H
diff --git a/include/camera/ndk/NdkCaptureRequest.h b/include/camera/ndk/NdkCaptureRequest.h
new file mode 100644
index 0000000..566d78f
--- /dev/null
+++ b/include/camera/ndk/NdkCaptureRequest.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+#include <android/native_window.h>
+#include "NdkCameraError.h"
+#include "NdkCameraMetadata.h"
+
+#ifndef _NDK_CAPTURE_REQUEST_H
+#define _NDK_CAPTURE_REQUEST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Container for output targets
+typedef struct ACameraOutputTargets ACameraOutputTargets;
+
+// Container for a single output target
+typedef struct ACameraOutputTarget ACameraOutputTarget;
+
+typedef struct ACaptureRequest ACaptureRequest;
+
+camera_status_t ACameraOutputTarget_create(ANativeWindow* window, ACameraOutputTarget** out);
+void ACameraOutputTarget_free(ACameraOutputTarget*);
+
+camera_status_t ACaptureRequest_addTarget(ACaptureRequest*, const ACameraOutputTarget*);
+camera_status_t ACaptureRequest_removeTarget(ACaptureRequest*, const ACameraOutputTarget*);
+//TODO: do we need API to query added targets?
+
+/*
+ * Get a metadata entry
+ */
+camera_status_t ACaptureRequest_getConstEntry(
+ const ACaptureRequest*, uint32_t tag, ACameraMetadata_const_entry* entry);
+/*
+ * Set an entry of corresponding type.
+ * The entry tag's type must match corresponding set API or an
+ * ACAMERA_ERROR_INVALID_PARAMETER error will occur.
+ * Also, the input ACameraMetadata* must belong to a capture request or an
+ * ACAMERA_ERROR_INVALID_PARAMETER error will occur.
+ */
+camera_status_t ACaptureRequest_setEntry_u8(
+ ACaptureRequest*, uint32_t tag, uint32_t count, const uint8_t* data);
+camera_status_t ACaptureRequest_setEntry_i32(
+ ACaptureRequest*, uint32_t tag, uint32_t count, const int32_t* data);
+camera_status_t ACaptureRequest_setEntry_float(
+ ACaptureRequest*, uint32_t tag, uint32_t count, const float* data);
+camera_status_t ACaptureRequest_setEntry_i64(
+ ACaptureRequest*, uint32_t tag, uint32_t count, const int64_t* data);
+camera_status_t ACaptureRequest_setEntry_double(
+ ACaptureRequest*, uint32_t tag, uint32_t count, const double* data);
+camera_status_t ACaptureRequest_setEntry_rational(
+ ACaptureRequest*, uint32_t tag, uint32_t count, const ACameraMetadata_rational* data);
+
+// free the capture request created by ACameraDevice_createCaptureRequest
+void ACaptureRequest_free(ACaptureRequest* request);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _NDK_CAPTURE_REQUEST_H
diff --git a/include/media/AudioBufferProvider.h b/include/media/AudioBufferProvider.h
index 7be449c..458d170 100644
--- a/include/media/AudioBufferProvider.h
+++ b/include/media/AudioBufferProvider.h
@@ -40,12 +40,6 @@
virtual ~AudioBufferProvider() {}
- // value representing an invalid presentation timestamp
- static const int64_t kInvalidPTS = 0x7FFFFFFFFFFFFFFFLL; // <stdint.h> is too painful
-
- // pts is the local time when the next sample yielded by getNextBuffer
- // will be rendered.
- // Pass kInvalidPTS if the PTS is unknown or not applicable.
// On entry:
// buffer != NULL
// buffer->raw unused
@@ -59,7 +53,7 @@
// status != NO_ERROR
// buffer->raw NULL
// buffer->frameCount 0
- virtual status_t getNextBuffer(Buffer* buffer, int64_t pts = kInvalidPTS) = 0;
+ virtual status_t getNextBuffer(Buffer* buffer) = 0;
// Release (a portion of) the buffer previously obtained by getNextBuffer().
// It is permissible to call releaseBuffer() multiple times per getNextBuffer().
diff --git a/include/media/AudioPolicy.h b/include/media/AudioPolicy.h
index feed402..a171493 100644
--- a/include/media/AudioPolicy.h
+++ b/include/media/AudioPolicy.h
@@ -28,11 +28,13 @@
// Keep in sync with AudioMix.java, AudioMixingRule.java, AudioPolicyConfig.java
#define RULE_EXCLUSION_MASK 0x8000
-#define RULE_MATCH_ATTRIBUTE_USAGE 0x1
+#define RULE_MATCH_ATTRIBUTE_USAGE 0x1
#define RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET (0x1 << 1)
-#define RULE_EXCLUDE_ATTRIBUTE_USAGE (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_USAGE)
+#define RULE_MATCH_UID (0x1 << 2)
+#define RULE_EXCLUDE_ATTRIBUTE_USAGE (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_USAGE)
#define RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET \
- (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
+ (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
+#define RULE_EXCLUDE_UID (RULE_EXCLUSION_MASK|RULE_MATCH_UID)
#define MIX_TYPE_INVALID -1
#define MIX_TYPE_PLAYERS 0
@@ -53,10 +55,10 @@
#define MAX_MIXES_PER_POLICY 10
#define MAX_CRITERIA_PER_MIX 20
-class AttributeMatchCriterion {
+class AudioMixMatchCriterion {
public:
- AttributeMatchCriterion() {}
- AttributeMatchCriterion(audio_usage_t usage, audio_source_t source, uint32_t rule);
+ AudioMixMatchCriterion() {}
+ AudioMixMatchCriterion(audio_usage_t usage, audio_source_t source, uint32_t rule);
status_t readFromParcel(Parcel *parcel);
status_t writeToParcel(Parcel *parcel) const;
@@ -64,7 +66,8 @@
union {
audio_usage_t mUsage;
audio_source_t mSource;
- } mAttr;
+ uid_t mUid;
+ } mValue;
uint32_t mRule;
};
@@ -75,7 +78,7 @@
static const uint32_t kCbFlagNotifyActivity = 0x1;
AudioMix() {}
- AudioMix(Vector<AttributeMatchCriterion> criteria, uint32_t mixType, audio_config_t format,
+ AudioMix(Vector<AudioMixMatchCriterion> criteria, uint32_t mixType, audio_config_t format,
uint32_t routeFlags, String8 registrationId, uint32_t flags) :
mCriteria(criteria), mMixType(mixType), mFormat(format),
mRouteFlags(routeFlags), mRegistrationId(registrationId), mCbFlags(flags){}
@@ -83,7 +86,7 @@
status_t readFromParcel(Parcel *parcel);
status_t writeToParcel(Parcel *parcel) const;
- Vector<AttributeMatchCriterion> mCriteria;
+ Vector<AudioMixMatchCriterion> mCriteria;
uint32_t mMixType;
audio_config_t mFormat;
uint32_t mRouteFlags;
@@ -91,6 +94,12 @@
uint32_t mCbFlags; // flags indicating which callbacks to use, see kCbFlag*
};
+
+// definitions for audio recording configuration updates
+// which update type is reported
+#define RECORD_CONFIG_EVENT_START 1
+#define RECORD_CONFIG_EVENT_STOP 0
+
}; // namespace android
#endif // ANDROID_AUDIO_POLICY_H
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index c4c7b0e..521557d 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -19,7 +19,9 @@
#include <cutils/sched_policy.h>
#include <media/AudioSystem.h>
+#include <media/AudioTimestamp.h>
#include <media/IAudioRecord.h>
+#include <media/Modulo.h>
#include <utils/threads.h>
namespace android {
@@ -313,6 +315,17 @@
*/
status_t getPosition(uint32_t *position) const;
+ /* Return the record timestamp.
+ *
+ * Parameters:
+ * timestamp: A pointer to the timestamp to be filled.
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * - NO_ERROR: successful operation
+ * - BAD_VALUE: timestamp is NULL
+ */
+ status_t getTimestamp(ExtendedTimestamp *timestamp);
+
/* Returns a handle on the audio input used by this AudioRecord.
*
* Parameters:
@@ -526,7 +539,7 @@
// caller must hold lock on mLock for all _l methods
- status_t openRecord_l(size_t epoch, const String16& opPackageName);
+ status_t openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName);
// FIXME enum is faster than strcmp() for parameter 'from'
status_t restoreRecord_l(const char *from);
@@ -556,9 +569,9 @@
bool mRetryOnPartialBuffer; // sleep and retry after partial obtainBuffer()
uint32_t mObservedSequence; // last observed value of mSequence
- uint32_t mMarkerPosition; // in wrapping (overflow) frame units
+ Modulo<uint32_t> mMarkerPosition; // in wrapping (overflow) frame units
bool mMarkerReached;
- uint32_t mNewPosition; // in frames
+ Modulo<uint32_t> mNewPosition; // in frames
uint32_t mUpdatePeriod; // in frames, zero means no EVENT_NEW_POS
status_t mStatus;
@@ -570,6 +583,11 @@
size_t mReqFrameCount; // frame count to request the first or next time
// a new IAudioRecord is needed, non-decreasing
+ int64_t mFramesRead; // total frames read. reset to zero after
+ // the start() following stop(). It is not
+ // changed after restoring the track.
+ int64_t mFramesReadServerOffset; // An offset to server frames read due to
+ // restoring AudioRecord, or stop/start.
// constant after constructor or set()
uint32_t mSampleRate;
audio_format_t mFormat;
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 26a0bb2..2f95b90 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -31,6 +31,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, int session, int source);
class IAudioFlinger;
class IAudioPolicyService;
@@ -92,6 +93,7 @@
static void setErrorCallback(audio_error_callback cb);
static void setDynPolicyCallback(dynamic_policy_callback cb);
+ static void setRecordConfigCallback(record_config_callback);
// helper function to obtain AudioFlinger service handle
static const sp<IAudioFlinger> get_audio_flinger();
@@ -319,6 +321,8 @@
audio_io_handle_t *handle);
static status_t stopAudioSource(audio_io_handle_t handle);
+ static status_t setMasterMono(bool mono);
+ static status_t getMasterMono(bool *mono);
// ----------------------------------------------------------------------------
@@ -419,6 +423,8 @@
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);
private:
Mutex mLock;
@@ -438,6 +444,7 @@
static sp<IAudioFlinger> gAudioFlinger;
static audio_error_callback gAudioErrorCallback;
static dynamic_policy_callback gDynPolicyCallback;
+ static record_config_callback gRecordConfigCallback;
static size_t gInBuffSize;
// previous parameters for recording buffer size queries
diff --git a/include/media/AudioTimestamp.h b/include/media/AudioTimestamp.h
index 99e9c3e..531b548 100644
--- a/include/media/AudioTimestamp.h
+++ b/include/media/AudioTimestamp.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_AUDIO_TIMESTAMP_H
#define ANDROID_AUDIO_TIMESTAMP_H
+#include <string>
+#include <sstream>
#include <time.h>
namespace android {
@@ -32,6 +34,99 @@
struct timespec mTime; // corresponding CLOCK_MONOTONIC when frame is expected to present
};
+struct ExtendedTimestamp {
+ enum Location {
+ LOCATION_CLIENT, // timestamp of last read frame from client-server track buffer
+ LOCATION_SERVER, // timestamp of newest frame from client-server track buffer
+ LOCATION_KERNEL, // timestamp of newest frame in the kernel (alsa) buffer.
+ LOCATION_MAX // for sizing arrays only
+ };
+
+ // This needs to be kept in sync with android.media.AudioTimestamp
+ enum Timebase {
+ TIMEBASE_MONOTONIC, // Clock monotonic offset (generally 0)
+ TIMEBASE_BOOTTIME,
+ TIMEBASE_MAX,
+ };
+
+ ExtendedTimestamp() {
+ clear();
+ }
+
+ // mPosition is expressed in frame units.
+ // It is generally nonnegative, though we keep this signed for
+ // to potentially express algorithmic latency at the start of the stream
+ // and to prevent unintentional unsigned integer underflow.
+ int64_t mPosition[LOCATION_MAX];
+
+ // mTimeNs is in nanoseconds for the default timebase, monotonic.
+ // If this value is -1, then both time and position are invalid.
+ // If this value is 0, then the time is not valid but the position is valid.
+ int64_t mTimeNs[LOCATION_MAX];
+
+ // mTimebaseOffset is the offset in ns from monotonic when the
+ // timestamp was taken. This may vary due to suspend time
+ // or NTP adjustment.
+ int64_t mTimebaseOffset[TIMEBASE_MAX];
+
+ void clear() {
+ memset(mPosition, 0, sizeof(mPosition)); // actually not necessary if time is -1
+ for (int i = 0; i < LOCATION_MAX; ++i) {
+ mTimeNs[i] = -1;
+ }
+ memset(mTimebaseOffset, 0, sizeof(mTimebaseOffset));
+ }
+
+ // Returns the best timestamp as judged from the closest-to-hw stage in the
+ // pipeline with a valid timestamp.
+ status_t getBestTimestamp(int64_t *position, int64_t *time, int timebase) const {
+ if (position == nullptr || time == nullptr
+ || timebase < 0 || timebase >= TIMEBASE_MAX) {
+ return BAD_VALUE;
+ }
+ // look for the closest-to-hw stage in the pipeline with a valid timestamp.
+ // We omit LOCATION_CLIENT as we prefer at least LOCATION_SERVER based accuracy
+ // when getting the best timestamp.
+ for (int i = LOCATION_MAX - 1; i >= LOCATION_SERVER; --i) {
+ if (mTimeNs[i] > 0) {
+ *position = mPosition[i];
+ *time = mTimeNs[i] + mTimebaseOffset[timebase];
+ return OK;
+ }
+ }
+ return INVALID_OPERATION;
+ }
+
+ status_t getBestTimestamp(AudioTimestamp *timestamp) const {
+ if (timestamp == nullptr) {
+ return BAD_VALUE;
+ }
+ int64_t position, time;
+ if (getBestTimestamp(&position, &time, TIMEBASE_MONOTONIC) == OK) {
+ timestamp->mPosition = position;
+ timestamp->mTime.tv_sec = time / 1000000000;
+ timestamp->mTime.tv_nsec = time - timestamp->mTime.tv_sec * 1000000000LL;
+ return OK;
+ }
+ return INVALID_OPERATION;
+ }
+
+ // convert fields to a printable string
+ std::string toString() {
+ std::stringstream ss;
+
+ ss << "BOOTTIME offset " << mTimebaseOffset[TIMEBASE_BOOTTIME] << "\n";
+ for (int i = 0; i < LOCATION_MAX; ++i) {
+ ss << "ExtendedTimestamp[" << i << "] position: "
+ << mPosition[i] << " time: " << mTimeNs[i] << "\n";
+ }
+ return ss.str();
+ }
+ // TODO:
+ // Consider adding buffer status:
+ // size, available, algorithmic latency
+};
+
} // namespace
#endif // ANDROID_AUDIO_TIMESTAMP_H
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index e02f1b7..a4b8571 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -22,6 +22,7 @@
#include <media/AudioTimestamp.h>
#include <media/IAudioTrack.h>
#include <media/AudioResamplerPublic.h>
+#include <media/Modulo.h>
#include <utils/threads.h>
namespace android {
@@ -304,6 +305,11 @@
*/
uint32_t latency() const { return mLatency; }
+ /* Returns the number of application-level buffer underruns
+ * since the AudioTrack was created.
+ */
+ uint32_t getUnderrunCount() const;
+
/* getters, see constructors and set() */
audio_stream_type_t streamType() const;
@@ -319,6 +325,25 @@
uint32_t channelCount() const { return mChannelCount; }
size_t frameCount() const { return mFrameCount; }
+ /* Return effective size of audio buffer that an application writes to
+ * or a negative error if the track is uninitialized.
+ */
+ ssize_t getBufferSizeInFrames();
+
+ /* Set the effective size of audio buffer that an application writes to.
+ * This is used to determine the amount of available room in the buffer,
+ * which determines when a write will block.
+ * This allows an application to raise and lower the audio latency.
+ * The requested size may be adjusted so that it is
+ * greater or equal to the absolute minimum and
+ * less than or equal to the getBufferCapacityInFrames().
+ * It may also be adjusted slightly for internal reasons.
+ *
+ * Return the final size or a negative error if the track is unitialized
+ * or does not support variable sizes.
+ */
+ ssize_t setBufferSizeInFrames(size_t size);
+
/* Return the static buffer specified in constructor or set(), or 0 for streaming mode */
sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
@@ -783,6 +808,8 @@
// FIXME enum is faster than strcmp() for parameter 'from'
status_t restoreTrack_l(const char *from);
+ uint32_t getUnderrunCount_l() const;
+
bool isOffloaded() const;
bool isDirect() const;
bool isOffloadedOrDirect() const;
@@ -798,7 +825,7 @@
{ return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }
// increment mPosition by the delta of mServer, and return new value of mPosition
- uint32_t updateAndGetPosition_l();
+ Modulo<uint32_t> updateAndGetPosition_l();
// check sample rate and speed is compatible with AudioTrack
bool isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const;
@@ -810,14 +837,18 @@
audio_io_handle_t mOutput; // returned by AudioSystem::getOutput()
sp<AudioTrackThread> mAudioTrackThread;
+ bool mThreadCanCallJava;
float mVolume[2];
float mSendLevel;
mutable uint32_t mSampleRate; // mutable because getSampleRate() can update it
uint32_t mOriginalSampleRate;
AudioPlaybackRate mPlaybackRate;
- size_t mFrameCount; // corresponds to current IAudioTrack, value is
- // reported back by AudioFlinger to the client
+
+ // Corresponds to current IAudioTrack, value is reported back by AudioFlinger to the client.
+ // This allocated buffer size is maintained by the proxy.
+ size_t mFrameCount; // maximum size of buffer
+
size_t mReqFrameCount; // frame count to request the first or next time
// a new IAudioTrack is needed, non-decreasing
@@ -885,19 +916,19 @@
bool mRetryOnPartialBuffer; // sleep and retry after partial obtainBuffer()
uint32_t mObservedSequence; // last observed value of mSequence
- uint32_t mMarkerPosition; // in wrapping (overflow) frame units
+ Modulo<uint32_t> mMarkerPosition; // in wrapping (overflow) frame units
bool mMarkerReached;
- uint32_t mNewPosition; // in frames
+ Modulo<uint32_t> mNewPosition; // in frames
uint32_t mUpdatePeriod; // in frames, zero means no EVENT_NEW_POS
- uint32_t mServer; // in frames, last known mProxy->getPosition()
+ Modulo<uint32_t> mServer; // in frames, last known mProxy->getPosition()
// which is count of frames consumed by server,
// reset by new IAudioTrack,
// whether it is reset by stop() is TBD
- uint32_t mPosition; // in frames, like mServer except continues
+ Modulo<uint32_t> mPosition; // in frames, like mServer except continues
// monotonically after new IAudioTrack,
// and could be easily widened to uint64_t
- uint32_t mReleased; // in frames, count of frames released to server
+ Modulo<uint32_t> mReleased; // count of frames released to server
// but not necessarily consumed by server,
// reset by stop() but continues monotonically
// after new IAudioTrack to restore mPosition,
@@ -910,6 +941,8 @@
bool mRetrogradeMotionReported; // reduce log spam
AudioTimestamp mPreviousTimestamp; // used to detect retrograde motion
+ uint32_t mUnderrunCountOffset; // updated when restoring tracks
+
audio_output_flags_t mFlags;
// const after set(), except for bits AUDIO_OUTPUT_FLAG_FAST and AUDIO_OUTPUT_FLAG_OFFLOAD.
// mLock must be held to read or write those bits reliably.
@@ -921,7 +954,6 @@
mutable Mutex mLock;
- bool mIsTimed;
int mPreviousPriority; // before start()
SchedPolicy mPreviousSchedulingGroup;
bool mAwaitBoost; // thread should wait for priority boost before running
@@ -959,29 +991,6 @@
sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
};
-class TimedAudioTrack : public AudioTrack
-{
-public:
- TimedAudioTrack();
-
- /* allocate a shared memory buffer that can be passed to queueTimedBuffer */
- status_t allocateTimedBuffer(size_t size, sp<IMemory>* buffer);
-
- /* queue a buffer obtained via allocateTimedBuffer for playback at the
- given timestamp. PTS units are microseconds on the media time timeline.
- The media time transform (set with setMediaTimeTransform) set by the
- audio producer will handle converting from media time to local time
- (perhaps going through the common time timeline in the case of
- synchronized multiroom audio case) */
- status_t queueTimedBuffer(const sp<IMemory>& buffer, int64_t pts);
-
- /* define a transform between media time and either common time or
- local time */
- enum TargetTimeline {LOCAL_TIME, COMMON_TIME};
- status_t setMediaTimeTransform(const LinearTransform& xform,
- TargetTimeline target);
-};
-
}; // namespace android
#endif // ANDROID_AUDIOTRACK_H
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 5051aff..3b69ecf 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -47,7 +47,8 @@
// or-able bits shared by createTrack and openRecord, but not all combinations make sense
enum {
TRACK_DEFAULT = 0, // client requests a default AudioTrack
- TRACK_TIMED = 1, // client requests a TimedAudioTrack
+ // FIXME: obsolete
+ // TRACK_TIMED= 1, // client requests a TimedAudioTrack
TRACK_FAST = 2, // client requests a fast AudioTrack or AudioRecord
TRACK_OFFLOAD = 4, // client requests offload to hw codec
TRACK_DIRECT = 8, // client requests a direct output
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 6b93f6f..ceca71a 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -165,6 +165,9 @@
const audio_attributes_t *attributes,
audio_io_handle_t *handle) = 0;
virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
+
+ virtual status_t setMasterMono(bool mono) = 0;
+ virtual status_t getMasterMono(bool *mono) = 0;
};
diff --git a/include/media/IAudioPolicyServiceClient.h b/include/media/IAudioPolicyServiceClient.h
index a7f2cc3..e8fd39f 100644
--- a/include/media/IAudioPolicyServiceClient.h
+++ b/include/media/IAudioPolicyServiceClient.h
@@ -37,6 +37,9 @@
virtual void onAudioPatchListUpdate() = 0;
// 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) = 0;
};
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index 619ac78..a31cec6 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -24,7 +24,6 @@
#include <utils/Errors.h>
#include <binder/IInterface.h>
#include <binder/IMemory.h>
-#include <utils/LinearTransform.h>
#include <utils/String8.h>
#include <media/AudioTimestamp.h>
@@ -67,24 +66,6 @@
*/
virtual status_t attachAuxEffect(int effectId) = 0;
-
- /* Allocate a shared memory buffer suitable for holding timed audio
- samples */
- virtual status_t allocateTimedBuffer(size_t size,
- sp<IMemory>* buffer) = 0;
-
- /* Queue a buffer obtained via allocateTimedBuffer for playback at the given
- timestamp */
- virtual status_t queueTimedBuffer(const sp<IMemory>& buffer,
- int64_t pts) = 0;
-
- /* Define the linear transform that will be applied to the timestamps
- given to queueTimedBuffer (which are expressed in media time).
- Target specifies whether this transform converts media time to local time
- or Tungsten time. The values for target are defined in AudioTrack.h */
- virtual status_t setMediaTimeTransform(const LinearTransform& xform,
- int target) = 0;
-
/* Send parameters to the audio hardware */
virtual status_t setParameters(const String8& keyValuePairs) = 0;
diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h
index ea316de..a4bfaf8 100644
--- a/include/media/ICrypto.h
+++ b/include/media/ICrypto.h
@@ -46,11 +46,18 @@
virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId) = 0;
+ enum DestinationType {
+ kDestinationTypeVmPointer, // non-secure
+ kDestinationTypeOpaqueHandle, // secure
+ kDestinationTypeNativeHandle // secure
+ };
+
virtual ssize_t decrypt(
- bool secure,
+ DestinationType dstType,
const uint8_t key[16],
const uint8_t iv[16],
CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern &pattern,
const sp<IMemory> &sharedBuffer, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
diff --git a/include/media/IDataSource.h b/include/media/IDataSource.h
index 07e46f7..09009f0 100644
--- a/include/media/IDataSource.h
+++ b/include/media/IDataSource.h
@@ -41,6 +41,9 @@
// This should be called before deleting |this|. The other methods may
// return errors if they're called after calling close().
virtual void close() = 0;
+ // Get the flags of the source.
+ // Refer to DataSource:Flags for the definition of the flags.
+ virtual uint32_t getFlags() = 0;
private:
DISALLOW_EVIL_CONSTRUCTORS(IDataSource);
diff --git a/include/media/IDrm.h b/include/media/IDrm.h
index 9449beb6..fd51fd0 100644
--- a/include/media/IDrm.h
+++ b/include/media/IDrm.h
@@ -71,8 +71,6 @@
Vector<uint8_t> &certificate,
Vector<uint8_t> &wrappedKey) = 0;
- virtual status_t unprovisionDevice() = 0;
-
virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) = 0;
virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) = 0;
diff --git a/include/media/IMediaCodecService.h b/include/media/IMediaCodecService.h
new file mode 100644
index 0000000..984a0fd
--- /dev/null
+++ b/include/media/IMediaCodecService.h
@@ -0,0 +1,45 @@
+/*
+ * 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_IMEDIACODECSERVICE_H
+#define ANDROID_IMEDIACODECSERVICE_H
+
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <media/IDataSource.h>
+#include <include/OMX.h>
+
+namespace android {
+
+class IMediaCodecService: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MediaCodecService);
+
+ virtual sp<IOMX> getOMX() = 0;
+};
+
+class BnMediaCodecService: public BnInterface<IMediaCodecService>
+{
+public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // ANDROID_IMEDIACODECSERVICE_H
diff --git a/include/media/IMediaDrmService.h b/include/media/IMediaDrmService.h
new file mode 100644
index 0000000..323fae5
--- /dev/null
+++ b/include/media/IMediaDrmService.h
@@ -0,0 +1,53 @@
+/*
+ * 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_IMEDIADRMSERVICE_H
+#define ANDROID_IMEDIADRMSERVICE_H
+
+#include <utils/Errors.h> // for status_t
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+struct ICrypto;
+struct IDrm;
+
+class IMediaDrmService: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MediaDrmService);
+
+ virtual sp<ICrypto> makeCrypto() = 0;
+ virtual sp<IDrm> makeDrm() = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaDrmService: public BnInterface<IMediaDrmService>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIADRMSERVICE_H
diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
new file mode 100644
index 0000000..9f7a719
--- /dev/null
+++ b/include/media/IMediaExtractor.h
@@ -0,0 +1,75 @@
+/*
+ * 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 IMEDIA_EXTRACTOR_BASE_H_
+
+#define IMEDIA_EXTRACTOR_BASE_H_
+
+#include <media/IMediaSource.h>
+
+namespace android {
+
+class MetaData;
+
+class IMediaExtractor : public IInterface {
+public:
+ DECLARE_META_INTERFACE(MediaExtractor);
+
+ virtual size_t countTracks() = 0;
+ virtual sp<IMediaSource> getTrack(size_t index) = 0;
+
+ enum GetTrackMetaDataFlags {
+ kIncludeExtensiveMetaData = 1
+ };
+ virtual sp<MetaData> getTrackMetaData(
+ size_t index, uint32_t flags = 0) = 0;
+
+ // Return container specific meta-data. The default implementation
+ // returns an empty metadata object.
+ virtual sp<MetaData> getMetaData() = 0;
+
+ enum Flags {
+ CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"
+ CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"
+ CAN_PAUSE = 4,
+ CAN_SEEK = 8, // the "seek bar"
+ };
+
+ // If subclasses do _not_ override this, the default is
+ // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
+ virtual uint32_t flags() const = 0;
+
+ // for DRM
+ virtual void setDrmFlag(bool flag) = 0;
+ virtual bool getDrmFlag() = 0;
+ virtual char* getDrmTrackInfo(size_t trackID, int *len) = 0;
+ virtual void setUID(uid_t uid) = 0;
+
+ virtual const char * name() = 0;
+};
+
+
+class BnMediaExtractor: public BnInterface<IMediaExtractor>
+{
+public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+};
+
+
+} // namespace android
+
+#endif // IMEDIA_EXTRACTOR_BASE_H_
diff --git a/include/media/IMediaExtractorService.h b/include/media/IMediaExtractorService.h
new file mode 100644
index 0000000..4d7b317
--- /dev/null
+++ b/include/media/IMediaExtractorService.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IMEDIAEXTRACTORSERVICE_H
+#define ANDROID_IMEDIAEXTRACTORSERVICE_H
+
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <media/IDataSource.h>
+#include <media/IMediaExtractor.h>
+
+namespace android {
+
+class IMediaExtractorService: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MediaExtractorService);
+
+ virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime) = 0;
+
+};
+
+class BnMediaExtractorService: public BnInterface<IMediaExtractorService>
+{
+public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // ANDROID_IMEDIAEXTRACTORSERVICE_H
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index a316ce2..99ca6f0 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -51,7 +51,6 @@
virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0;
virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, int audioSessionId = 0)
= 0;
-
virtual sp<IOMX> getOMX() = 0;
virtual sp<ICrypto> makeCrypto() = 0;
virtual sp<IDrm> makeDrm() = 0;
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 77ed5d3..caa6592 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -53,6 +53,8 @@
virtual status_t start() = 0;
virtual status_t stop() = 0;
virtual status_t reset() = 0;
+ virtual status_t pause() = 0;
+ virtual status_t resume() = 0;
virtual status_t init() = 0;
virtual status_t close() = 0;
virtual status_t release() = 0;
diff --git a/include/media/IMediaSource.h b/include/media/IMediaSource.h
new file mode 100644
index 0000000..f7586a7
--- /dev/null
+++ b/include/media/IMediaSource.h
@@ -0,0 +1,139 @@
+/*
+ * 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 IMEDIA_SOURCE_BASE_H_
+
+#define IMEDIA_SOURCE_BASE_H_
+
+#include <binder/IInterface.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+struct MediaSource;
+class MetaData;
+class MediaBuffer;
+class MediaBufferGroup;
+
+class IMediaSource : public IInterface {
+public:
+ DECLARE_META_INTERFACE(MediaSource);
+
+ // To be called before any other methods on this object, except
+ // getFormat().
+ virtual status_t start(MetaData *params = NULL) = 0;
+
+ // Any blocking read call returns immediately with a result of NO_INIT.
+ // It is an error to call any methods other than start after this call
+ // returns. Any buffers the object may be holding onto at the time of
+ // the stop() call are released.
+ // Also, it is imperative that any buffers output by this object and
+ // held onto by callers be released before a call to stop() !!!
+ virtual status_t stop() = 0;
+
+ // Returns the format of the data output by this media source.
+ virtual sp<MetaData> getFormat() = 0;
+
+ // Options that modify read() behaviour. The default is to
+ // a) not request a seek
+ // b) not be late, i.e. lateness_us = 0
+ struct ReadOptions {
+ enum SeekMode {
+ SEEK_PREVIOUS_SYNC,
+ SEEK_NEXT_SYNC,
+ SEEK_CLOSEST_SYNC,
+ SEEK_CLOSEST,
+ };
+
+ ReadOptions();
+
+ // Reset everything back to defaults.
+ void reset();
+
+ void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
+ void clearSeekTo();
+ bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
+
+ void setLateBy(int64_t lateness_us);
+ int64_t getLateBy() const;
+
+ void setNonBlocking();
+ void clearNonBlocking();
+ bool getNonBlocking() const;
+
+ private:
+ enum Options {
+ kSeekTo_Option = 1,
+ };
+
+ uint32_t mOptions;
+ int64_t mSeekTimeUs;
+ SeekMode mSeekMode;
+ int64_t mLatenessUs;
+ bool mNonBlocking;
+ };
+
+ // Returns a new buffer of data. Call blocks until a
+ // buffer is available, an error is encountered of the end of the stream
+ // is reached.
+ // End of stream is signalled by a result of ERROR_END_OF_STREAM.
+ // A result of INFO_FORMAT_CHANGED indicates that the format of this
+ // MediaSource has changed mid-stream, the client can continue reading
+ // but should be prepared for buffers of the new configuration.
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
+
+ // Causes this source to suspend pulling data from its upstream source
+ // until a subsequent read-with-seek. Currently only supported by
+ // OMXCodec.
+ virtual status_t pause() = 0;
+
+ // The consumer of this media source requests that the given buffers
+ // are to be returned exclusively in response to read calls.
+ // This will be called after a successful start() and before the
+ // first read() call.
+ // Callee assumes ownership of the buffers if no error is returned.
+ virtual status_t setBuffers(const Vector<MediaBuffer *> & /* buffers */) = 0;
+
+};
+
+class BnMediaSource: public BnInterface<IMediaSource>
+{
+public:
+ BnMediaSource();
+
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+
+ virtual status_t pause() {
+ return ERROR_UNSUPPORTED;
+ }
+
+ virtual status_t setBuffers(const Vector<MediaBuffer *> & /* buffers */) {
+ return ERROR_UNSUPPORTED;
+ }
+
+protected:
+ virtual ~BnMediaSource();
+
+private:
+ MediaBufferGroup *mGroup;
+};
+
+
+} // namespace android
+
+#endif // IMEDIA_SOURCE_BASE_H_
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 27ad694..3f211bf 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -59,6 +59,7 @@
virtual status_t allocateNode(
const char *name, const sp<IOMXObserver> &observer,
+ sp<IBinder> *nodeBinder,
node_id *node) = 0;
virtual status_t freeNode(node_id node) = 0;
@@ -98,8 +99,8 @@
node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
OMX_U32 audioHwSync, native_handle_t **sidebandHandle) = 0;
- virtual status_t enableGraphicBuffers(
- node_id node, OMX_U32 port_index, OMX_BOOL enable) = 0;
+ virtual status_t enableNativeBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL graphic, OMX_BOOL enable) = 0;
virtual status_t getGraphicBufferUsage(
node_id node, OMX_U32 port_index, OMX_U32* usage) = 0;
@@ -137,13 +138,14 @@
virtual status_t signalEndOfInputStream(node_id node) = 0;
- // This API clearly only makes sense if the caller lives in the
- // same process as the callee, i.e. is the media_server, as the
- // returned "buffer_data" pointer is just that, a pointer into local
- // address space.
- virtual status_t allocateBuffer(
+ // Allocate an opaque buffer as a native handle. If component supports returning native
+ // handles, those are returned in *native_handle. Otherwise, the allocated buffer is
+ // returned in *buffer_data. This clearly only makes sense if the caller lives in the
+ // same process as the callee, i.e. is the media_server, as the returned "buffer_data"
+ // pointer is just that, a pointer into local address space.
+ virtual status_t allocateSecureBuffer(
node_id node, OMX_U32 port_index, size_t size,
- buffer_id *buffer, void **buffer_data) = 0;
+ buffer_id *buffer, void **buffer_data, native_handle_t **native_handle) = 0;
// Allocate an OMX buffer of size |allotedSize|. Use |params| as the backup buffer, which
// may be larger.
diff --git a/include/media/MediaCodecInfo.h b/include/media/MediaCodecInfo.h
index 4067b47..48d0407 100644
--- a/include/media/MediaCodecInfo.h
+++ b/include/media/MediaCodecInfo.h
@@ -33,7 +33,6 @@
struct AMessage;
class Parcel;
-struct CodecCapabilities;
typedef KeyedVector<AString, AString> CodecSettings;
@@ -44,12 +43,23 @@
};
struct Capabilities : public RefBase {
+ enum {
+ // decoder flags
+ kFlagSupportsAdaptivePlayback = 1 << 0,
+ kFlagSupportsSecurePlayback = 1 << 1,
+ kFlagSupportsTunneledPlayback = 1 << 2,
+
+ // encoder flags
+ kFlagSupportsIntraRefresh = 1 << 0,
+
+ };
+
void getSupportedProfileLevels(Vector<ProfileLevel> *profileLevels) const;
void getSupportedColorFormats(Vector<uint32_t> *colorFormats) const;
uint32_t getFlags() const;
const sp<AMessage> getDetails() const;
- private:
+ protected:
Vector<ProfileLevel> mProfileLevels;
Vector<uint32_t> mColorFormats;
uint32_t mFlags;
@@ -57,6 +67,7 @@
Capabilities();
+ private:
// read object from parcel even if object creation fails
static sp<Capabilities> FromParcel(const Parcel &parcel);
status_t writeToParcel(Parcel *parcel) const;
@@ -66,6 +77,14 @@
friend class MediaCodecInfo;
};
+ // Use a subclass to allow setting fields on construction without allowing
+ // to do the same throughout the framework.
+ struct CapabilitiesBuilder : public Capabilities {
+ void addProfileLevel(uint32_t profile, uint32_t level);
+ void addColorFormat(uint32_t format);
+ void addFlags(uint32_t flags);
+ };
+
bool isEncoder() const;
bool hasQuirk(const char *name) const;
void getSupportedMimes(Vector<AString> *mimes) const;
@@ -107,7 +126,8 @@
void addQuirk(const char *name);
status_t addMime(const char *mime);
status_t updateMime(const char *mime);
- status_t initializeCapabilities(const CodecCapabilities &caps);
+
+ 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);
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index de82554..9e5056f 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -99,6 +99,7 @@
virtual float msecsPerFrame() const = 0;
virtual status_t getPosition(uint32_t *position) const = 0;
virtual status_t getTimestamp(AudioTimestamp &ts) const = 0;
+ virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const = 0;
virtual status_t getFramesWritten(uint32_t *frameswritten) const = 0;
virtual int getSessionId() const = 0;
virtual audio_stream_type_t getAudioStreamType() const = 0;
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index d6cc4bb..c05d782 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -53,6 +53,8 @@
virtual status_t prepare() = 0;
virtual status_t start() = 0;
virtual status_t stop() = 0;
+ virtual status_t pause() = 0;
+ virtual status_t resume() = 0;
virtual status_t close() = 0;
virtual status_t reset() = 0;
virtual status_t getMaxAmplitude(int *max) = 0;
diff --git a/include/media/Modulo.h b/include/media/Modulo.h
new file mode 100644
index 0000000..23280ac
--- /dev/null
+++ b/include/media/Modulo.h
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MODULO_H
+#define ANDROID_MODULO_H
+
+namespace android {
+
+// Modulo class is used for intentionally wrapping variables such as
+// counters and timers.
+//
+// It may also be used for variables whose computation depends on the
+// associativity of addition or subtraction.
+//
+// Features:
+// 1) Modulo checks type sizes before performing operations to ensure
+// that the wrap points match. This is critical for safe modular arithmetic.
+// 2) Modulo returns Modulo types from arithmetic operations, thereby
+// avoiding unintentional use in a non-modular computation. A Modulo
+// type is converted to its base non-Modulo type through the value() function.
+// 3) Modulo separates out overflowable types from non-overflowable types.
+// A signed overflow is technically undefined in C and C++.
+// Modulo types do not participate in sanitization.
+// 4) Modulo comparisons are based on signed differences to account for wrap;
+// this is not the same as the direct comparison of values.
+// 5) Safe use of binary arithmetic operations relies on conversions of
+// signed operands to unsigned operands (which are modular arithmetic safe).
+// Conversions which are implementation-defined are assumed to use 2's complement
+// representation. (See A, B, C, D from the ISO/IEC FDIS 14882
+// Information technology — Programming languages — C++).
+//
+// A: ISO/IEC 14882:2011(E) p84 section 4.7 Integral conversions
+// (2) If the destination type is unsigned, the resulting value is the least unsigned
+// integer congruent to the source integer (modulo 2^n where n is the number of bits
+// used to represent the unsigned type). [ Note: In a two’s complement representation,
+// this conversion is conceptual and there is no change in the bit pattern (if there
+// is no truncation). — end note ]
+// (3) If the destination type is signed, the value is unchanged if it can be represented
+// in the destination type (and bit-field width); otherwise, the value is
+// implementation-defined.
+//
+// B: ISO/IEC 14882:2011(E) p88 section 5 Expressions
+// (9) Many binary operators that expect operands of arithmetic or enumeration type
+// cause conversions and yield result types in a similar way. The purpose is to
+// yield a common type, which is also the type of the result. This pattern is called
+// the usual arithmetic conversions, which are defined as follows:
+// [...]
+// Otherwise, if both operands have signed integer types or both have unsigned
+// integer types, the operand with the type of lesser integer conversion rank shall be
+// converted to the type of the operand with greater rank.
+// — Otherwise, if the operand that has unsigned integer type has rank greater than
+// or equal to the rank of the type of the other operand, the operand with signed
+// integer type shall be converted to the type of the operand with unsigned integer type.
+//
+// C: ISO/IEC 14882:2011(E) p86 section 4.13 Integer conversion rank
+// [...] The rank of long long int shall be greater than the rank of long int,
+// which shall be greater than the rank of int, which shall be greater than the
+// rank of short int, which shall be greater than the rank of signed char.
+// — The rank of any unsigned integer type shall equal the rank of the corresponding
+// signed integer type.
+//
+// D: ISO/IEC 14882:2011(E) p75 section 3.9.1 Fundamental types
+// [...] Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo
+// 2^n where n is the number of bits in the value representation of that particular
+// size of integer.
+//
+// Note:
+// Other libraries do exist for safe integer operations which can detect the
+// possibility of overflow (SafeInt from MS and safe-iop in android).
+// Signed safe computation is also possible from the art header safe_math.h.
+
+template <typename T> class Modulo {
+ T mValue;
+
+public:
+ typedef typename std::make_signed<T>::type signedT;
+ typedef typename std::make_unsigned<T>::type unsignedT;
+
+ Modulo() { } // intentionally uninitialized data
+ Modulo(const T &value) { mValue = value; }
+ const T & value() const { return mValue; } // not assignable
+ signedT signedValue() const { return mValue; }
+ unsignedT unsignedValue() const { return mValue; }
+ void getValue(T *value) const { *value = mValue; } // more type safe than value()
+
+ // modular operations valid only if size of T <= size of S.
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ Modulo<T> operator +=(const Modulo<S> &other) {
+ static_assert(sizeof(T) <= sizeof(S), "argument size mismatch");
+ mValue += other.unsignedValue();
+ return *this;
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ Modulo<T> operator -=(const Modulo<S> &other) {
+ static_assert(sizeof(T) <= sizeof(S), "argument size mismatch");
+ mValue -= other.unsignedValue();
+ return *this;
+ }
+
+ // modular operations resulting in a value valid only at the smaller of the two
+ // Modulo base type sizes, but we only allow equal sizes to avoid confusion.
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ const Modulo<T> operator +(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return Modulo<T>(mValue + other.unsignedValue());
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ const Modulo<T> operator -(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return Modulo<T>(mValue - other.unsignedValue());
+ }
+
+ // modular operations that should be checked only at the smaller of
+ // the two type sizes, but we only allow equal sizes to avoid confusion.
+ //
+ // Caution: These relational and comparison operations are not equivalent to
+ // the base type operations.
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ bool operator >(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return static_cast<signedT>(mValue - other.unsignedValue()) > 0;
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ bool operator >=(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return static_cast<signedT>(mValue - other.unsignedValue()) >= 0;
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ bool operator ==(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return static_cast<signedT>(mValue - other.unsignedValue()) == 0;
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ bool operator <=(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return static_cast<signedT>(mValue - other.unsignedValue()) <= 0;
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ bool operator <(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return static_cast<signedT>(mValue - other.unsignedValue()) < 0;
+ }
+
+
+ // modular operations with a non-Modulo type allowed with wrapping
+ // because there should be no confusion as to the meaning.
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ Modulo<T> operator +=(const S &other) {
+ mValue += unsignedT(other);
+ return *this;
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ Modulo<T> operator -=(const S &other) {
+ mValue -= unsignedT(other);
+ return *this;
+ }
+
+ // modular operations with a non-Modulo type allowed with wrapping,
+ // but we restrict this only when size of T is greater than or equal to
+ // the size of S to avoid confusion with the nature of overflow.
+ //
+ // Use of this follows left-associative style.
+ //
+ // Note: a Modulo type may be promoted by using "differences" off of
+ // a larger sized type, but we do not automate this.
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ const Modulo<T> operator +(const S &other) const {
+ static_assert(sizeof(T) >= sizeof(S), "argument size mismatch");
+ return Modulo<T>(mValue + unsignedT(other));
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ const Modulo<T> operator -(const S &other) const {
+ static_assert(sizeof(T) >= sizeof(S), "argument size mismatch");
+ return Modulo<T>(mValue - unsignedT(other));
+ }
+
+ // multiply is intentionally omitted, but it is a common operator in
+ // modular arithmetic.
+
+ // shift operations are intentionally omitted, but perhaps useful.
+ // For example, left-shifting a negative number is undefined in C++11.
+};
+
+} // namespace android
+
+#endif /* ANDROID_MODULO_H */
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 3fe749c..00df523 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -215,7 +215,6 @@
const KeyedVector<String8, String8> *headers);
status_t setDataSource(int fd, int64_t offset, int64_t length);
- status_t setDataSource(const sp<IStreamSource> &source);
status_t setDataSource(const sp<IDataSource> &source);
status_t setVideoSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 15ff82d..64e3660 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -95,6 +95,7 @@
VIDEO_ENCODER_H264 = 2,
VIDEO_ENCODER_MPEG_4_SP = 3,
VIDEO_ENCODER_VP8 = 4,
+ VIDEO_ENCODER_HEVC = 5,
VIDEO_ENCODER_LIST_END // must be the last - used to validate the video encoder type
};
@@ -233,6 +234,8 @@
status_t start();
status_t stop();
status_t reset();
+ status_t pause();
+ status_t resume();
status_t init();
status_t close();
status_t release();
diff --git a/include/media/nbaio/AudioBufferProviderSource.h b/include/media/nbaio/AudioBufferProviderSource.h
index b16e20a..4747dcf 100644
--- a/include/media/nbaio/AudioBufferProviderSource.h
+++ b/include/media/nbaio/AudioBufferProviderSource.h
@@ -42,9 +42,8 @@
//virtual size_t framesOverrun();
//virtual size_t overruns();
virtual ssize_t availableToRead();
- virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
- virtual ssize_t readVia(readVia_t via, size_t total, void *user,
- int64_t readPTS, size_t block);
+ virtual ssize_t read(void *buffer, size_t count);
+ virtual ssize_t readVia(readVia_t via, size_t total, void *user, size_t block);
private:
AudioBufferProvider * const mProvider;
diff --git a/include/media/nbaio/AudioStreamInSource.h b/include/media/nbaio/AudioStreamInSource.h
index 5169f1e..eaea63c 100644
--- a/include/media/nbaio/AudioStreamInSource.h
+++ b/include/media/nbaio/AudioStreamInSource.h
@@ -45,7 +45,7 @@
// FIXME Use an audio HAL API to query the buffer filling status when it's available.
virtual ssize_t availableToRead() { return mStreamBufferSizeBytes / mFrameSize; }
- virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
+ virtual ssize_t read(void *buffer, size_t count);
// NBAIO_Sink end
diff --git a/include/media/nbaio/AudioStreamOutSink.h b/include/media/nbaio/AudioStreamOutSink.h
index 9949b88..0998d45 100644
--- a/include/media/nbaio/AudioStreamOutSink.h
+++ b/include/media/nbaio/AudioStreamOutSink.h
@@ -47,11 +47,6 @@
virtual ssize_t write(const void *buffer, size_t count);
- // AudioStreamOutSink wraps a HAL's output stream. Its
- // getNextWriteTimestamp method is simply a passthru to the HAL's underlying
- // implementation of GNWT (if any)
- virtual status_t getNextWriteTimestamp(int64_t *timestamp);
-
virtual status_t getTimestamp(AudioTimestamp& timestamp);
// NBAIO_Sink end
diff --git a/include/media/nbaio/MonoPipe.h b/include/media/nbaio/MonoPipe.h
index b09b35f..df9cafe 100644
--- a/include/media/nbaio/MonoPipe.h
+++ b/include/media/nbaio/MonoPipe.h
@@ -18,7 +18,6 @@
#define ANDROID_AUDIO_MONO_PIPE_H
#include <time.h>
-#include <utils/LinearTransform.h>
#include "NBAIO.h"
#include <media/SingleStateQueue.h>
@@ -60,20 +59,6 @@
virtual ssize_t write(const void *buffer, size_t count);
//virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block);
- // MonoPipe's implementation of getNextWriteTimestamp works in conjunction
- // with MonoPipeReader. Every time a MonoPipeReader reads from the pipe, it
- // receives a "readPTS" indicating the point in time for which the reader
- // would like to read data. This "last read PTS" is offset by the amt of
- // data the reader is currently mixing and then cached cached along with the
- // updated read pointer. This cached value is the local time for which the
- // reader is going to request data next time it reads data (assuming we are
- // in steady state and operating with no underflows). Writers to the
- // MonoPipe who would like to know when their next write operation will hit
- // the speakers can call getNextWriteTimestamp which will return the value
- // of the last read PTS plus the duration of the amt of data waiting to be
- // read in the MonoPipe.
- virtual status_t getNextWriteTimestamp(int64_t *timestamp);
-
// average number of frames present in the pipe under normal conditions.
// See throttling mechanism in MonoPipe::write()
size_t getAvgFrames() const { return mSetpoint; }
@@ -95,43 +80,21 @@
status_t getTimestamp(AudioTimestamp& timestamp);
private:
- // A pair of methods and a helper variable which allows the reader and the
- // writer to update and observe the values of mFront and mNextRdPTS in an
- // atomic lock-less fashion.
- //
- // :: Important ::
- // Two assumptions must be true in order for this lock-less approach to
- // function properly on all systems. First, there may only be one updater
- // thread in the system. Second, the updater thread must be running at a
- // strictly higher priority than the observer threads. Currently, both of
- // these assumptions are true. The only updater is always a single
- // FastMixer thread (which runs with SCHED_FIFO/RT priority while the only
- // observer is always an AudioFlinger::PlaybackThread running with
- // traditional (non-RT) audio priority.
- void updateFrontAndNRPTS(int32_t newFront, int64_t newNextRdPTS);
- void observeFrontAndNRPTS(int32_t *outFront, int64_t *outNextRdPTS);
- volatile int32_t mUpdateSeq;
-
const size_t mReqFrames; // as requested in constructor, unrounded
const size_t mMaxFrames; // always a power of 2
void * const mBuffer;
// mFront and mRear will never be separated by more than mMaxFrames.
// 32-bit overflow is possible if the pipe is active for a long time, but if that happens it's
// safe because we "&" with (mMaxFrames-1) at end of computations to calculate a buffer index.
- volatile int32_t mFront; // written by the reader with updateFrontAndNRPTS, observed by
- // the writer with observeFrontAndNRPTS
+ volatile int32_t mFront; // written by reader with android_atomic_release_store,
+ // read by writer with android_atomic_acquire_load
volatile int32_t mRear; // written by writer with android_atomic_release_store,
// read by reader with android_atomic_acquire_load
- volatile int64_t mNextRdPTS; // written by the reader with updateFrontAndNRPTS, observed by
- // the writer with observeFrontAndNRPTS
bool mWriteTsValid; // whether mWriteTs is valid
struct timespec mWriteTs; // time that the previous write() completed
size_t mSetpoint; // target value for pipe fill depth
const bool mWriteCanBlock; // whether write() should block if the pipe is full
- int64_t offsetTimestampByAudioFrames(int64_t ts, size_t audFrames);
- LinearTransform mSamplesToLocalTime;
-
bool mIsShutdown; // whether shutdown(true) was called, no barriers are needed
AudioTimestampSingleStateQueue::Shared mTimestampShared;
diff --git a/include/media/nbaio/MonoPipeReader.h b/include/media/nbaio/MonoPipeReader.h
index 78fe867..4a7c3c5 100644
--- a/include/media/nbaio/MonoPipeReader.h
+++ b/include/media/nbaio/MonoPipeReader.h
@@ -47,7 +47,7 @@
virtual ssize_t availableToRead();
- virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
+ virtual ssize_t read(void *buffer, size_t count);
virtual void onTimestamp(const AudioTimestamp& timestamp);
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
index d9bbc8d..2f7e291 100644
--- a/include/media/nbaio/NBAIO.h
+++ b/include/media/nbaio/NBAIO.h
@@ -79,8 +79,7 @@
// Callbacks used by NBAIO_Sink::writeVia() and NBAIO_Source::readVia() below.
typedef ssize_t (*writeVia_t)(void *user, void *buffer, size_t count);
-typedef ssize_t (*readVia_t)(void *user, const void *buffer,
- size_t count, int64_t readPTS);
+typedef ssize_t (*readVia_t)(void *user, const void *buffer, size_t count);
// Check whether an NBAIO_Format is valid
bool Format_isValid(const NBAIO_Format& format);
@@ -210,21 +209,6 @@
// < 0 status_t error occurred prior to the first frame transfer during this callback.
virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block = 0);
- // Get the time (on the LocalTime timeline) at which the first frame of audio of the next write
- // operation to this sink will be eventually rendered by the HAL.
- // Inputs:
- // ts A pointer pointing to the int64_t which will hold the result.
- // Return value:
- // OK Everything went well, *ts holds the time at which the first audio frame of the next
- // write operation will be rendered, or AudioBufferProvider::kInvalidPTS if this sink
- // does not know the answer for some reason. Sinks which eventually lead to a HAL
- // which implements get_next_write_timestamp may return Invalid temporarily if the DMA
- // output of the audio driver has not started yet. Sinks which lead to a HAL which
- // does not implement get_next_write_timestamp, or which don't lead to a HAL at all,
- // will always return kInvalidPTS.
- // <other> Something unexpected happened internally. Check the logs and start debugging.
- virtual status_t getNextWriteTimestamp(int64_t *ts) { return INVALID_OPERATION; }
-
// Returns NO_ERROR if a timestamp is available. The timestamp includes the total number
// of frames presented to an external observer, together with the value of CLOCK_MONOTONIC
// as of this presentation count. The timestamp parameter is undefined if error is returned.
@@ -271,8 +255,6 @@
// Inputs:
// buffer Non-NULL destination buffer owned by consumer.
// count Maximum number of frames to transfer.
- // readPTS The presentation time (on the LocalTime timeline) for which data
- // is being requested, or kInvalidPTS if not known.
// Return value:
// > 0 Number of frames successfully transferred prior to first error.
// = 0 Count was zero.
@@ -282,7 +264,7 @@
// WOULD_BLOCK No frames can be transferred without blocking.
// OVERRUN read() has not been called frequently enough, or with enough frames to keep up.
// One or more frames were lost due to overrun, try again to read more recent data.
- virtual ssize_t read(void *buffer, size_t count, int64_t readPTS) = 0;
+ virtual ssize_t read(void *buffer, size_t count) = 0;
// Transfer data from source using a series of callbacks. More suitable for zero-fill,
// synthesis, and non-contiguous transfers (e.g. circular buffer or readv).
@@ -291,8 +273,6 @@
// total Estimate of the number of frames the consumer desires. This is an estimate,
// and it can consume a different number of frames during the series of callbacks.
// user Arbitrary void * reserved for data consumer.
- // readPTS The presentation time (on the LocalTime timeline) for which data
- // is being requested, or kInvalidPTS if not known.
// block Number of frames per block, that is a suggested value for 'count' in each callback.
// Zero means no preference. This parameter is a hint only, and may be ignored.
// Return value:
@@ -315,8 +295,7 @@
// > 0 Number of frames successfully transferred during this callback prior to first error.
// = 0 Count was zero.
// < 0 status_t error occurred prior to the first frame transfer during this callback.
- virtual ssize_t readVia(readVia_t via, size_t total, void *user,
- int64_t readPTS, size_t block = 0);
+ virtual ssize_t readVia(readVia_t via, size_t total, void *user, size_t block = 0);
// Invoked asynchronously by corresponding sink when a new timestamp is available.
// Default implementation ignores the timestamp.
diff --git a/include/media/nbaio/PipeReader.h b/include/media/nbaio/PipeReader.h
index 350e6ab..398353b 100644
--- a/include/media/nbaio/PipeReader.h
+++ b/include/media/nbaio/PipeReader.h
@@ -45,7 +45,7 @@
virtual ssize_t availableToRead();
- virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
+ virtual ssize_t read(void *buffer, size_t count);
// NBAIO_Source end
diff --git a/include/media/nbaio/SourceAudioBufferProvider.h b/include/media/nbaio/SourceAudioBufferProvider.h
index daf6bc3..29172e1 100644
--- a/include/media/nbaio/SourceAudioBufferProvider.h
+++ b/include/media/nbaio/SourceAudioBufferProvider.h
@@ -31,7 +31,7 @@
virtual ~SourceAudioBufferProvider();
// AudioBufferProvider interface
- virtual status_t getNextBuffer(Buffer *buffer, int64_t pts);
+ virtual status_t getNextBuffer(Buffer *buffer);
virtual void releaseBuffer(Buffer *buffer);
// ExtendedAudioBufferProvider interface
diff --git a/include/media/stagefright/AACWriter.h b/include/media/stagefright/AACWriter.h
index aa60a19..a1f63d7 100644
--- a/include/media/stagefright/AACWriter.h
+++ b/include/media/stagefright/AACWriter.h
@@ -31,7 +31,7 @@
status_t initCheck() const;
- virtual status_t addSource(const sp<MediaSource> &source);
+ virtual status_t addSource(const sp<IMediaSource> &source);
virtual bool reachedEOS();
virtual status_t start(MetaData *params = NULL);
virtual status_t stop() { return reset(); }
@@ -48,7 +48,7 @@
int mFd;
status_t mInitCheck;
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
bool mStarted;
volatile bool mPaused;
volatile bool mResumed;
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 8b5b862..4489d37 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -26,6 +26,7 @@
#include <media/stagefright/CodecBase.h>
#include <media/stagefright/FrameRenderTracker.h>
#include <media/stagefright/SkipCutBuffer.h>
+#include <utils/NativeHandle.h>
#include <OMX_Audio.h>
#define TRACK_BUFFER_TIMING 0
@@ -50,6 +51,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);
+
virtual status_t setSurface(const sp<Surface> &surface);
virtual void signalFlush();
@@ -68,15 +73,21 @@
size_t countBuffers();
IOMX::buffer_id bufferIDAt(size_t index) const;
sp<ABuffer> bufferAt(size_t index) const;
+ sp<NativeHandle> handleAt(size_t index) const;
+ sp<RefBase> memRefAt(size_t index) const;
private:
friend struct ACodec;
Vector<IOMX::buffer_id> mBufferIDs;
Vector<sp<ABuffer> > mBuffers;
+ Vector<sp<NativeHandle> > mHandles;
+ Vector<sp<RefBase> > mMemRefs;
PortDescription();
- void addBuffer(IOMX::buffer_id id, const sp<ABuffer> &buffer);
+ void addBuffer(
+ IOMX::buffer_id id, const sp<ABuffer> &buffer,
+ const sp<NativeHandle> &handle, const sp<RefBase> &memRef);
DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
};
@@ -91,6 +102,14 @@
int width, int height, int rate, int bitrate,
OMX_VIDEO_AVCPROFILETYPE profile = OMX_VIDEO_AVCProfileBaseline);
+ // Quirk still supported, even though deprecated
+ enum Quirks {
+ kRequiresAllocateBufferOnInputPorts = 1,
+ kRequiresAllocateBufferOnOutputPorts = 2,
+ };
+
+ static status_t getOMXChannelMapping(size_t numChannels, OMX_AUDIO_CHANNELTYPE map[]);
+
protected:
virtual ~ACodec();
@@ -170,7 +189,9 @@
unsigned mDequeuedAt;
sp<ABuffer> mData;
+ sp<RefBase> mMemRef;
sp<GraphicBuffer> mGraphicBuffer;
+ sp<NativeHandle> mNativeHandle;
int mFenceFd;
FrameRenderTracker::Info *mRenderInfo;
@@ -217,6 +238,7 @@
uint32_t mFlags;
uint32_t mQuirks;
sp<IOMX> mOMX;
+ sp<IBinder> mNodeBinder;
IOMX::node_id mNode;
sp<MemoryDealer> mDealer[2];
@@ -301,6 +323,10 @@
ssize_t *index = NULL);
status_t setComponentRole(bool isEncoder, const char *mime);
+ static const char *getComponentRole(bool isEncoder, const char *mime);
+ static status_t setComponentRole(
+ const sp<IOMX> &omx, IOMX::node_id node, const char *role);
+
status_t configureCodec(const char *mime, const sp<AMessage> &msg);
status_t configureTunneledVideoPlayback(int32_t audioHwSync,
@@ -358,6 +384,8 @@
status_t setPriority(int32_t priority);
status_t setOperatingRate(float rateFloat, bool isVideo);
+ status_t getIntraRefreshPeriod(uint32_t *intraRefreshPeriod);
+ status_t setIntraRefreshPeriod(uint32_t intraRefreshPeriod, bool inConfigure);
status_t setMinBufferSize(OMX_U32 portIndex, size_t size);
diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h
index b38be55..fbbdf2e 100644
--- a/include/media/stagefright/AMRWriter.h
+++ b/include/media/stagefright/AMRWriter.h
@@ -20,12 +20,12 @@
#include <stdio.h>
+#include <media/IMediaSource.h>
#include <media/stagefright/MediaWriter.h>
#include <utils/threads.h>
namespace android {
-struct MediaSource;
class MetaData;
struct AMRWriter : public MediaWriter {
@@ -33,7 +33,7 @@
status_t initCheck() const;
- virtual status_t addSource(const sp<MediaSource> &source);
+ virtual status_t addSource(const sp<IMediaSource> &source);
virtual bool reachedEOS();
virtual status_t start(MetaData *params = NULL);
virtual status_t stop() { return reset(); }
@@ -45,7 +45,7 @@
private:
int mFd;
status_t mInitCheck;
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
bool mStarted;
volatile bool mPaused;
volatile bool mResumed;
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index e0cd965..f7499b6 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -18,9 +18,9 @@
#define AUDIO_PLAYER_H_
+#include <media/IMediaSource.h>
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/TimeSource.h>
#include <utils/threads.h>
namespace android {
@@ -28,9 +28,8 @@
struct AudioPlaybackRate;
class AudioTrack;
struct AwesomePlayer;
-class MediaSource;
-class AudioPlayer : public TimeSource {
+class AudioPlayer {
public:
enum {
REACHED_EOS,
@@ -46,29 +45,18 @@
};
AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink,
- uint32_t flags = 0,
- AwesomePlayer *audioObserver = NULL);
+ uint32_t flags = 0);
virtual ~AudioPlayer();
// Caller retains ownership of "source".
- void setSource(const sp<MediaSource> &source);
-
- // Return time in us.
- virtual int64_t getRealTimeUs();
+ void setSource(const sp<IMediaSource> &source);
status_t start(bool sourceAlreadyStarted = false);
void pause(bool playPendingSamples = false);
status_t resume();
- // Returns the timestamp of the last buffer played (in us).
- int64_t getMediaTimeUs();
-
- // Returns true iff a mapping is established, i.e. the AudioPlayer
- // has played at least one frame of audio.
- bool getMediaTimeMapping(int64_t *realtime_us, int64_t *mediatime_us);
-
status_t seekTo(int64_t time_us);
bool isSeeking();
@@ -77,11 +65,8 @@
status_t setPlaybackRate(const AudioPlaybackRate &rate);
status_t getPlaybackRate(AudioPlaybackRate *rate /* nonnull */);
- void notifyAudioEOS();
-
private:
- friend class VideoEditorAudioPlayer;
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
sp<AudioTrack> mAudioTrack;
MediaBuffer *mInputBuffer;
@@ -109,8 +94,6 @@
MediaBuffer *mFirstBuffer;
sp<MediaPlayerBase::AudioSink> mAudioSink;
- AwesomePlayer *mObserver;
- int64_t mPinnedTimeUs;
bool mPlaying;
int64_t mStartPosUs;
@@ -126,11 +109,8 @@
size_t fillBuffer(void *data, size_t size);
- int64_t getRealTimeUsLocked() const;
-
void reset();
- uint32_t getNumFramesPendingPlayout() const;
int64_t getOutputPlayPositionUs_l();
bool allowDeepBuffering() const { return (mCreateFlags & ALLOW_DEEP_BUFFERING) != 0; }
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 069e897..3d00d30 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -23,6 +23,7 @@
#include <camera/ICamera.h>
#include <camera/ICameraRecordingProxyListener.h>
#include <camera/CameraParameters.h>
+#include <gui/BufferItemConsumer.h>
#include <utils/List.h>
#include <utils/RefBase.h>
#include <utils/String16.h>
@@ -60,6 +61,8 @@
* permissions checking.
* @param clientUid the UID of the camera-using application if camera is
* NULL; otherwise ignored. Used for permissions checking.
+ * @param clientPid the PID of the camera-using application if camera is
+ * NULL; otherwise ignored. Used for permissions checking.
* @param videoSize the dimension (in pixels) of the video frame
* @param frameRate the target frames per second
* @param surface the preview surface for display where preview
@@ -80,6 +83,7 @@
int32_t cameraId,
const String16& clientName,
uid_t clientUid,
+ pid_t clientPid,
Size videoSize,
int32_t frameRate,
const sp<IGraphicBufferProducer>& surface,
@@ -122,6 +126,12 @@
virtual void signalBufferReturned(MediaBuffer* buffer);
protected:
+
+ /**
+ * The class for listening to BnCameraRecordingProxyListener. This is used to receive video
+ * buffers in VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV and VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA
+ * mode. When a frame is available, CameraSource::dataCallbackTimestamp() will be called.
+ */
class ProxyListener: public BnCameraRecordingProxyListener {
public:
ProxyListener(const sp<CameraSource>& source);
@@ -132,6 +142,28 @@
sp<CameraSource> mSource;
};
+ /**
+ * The class for listening to BufferQueue's onFrameAvailable. This is used to receive video
+ * buffers in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode. When a frame is available,
+ * CameraSource::processBufferQueueFrame() will be called.
+ */
+ class BufferQueueListener : public Thread, public BufferItemConsumer::FrameAvailableListener {
+ public:
+ BufferQueueListener(const sp<BufferItemConsumer> &consumer,
+ const sp<CameraSource> &cameraSource);
+ virtual void onFrameAvailable(const BufferItem& item);
+ virtual bool threadLoop();
+ private:
+ static const nsecs_t kFrameAvailableTimeout = 50000000; // 50ms
+
+ sp<BufferItemConsumer> mConsumer;
+ sp<CameraSource> mCameraSource;
+
+ Mutex mLock;
+ Condition mFrameAvailableSignal;
+ bool mFrameAvailable;
+ };
+
// isBinderAlive needs linkToDeath to work.
class DeathNotifier: public IBinder::DeathRecipient {
public:
@@ -169,7 +201,7 @@
int64_t mTimeBetweenFrameCaptureUs;
CameraSource(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
- int32_t cameraId, const String16& clientName, uid_t clientUid,
+ int32_t cameraId, const String16& clientName, uid_t clientUid, pid_t clientPid,
Size videoSize, int32_t frameRate,
const sp<IGraphicBufferProducer>& surface,
bool storeMetaDataInVideoBuffers);
@@ -204,26 +236,49 @@
int32_t mNumGlitches;
int64_t mGlitchDurationThresholdUs;
bool mCollectStats;
- bool mIsMetaDataStoredInVideoBuffers;
+
+ // The mode video buffers are received from camera. One of VIDEO_BUFFER_MODE_*.
+ int32_t mVideoBufferMode;
+
+ /**
+ * The following variables are used in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
+ */
+ static const size_t kConsumerBufferCount = 8;
+ // Consumer and producer of the buffer queue between this class and camera.
+ sp<BufferItemConsumer> mVideoBufferConsumer;
+ sp<IGraphicBufferProducer> mVideoBufferProducer;
+ // Memory used to send the buffers to encoder, where sp<IMemory> stores VideoNativeMetadata.
+ sp<IMemoryHeap> mMemoryHeapBase;
+ List<sp<IMemory>> mMemoryBases;
+ // A mapping from ANativeWindowBuffer sent to encoder to BufferItem received from camera.
+ // This is protected by mLock.
+ KeyedVector<ANativeWindowBuffer*, BufferItem> mReceivedBufferItemMap;
+ sp<BufferQueueListener> mBufferQueueListener;
void releaseQueuedFrames();
void releaseOneRecordingFrame(const sp<IMemory>& frame);
-
+ // Process a buffer item received in BufferQueueListener.
+ void processBufferQueueFrame(const BufferItem& buffer);
status_t init(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
- int32_t cameraId, const String16& clientName, uid_t clientUid,
+ int32_t cameraId, const String16& clientName, uid_t clientUid, pid_t clientPid,
Size videoSize, int32_t frameRate, bool storeMetaDataInVideoBuffers);
status_t initWithCameraAccess(
const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
- int32_t cameraId, const String16& clientName, uid_t clientUid,
+ int32_t cameraId, const String16& clientName, uid_t clientUid, pid_t clientPid,
Size videoSize, int32_t frameRate, bool storeMetaDataInVideoBuffers);
+ // Initialize the buffer queue used in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
+ status_t initBufferQueue(uint32_t width, uint32_t height, uint32_t format,
+ android_dataspace dataSpace, uint32_t bufferCount);
+
status_t isCameraAvailable(const sp<ICamera>& camera,
const sp<ICameraRecordingProxy>& proxy,
int32_t cameraId,
const String16& clientName,
- uid_t clientUid);
+ uid_t clientUid,
+ pid_t clientPid);
status_t isCameraColorFormatSupported(const CameraParameters& params);
status_t configureCamera(CameraParameters* params,
@@ -236,6 +291,10 @@
status_t checkFrameRate(const CameraParameters& params,
int32_t frameRate);
+ // Check if this frame should be skipped based on the frame's timestamp in microsecond.
+ // mLock must be locked before calling this function.
+ bool shouldSkipFrameLocked(int64_t timestampUs);
+
void stopCameraRecording();
status_t reset();
diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h
index 34213be..1023027 100644
--- a/include/media/stagefright/CameraSourceTimeLapse.h
+++ b/include/media/stagefright/CameraSourceTimeLapse.h
@@ -38,6 +38,7 @@
int32_t cameraId,
const String16& clientName,
uid_t clientUid,
+ pid_t clientPid,
Size videoSize,
int32_t videoFrameRate,
const sp<IGraphicBufferProducer>& surface,
@@ -114,6 +115,7 @@
int32_t cameraId,
const String16& clientName,
uid_t clientUid,
+ pid_t clientPid,
Size videoSize,
int32_t videoFrameRate,
const sp<IGraphicBufferProducer>& surface,
diff --git a/include/media/stagefright/ClockEstimator.h b/include/media/stagefright/ClockEstimator.h
deleted file mode 100644
index 1455b7f..0000000
--- a/include/media/stagefright/ClockEstimator.h
+++ /dev/null
@@ -1,110 +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.
-*/
-
-#ifndef CLOCK_ESTIMATOR_H_
-
-#define CLOCK_ESTIMATOR_H_
-
-#include "foundation/ABase.h"
-#include <utils/RefBase.h>
-#include <utils/Vector.h>
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-struct ClockEstimator : RefBase {
- virtual double estimate(double x, double y) = 0;
- virtual void reset() = 0;
-};
-
-struct WindowedLinearFitEstimator : ClockEstimator {
- struct LinearFit {
- /**
- * Fit y = a * x + b, where each input has a weight
- */
- double mX; // sum(w_i * x_i)
- double mXX; // sum(w_i * x_i^2)
- double mY; // sum(w_i * y_i)
- double mYY; // sum(w_i * y_i^2)
- double mXY; // sum(w_i * x_i * y_i)
- double mW; // sum(w_i)
-
- LinearFit();
- void reset();
- void combine(const LinearFit &lf);
- void add(double x, double y, double w);
- void scale(double w);
- double interpolate(double x);
- double size() const;
-
- DISALLOW_EVIL_CONSTRUCTORS(LinearFit);
- };
-
- /**
- * Estimator for f(x) = y' where input y' is noisy, but
- * theoretically linear:
- *
- * y' =~ y = a * x + b
- *
- * It uses linear fit regression over a tapering rolling window
- * to get an estimate for y (from the current and past inputs
- * (x, y')).
- *
- * ____________
- * /| |\
- * / | | \
- * / | | \ <--- new data (x, y')
- * / | main | \
- * <--><----------><-->
- * tail head
- *
- * weight is 1 under the main window, tapers exponentially by
- * the factors given in the head and the tail.
- *
- * Assuming that x and y' are monotonic, that x is somewhat
- * evenly sampled, and that a =~ 1, the estimated y is also
- * going to be monotonic.
- */
- WindowedLinearFitEstimator(
- size_t headLength = 5, double headFactor = 0.5,
- size_t mainLength = 0, double tailFactor = 0.99);
-
- virtual void reset();
-
- // add a new sample (x -> y') and return an estimated value for the true y
- virtual double estimate(double x, double y);
-
-private:
- Vector<double> mXHistory; // circular buffer
- Vector<double> mYHistory; // circular buffer
- LinearFit mHead;
- LinearFit mMain;
- LinearFit mTail;
- double mHeadFactorInv;
- double mTailFactor;
- double mFirstWeight;
- size_t mHistoryLength;
- size_t mHeadLength;
- size_t mNumSamples;
- size_t mSampleIx;
-
- DISALLOW_EVIL_CONSTRUCTORS(WindowedLinearFitEstimator);
-};
-
-}; // namespace android
-
-#endif
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index bb36052..cbf9839 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -21,7 +21,9 @@
#include <stdint.h>
#include <media/IOMX.h>
+#include <media/MediaCodecInfo.h>
#include <media/stagefright/foundation/AHandler.h>
+#include <utils/NativeHandle.h>
namespace android {
@@ -59,6 +61,10 @@
// 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;
@@ -72,6 +78,8 @@
virtual size_t countBuffers() = 0;
virtual IOMX::buffer_id bufferIDAt(size_t index) const = 0;
virtual sp<ABuffer> bufferAt(size_t index) const = 0;
+ virtual sp<NativeHandle> handleAt(size_t index) { return NULL; };
+ virtual sp<RefBase> memRefAt(size_t index) const { return NULL; }
protected:
PortDescription();
diff --git a/include/media/stagefright/FileSource.h b/include/media/stagefright/FileSource.h
index a981d1c..266168b 100644
--- a/include/media/stagefright/FileSource.h
+++ b/include/media/stagefright/FileSource.h
@@ -56,7 +56,7 @@
sp<DecryptHandle> mDecryptHandle;
DrmManagerClient *mDrmManagerClient;
int64_t mDrmBufOffset;
- size_t mDrmBufSize;
+ ssize_t mDrmBufSize;
unsigned char *mDrmBuf;
ssize_t readAtDRM(off64_t offset, void *data, size_t size);
diff --git a/include/media/stagefright/MPEG2TSWriter.h b/include/media/stagefright/MPEG2TSWriter.h
index 3d7960b..4516fb6 100644
--- a/include/media/stagefright/MPEG2TSWriter.h
+++ b/include/media/stagefright/MPEG2TSWriter.h
@@ -34,7 +34,7 @@
void *cookie,
ssize_t (*write)(void *cookie, const void *data, size_t size));
- virtual status_t addSource(const sp<MediaSource> &source);
+ virtual status_t addSource(const sp<IMediaSource> &source);
virtual status_t start(MetaData *param = NULL);
virtual status_t stop() { return reset(); }
virtual status_t pause();
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index a195fe8..a6901a8 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -20,6 +20,7 @@
#include <stdio.h>
+#include <media/IMediaSource.h>
#include <media/stagefright/MediaWriter.h>
#include <utils/List.h>
#include <utils/threads.h>
@@ -28,7 +29,6 @@
class AMessage;
class MediaBuffer;
-class MediaSource;
class MetaData;
class MPEG4Writer : public MediaWriter {
@@ -39,7 +39,7 @@
// 1. No more than 2 tracks can be added
// 2. Only video or audio source can be added
// 3. No more than one video and/or one audio source can be added.
- virtual status_t addSource(const sp<MediaSource> &source);
+ virtual status_t addSource(const sp<IMediaSource> &source);
// Returns INVALID_OPERATION if there is no source or track.
virtual status_t start(MetaData *param = NULL);
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index c8a50e8..18b80e3 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -22,6 +22,7 @@
#include <pthread.h>
+#include <binder/MemoryDealer.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -47,6 +48,9 @@
class MediaBuffer : public MediaBufferBase {
public:
+ // allocations larger than or equal to this will use shared memory.
+ static const size_t kSharedMemThreshold = 64 * 1024;
+
// The underlying data remains the responsibility of the caller!
MediaBuffer(void *data, size_t size);
@@ -93,6 +97,8 @@
private:
friend class MediaBufferGroup;
friend class OMXDecoder;
+ friend class BnMediaSource;
+ friend class BpMediaSource;
// For use by OMXDecoder, reference count must be 1, drop reference
// count to 0 without signalling the observer.
@@ -118,6 +124,7 @@
MediaBuffer(const MediaBuffer &);
MediaBuffer &operator=(const MediaBuffer &);
+ sp<IMemory> mMemory;
};
} // namespace android
diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
index a006f7f..7ca3fa1 100644
--- a/include/media/stagefright/MediaBufferGroup.h
+++ b/include/media/stagefright/MediaBufferGroup.h
@@ -39,7 +39,11 @@
// The returned buffer will have a reference count of 1.
// If nonBlocking is true and a buffer is not immediately available,
// buffer is set to NULL and it returns WOULD_BLOCK.
- status_t acquire_buffer(MediaBuffer **buffer, bool nonBlocking = false);
+ // If requestedSize is 0, any free MediaBuffer will be returned.
+ // If requestedSize is > 0, the returned MediaBuffer should have buffer
+ // size of at least requstedSize.
+ status_t acquire_buffer(
+ MediaBuffer **buffer, bool nonBlocking = false, size_t requestedSize = 0);
protected:
virtual void signalBufferReturned(MediaBuffer *buffer);
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index cdfa159..2bb1291 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -20,6 +20,7 @@
#include <gui/IGraphicBufferProducer.h>
#include <media/hardware/CryptoAPI.h>
+#include <media/MediaCodecInfo.h>
#include <media/MediaResource.h>
#include <media/stagefright/foundation/AHandler.h>
#include <media/stagefright/FrameRenderTracker.h>
@@ -64,15 +65,20 @@
static const pid_t kNoPid = -1;
static sp<MediaCodec> CreateByType(
- const sp<ALooper> &looper, const char *mime, bool encoder, status_t *err = NULL,
+ const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err = NULL,
pid_t pid = kNoPid);
static sp<MediaCodec> CreateByComponentName(
- const sp<ALooper> &looper, const char *name, status_t *err = NULL,
+ const sp<ALooper> &looper, const AString &name, status_t *err = NULL,
pid_t pid = kNoPid);
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,
@@ -119,6 +125,7 @@
const uint8_t key[16],
const uint8_t iv[16],
CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern &pattern,
int64_t presentationTimeUs,
uint32_t flags,
AString *errorDetailMsg = NULL);
@@ -247,6 +254,8 @@
struct BufferInfo {
uint32_t mBufferID;
sp<ABuffer> mData;
+ sp<NativeHandle> mNativeHandle;
+ sp<RefBase> mMemRef;
sp<ABuffer> mEncryptedData;
sp<IMemory> mSharedEncryptedBuffer;
sp<AMessage> mNotify;
@@ -339,6 +348,8 @@
MediaCodec(const sp<ALooper> &looper, pid_t pid);
+ static sp<CodecBase> GetCodecBase(const AString &name, bool nameIsType = false);
+
static status_t PostAndAwaitResponse(
const sp<AMessage> &msg, sp<AMessage> *response);
@@ -347,8 +358,8 @@
status_t init(const AString &name, bool nameIsType, bool encoder);
void setState(State newState);
- void returnBuffersToCodec();
- void returnBuffersToCodecOnPort(int32_t portIndex);
+ void returnBuffersToCodec(bool isReclaim = false);
+ void returnBuffersToCodecOnPort(int32_t portIndex, bool isReclaim = false);
size_t updateBuffers(int32_t portIndex, const sp<AMessage> &msg);
status_t onQueueInputBuffer(const sp<AMessage> &msg);
status_t onReleaseOutputBuffer(const sp<AMessage> &msg);
diff --git a/include/media/stagefright/MediaCodecList.h b/include/media/stagefright/MediaCodecList.h
index bf4db87..44dbde0 100644
--- a/include/media/stagefright/MediaCodecList.h
+++ b/include/media/stagefright/MediaCodecList.h
@@ -65,6 +65,22 @@
// only to be used by MediaPlayerService
void parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
+ enum Flags {
+ kPreferSoftwareCodecs = 1,
+ kHardwareCodecsOnly = 2,
+ };
+
+ static void findMatchingCodecs(
+ const char *mime,
+ bool createEncoder,
+ uint32_t flags,
+ Vector<AString> *matching);
+
+ static uint32_t getQuirksFor(const char *mComponentName);
+
+ static bool isSoftwareCodec(const AString &componentName);
+
+
private:
class BinderDeathObserver : public IBinder::DeathRecipient {
void binderDied(const wp<IBinder> &the_late_who __unused);
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index 71f58a9..e3f3f5e 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -19,16 +19,18 @@
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AHandlerReflector.h>
+#include <media/stagefright/foundation/Mutexed.h>
#include <media/stagefright/MediaSource.h>
+#include <gui/IGraphicBufferConsumer.h>
+
namespace android {
struct ALooper;
-class AMessage;
+struct AMessage;
struct AReplyToken;
class IGraphicBufferProducer;
-class IGraphicBufferConsumer;
-class MediaCodec;
+struct MediaCodec;
class MetaData;
struct MediaCodecSource : public MediaSource,
@@ -36,6 +38,7 @@
enum FlagBits {
FLAG_USE_SURFACE_INPUT = 1,
FLAG_USE_METADATA_INPUT = 2,
+ FLAG_PREFER_SOFTWARE_CODEC = 4, // used for testing only
};
static sp<MediaCodecSource> Create(
@@ -47,6 +50,7 @@
bool isVideo() const { return mIsVideo; }
sp<IGraphicBufferProducer> getGraphicBufferProducer();
+ void setInputBufferTimeOffset(int64_t timeOffsetUs);
// MediaSource
virtual status_t start(MetaData *params = NULL);
@@ -75,6 +79,8 @@
kWhatStart,
kWhatStop,
kWhatPause,
+ kWhatSetInputBufferTimeOffset,
+ kWhatStopStalled,
};
MediaCodecSource(
@@ -117,17 +123,22 @@
List<MediaBuffer *> mInputBufferQueue;
List<size_t> mAvailEncoderInputIndices;
List<int64_t> mDecodingTimeQueue; // decoding time (us) for video
+ int64_t mInputBufferTimeOffsetUs;
// audio drift time
int64_t mFirstSampleTimeUs;
List<int64_t> mDriftTimeQueue;
- // following variables are protected by mOutputBufferLock
- Mutex mOutputBufferLock;
- Condition mOutputBufferCond;
- List<MediaBuffer*> mOutputBufferQueue;
- bool mEncoderReachedEOS;
- status_t mErrorCode;
+ struct Output {
+ Output();
+ List<MediaBuffer*> mBufferQueue;
+ bool mEncoderReachedEOS;
+ status_t mErrorCode;
+ Condition mCond;
+ };
+ Mutexed<Output> mOutput;
+
+ int32_t mGeneration;
DISALLOW_EVIL_CONSTRUCTORS(MediaCodecSource);
};
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 21eb04a..e5bcec6 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -30,6 +30,7 @@
extern const char *MEDIA_MIMETYPE_VIDEO_H263;
extern const char *MEDIA_MIMETYPE_VIDEO_MPEG2;
extern const char *MEDIA_MIMETYPE_VIDEO_RAW;
+extern const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
@@ -64,6 +65,7 @@
extern const char *MEDIA_MIMETYPE_TEXT_SUBRIP;
extern const char *MEDIA_MIMETYPE_TEXT_VTT;
extern const char *MEDIA_MIMETYPE_TEXT_CEA_608;
+extern const char *MEDIA_MIMETYPE_TEXT_CEA_708;
extern const char *MEDIA_MIMETYPE_DATA_TIMED_ID3;
} // namespace android
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 183933a..6bf8c9e 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -18,7 +18,8 @@
#define MEDIA_EXTRACTOR_H_
-#include <utils/RefBase.h>
+#include <media/IMediaExtractor.h>
+#include <media/IMediaSource.h>
namespace android {
@@ -26,13 +27,15 @@
class MediaSource;
class MetaData;
-class MediaExtractor : public RefBase {
+class MediaExtractor : public BnMediaExtractor {
public:
- static sp<MediaExtractor> Create(
+ static sp<IMediaExtractor> Create(
+ const sp<DataSource> &source, const char *mime = NULL);
+ static sp<MediaExtractor> CreateFromService(
const sp<DataSource> &source, const char *mime = NULL);
virtual size_t countTracks() = 0;
- virtual sp<MediaSource> getTrack(size_t index) = 0;
+ virtual sp<IMediaSource> getTrack(size_t index) = 0;
enum GetTrackMetaDataFlags {
kIncludeExtensiveMetaData = 1
@@ -68,8 +71,10 @@
virtual void setUID(uid_t uid) {
}
+ virtual const char * name() { return "<unspecified>"; }
+
protected:
- MediaExtractor() : mIsDrm(false) {}
+ MediaExtractor();
virtual ~MediaExtractor() {}
private:
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
index a653db9..1bd3ed0 100644
--- a/include/media/stagefright/MediaSource.h
+++ b/include/media/stagefright/MediaSource.h
@@ -20,6 +20,7 @@
#include <sys/types.h>
+#include <media/IMediaSource.h>
#include <media/stagefright/MediaErrors.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
@@ -29,7 +30,7 @@
class MediaBuffer;
class MetaData;
-struct MediaSource : public virtual RefBase {
+struct MediaSource : public BnMediaSource {
MediaSource();
// To be called before any other methods on this object, except
@@ -47,8 +48,6 @@
// Returns the format of the data output by this media source.
virtual sp<MetaData> getFormat() = 0;
- struct ReadOptions;
-
// Returns a new buffer of data. Call blocks until a
// buffer is available, an error is encountered of the end of the stream
// is reached.
@@ -59,48 +58,10 @@
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
- // Options that modify read() behaviour. The default is to
- // a) not request a seek
- // b) not be late, i.e. lateness_us = 0
- struct ReadOptions {
- enum SeekMode {
- SEEK_PREVIOUS_SYNC,
- SEEK_NEXT_SYNC,
- SEEK_CLOSEST_SYNC,
- SEEK_CLOSEST,
- };
-
- ReadOptions();
-
- // Reset everything back to defaults.
- void reset();
-
- void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
- void clearSeekTo();
- bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
-
- void setLateBy(int64_t lateness_us);
- int64_t getLateBy() const;
-
- void setNonBlocking();
- void clearNonBlocking();
- bool getNonBlocking() const;
-
- private:
- enum Options {
- kSeekTo_Option = 1,
- };
-
- uint32_t mOptions;
- int64_t mSeekTimeUs;
- SeekMode mSeekMode;
- int64_t mLatenessUs;
- bool mNonBlocking;
- };
-
// Causes this source to suspend pulling data from its upstream source
- // until a subsequent read-with-seek. Currently only supported by
- // OMXCodec.
+ // until a subsequent read-with-seek. This is currently not supported
+ // as such by any source. E.g. MediaCodecSource does not suspend its
+ // upstream source, and instead discard upstream data while paused.
virtual status_t pause() {
return ERROR_UNSUPPORTED;
}
diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h
index 8e02506..b6476c9 100644
--- a/include/media/stagefright/MediaWriter.h
+++ b/include/media/stagefright/MediaWriter.h
@@ -20,10 +20,10 @@
#include <utils/RefBase.h>
#include <media/IMediaRecorderClient.h>
+#include <media/IMediaSource.h>
namespace android {
-struct MediaSource;
class MetaData;
struct MediaWriter : public RefBase {
@@ -32,7 +32,7 @@
mMaxFileDurationLimitUs(0) {
}
- virtual status_t addSource(const sp<MediaSource> &source) = 0;
+ virtual status_t addSource(const sp<IMediaSource> &source) = 0;
virtual bool reachedEOS() = 0;
virtual status_t start(MetaData *params = NULL) = 0;
virtual status_t stop() = 0;
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 8d4e15a..91341b8 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -22,6 +22,7 @@
#include <stdint.h>
+#include <binder/Parcel.h>
#include <utils/RefBase.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
@@ -181,6 +182,12 @@
// H264 supplemental enhancement information offsets/sizes
kKeySEI = 'sei ', // raw data
+
+ // MPEG user data offsets
+ kKeyMpegUserData = 'mpud', // size_t[]
+
+ // Size of NALU length in mkv/mp4
+ kKeyNalLengthSize = 'nals', // int32_t
};
enum {
@@ -239,6 +246,10 @@
void dumpToLog() const;
+ status_t writeToParcel(Parcel &parcel);
+ status_t updateFromParcel(const Parcel &parcel);
+ static sp<MetaData> createFromParcel(const Parcel &parcel);
+
protected:
virtual ~MetaData();
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index fd74452..b8bb824 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -19,6 +19,7 @@
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/MediaSource.h>
+#include <media/IMediaExtractor.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@@ -84,7 +85,7 @@
};
struct TrackInfo {
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
size_t mTrackIndex;
status_t mFinalResult;
MediaBuffer *mSample;
@@ -97,7 +98,7 @@
sp<DataSource> mDataSource;
- sp<MediaExtractor> mImpl;
+ sp<IMediaExtractor> mImpl;
bool mIsWidevineExtractor;
Vector<TrackInfo> mSelectedTracks;
@@ -113,6 +114,7 @@
bool getTotalBitrate(int64_t *bitRate) const;
void updateDurationAndBitrate();
+ status_t appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer);
DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor);
};
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
deleted file mode 100644
index 7fabcb3..0000000
--- a/include/media/stagefright/OMXCodec.h
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef OMX_CODEC_H_
-
-#define OMX_CODEC_H_
-
-#include <android/native_window.h>
-#include <media/IOMX.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/threads.h>
-
-#include <OMX_Audio.h>
-
-namespace android {
-
-struct MediaCodecInfo;
-class MemoryDealer;
-struct OMXCodecObserver;
-struct CodecProfileLevel;
-class SkipCutBuffer;
-
-struct OMXCodec : public MediaSource,
- public MediaBufferObserver {
- enum CreationFlags {
- kPreferSoftwareCodecs = 1,
- kIgnoreCodecSpecificData = 2,
-
- // The client wants to access the output buffer's video
- // data for example for thumbnail extraction.
- kClientNeedsFramebuffer = 4,
-
- // Request for software or hardware codecs. If request
- // can not be fullfilled, Create() returns NULL.
- kSoftwareCodecsOnly = 8,
- kHardwareCodecsOnly = 16,
-
- // Store meta data in video buffers
- kStoreMetaDataInVideoBuffers = 32,
-
- // Only submit one input buffer at one time.
- kOnlySubmitOneInputBufferAtOneTime = 64,
-
- // Enable GRALLOC_USAGE_PROTECTED for output buffers from native window
- kEnableGrallocUsageProtected = 128,
-
- // Secure decoding mode
- kUseSecureInputBuffers = 256,
- };
- static sp<MediaSource> Create(
- const sp<IOMX> &omx,
- const sp<MetaData> &meta, bool createEncoder,
- const sp<MediaSource> &source,
- const char *matchComponentName = NULL,
- uint32_t flags = 0,
- const sp<ANativeWindow> &nativeWindow = NULL);
-
- static void setComponentRole(
- const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
- const char *mime);
-
- virtual status_t start(MetaData *params = NULL);
- virtual status_t stop();
-
- virtual sp<MetaData> getFormat();
-
- virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
-
- virtual status_t pause();
-
- // from MediaBufferObserver
- virtual void signalBufferReturned(MediaBuffer *buffer);
-
- enum Quirks {
- kNeedsFlushBeforeDisable = 1,
- kWantsNALFragments = 2,
- kRequiresLoadedToIdleAfterAllocation = 4,
- kRequiresAllocateBufferOnInputPorts = 8,
- kRequiresFlushCompleteEmulation = 16,
- kRequiresAllocateBufferOnOutputPorts = 32,
- kRequiresFlushBeforeShutdown = 64,
- kDefersOutputBufferAllocation = 128,
- kDecoderLiesAboutNumberOfChannels = 256,
- kInputBufferSizesAreBogus = 512,
- kSupportsMultipleFramesPerInputBuffer = 1024,
- kRequiresLargerEncoderOutputBuffer = 2048,
- kOutputBuffersAreUnreadable = 4096,
- };
-
- struct CodecNameAndQuirks {
- String8 mName;
- uint32_t mQuirks;
- };
-
- // for use by ACodec
- static void findMatchingCodecs(
- const char *mime,
- bool createEncoder, const char *matchComponentName,
- uint32_t flags,
- Vector<CodecNameAndQuirks> *matchingCodecNamesAndQuirks);
-
- static uint32_t getComponentQuirks(
- const sp<MediaCodecInfo> &list);
-
- static bool findCodecQuirks(const char *componentName, uint32_t *quirks);
-
-protected:
- virtual ~OMXCodec();
-
-private:
-
- // Make sure mLock is accessible to OMXCodecObserver
- friend class OMXCodecObserver;
-
- // Call this with mLock hold
- void on_message(const omx_message &msg);
-
- enum State {
- DEAD,
- LOADED,
- LOADED_TO_IDLE,
- IDLE_TO_EXECUTING,
- EXECUTING,
- EXECUTING_TO_IDLE,
- IDLE_TO_LOADED,
- RECONFIGURING,
- ERROR
- };
-
- enum {
- kPortIndexInput = 0,
- kPortIndexOutput = 1
- };
-
- enum PortStatus {
- ENABLED,
- DISABLING,
- DISABLED,
- ENABLING,
- SHUTTING_DOWN,
- };
-
- enum BufferStatus {
- OWNED_BY_US,
- OWNED_BY_COMPONENT,
- OWNED_BY_NATIVE_WINDOW,
- OWNED_BY_CLIENT,
- };
-
- struct BufferInfo {
- IOMX::buffer_id mBuffer;
- BufferStatus mStatus;
- sp<IMemory> mMem;
- size_t mSize;
- void *mData;
- MediaBuffer *mMediaBuffer;
- };
-
- struct CodecSpecificData {
- size_t mSize;
- uint8_t mData[1];
- };
-
- sp<IOMX> mOMX;
- bool mOMXLivesLocally;
- IOMX::node_id mNode;
- uint32_t mQuirks;
-
- // Flags specified in the creation of the codec.
- uint32_t mFlags;
-
- bool mIsEncoder;
- bool mIsVideo;
- char *mMIME;
- char *mComponentName;
- sp<MetaData> mOutputFormat;
- sp<MediaSource> mSource;
- Vector<CodecSpecificData *> mCodecSpecificData;
- size_t mCodecSpecificDataIndex;
-
- sp<MemoryDealer> mDealer[2];
-
- State mState;
- Vector<BufferInfo> mPortBuffers[2];
- PortStatus mPortStatus[2];
- bool mInitialBufferSubmit;
- bool mSignalledEOS;
- status_t mFinalStatus;
- bool mNoMoreOutputData;
- bool mOutputPortSettingsHaveChanged;
- int64_t mSeekTimeUs;
- ReadOptions::SeekMode mSeekMode;
- int64_t mTargetTimeUs;
- bool mOutputPortSettingsChangedPending;
- sp<SkipCutBuffer> mSkipCutBuffer;
-
- MediaBuffer *mLeftOverBuffer;
-
- Mutex mLock;
- Condition mAsyncCompletion;
-
- bool mPaused;
-
- sp<ANativeWindow> mNativeWindow;
-
- // The index in each of the mPortBuffers arrays of the buffer that will be
- // submitted to OMX next. This only applies when using buffers from a
- // native window.
- size_t mNextNativeBufferIndex[2];
-
- // A list of indices into mPortStatus[kPortIndexOutput] filled with data.
- List<size_t> mFilledBuffers;
- Condition mBufferFilled;
-
- // Used to record the decoding time for an output picture from
- // a video encoder.
- List<int64_t> mDecodingTimeList;
-
- OMXCodec(const sp<IOMX> &omx, IOMX::node_id node,
- uint32_t quirks, uint32_t flags,
- bool isEncoder, const char *mime, const char *componentName,
- const sp<MediaSource> &source,
- const sp<ANativeWindow> &nativeWindow);
-
- void addCodecSpecificData(const void *data, size_t size);
- void clearCodecSpecificData();
-
- void setComponentRole();
-
- void setAMRFormat(bool isWAMR, int32_t bitRate);
-
- status_t setAACFormat(
- int32_t numChannels, int32_t sampleRate, int32_t bitRate,
- int32_t aacProfile, bool isADTS);
-
- status_t setAC3Format(int32_t numChannels, int32_t sampleRate);
-
- void setG711Format(int32_t sampleRate, int32_t numChannels);
-
- status_t setVideoPortFormatType(
- OMX_U32 portIndex,
- OMX_VIDEO_CODINGTYPE compressionFormat,
- OMX_COLOR_FORMATTYPE colorFormat);
-
- void setVideoInputFormat(
- const char *mime, const sp<MetaData>& meta);
-
- status_t setupBitRate(int32_t bitRate);
- status_t setupErrorCorrectionParameters();
- status_t setupH263EncoderParameters(const sp<MetaData>& meta);
- status_t setupMPEG4EncoderParameters(const sp<MetaData>& meta);
- status_t setupAVCEncoderParameters(const sp<MetaData>& meta);
- status_t findTargetColorFormat(
- const sp<MetaData>& meta, OMX_COLOR_FORMATTYPE *colorFormat);
-
- status_t isColorFormatSupported(
- OMX_COLOR_FORMATTYPE colorFormat, int portIndex);
-
- // If profile/level is set in the meta data, its value in the meta
- // data will be used; otherwise, the default value will be used.
- status_t getVideoProfileLevel(const sp<MetaData>& meta,
- const CodecProfileLevel& defaultProfileLevel,
- CodecProfileLevel& profileLevel);
-
- status_t setVideoOutputFormat(
- const char *mime, const sp<MetaData>& meta);
-
- void setImageOutputFormat(
- OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height);
-
- void setJPEGInputFormat(
- OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize);
-
- void setMinBufferSize(OMX_U32 portIndex, OMX_U32 size);
-
- void setRawAudioFormat(
- OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels);
-
- status_t allocateBuffers();
- status_t allocateBuffersOnPort(OMX_U32 portIndex);
- status_t allocateOutputBuffersFromNativeWindow();
-
- status_t queueBufferToNativeWindow(BufferInfo *info);
- status_t cancelBufferToNativeWindow(BufferInfo *info);
- BufferInfo* dequeueBufferFromNativeWindow();
-
- status_t freeBuffersOnPort(
- OMX_U32 portIndex, bool onlyThoseWeOwn = false);
-
- status_t freeBuffer(OMX_U32 portIndex, size_t bufIndex);
-
- bool drainInputBuffer(IOMX::buffer_id buffer);
- void fillOutputBuffer(IOMX::buffer_id buffer);
- bool drainInputBuffer(BufferInfo *info);
- void fillOutputBuffer(BufferInfo *info);
-
- void drainInputBuffers();
- void fillOutputBuffers();
-
- bool drainAnyInputBuffer();
- BufferInfo *findInputBufferByDataPointer(void *ptr);
- BufferInfo *findEmptyInputBuffer();
-
- // Returns true iff a flush was initiated and a completion event is
- // upcoming, false otherwise (A flush was not necessary as we own all
- // the buffers on that port).
- // This method will ONLY ever return false for a component with quirk
- // "kRequiresFlushCompleteEmulation".
- bool flushPortAsync(OMX_U32 portIndex);
-
- void disablePortAsync(OMX_U32 portIndex);
- status_t enablePortAsync(OMX_U32 portIndex);
-
- static size_t countBuffersWeOwn(const Vector<BufferInfo> &buffers);
- static bool isIntermediateState(State state);
-
- void onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
- void onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data);
- void onStateChange(OMX_STATETYPE newState);
- void onPortSettingsChanged(OMX_U32 portIndex);
-
- void setState(State newState);
-
- status_t init();
- void initOutputFormat(const sp<MetaData> &inputFormat);
- status_t initNativeWindow();
-
- void initNativeWindowCrop();
-
- void dumpPortStatus(OMX_U32 portIndex);
-
- status_t configureCodec(const sp<MetaData> &meta);
-
- status_t waitForBufferFilled_l();
-
- int64_t getDecodingTimeUs();
-
- status_t parseHEVCCodecSpecificData(
- const void *data, size_t size,
- unsigned *profile, unsigned *level);
- status_t parseAVCCodecSpecificData(
- const void *data, size_t size,
- unsigned *profile, unsigned *level);
-
- status_t stopOmxComponent_l();
-
- OMXCodec(const OMXCodec &);
- OMXCodec &operator=(const OMXCodec &);
-};
-
-struct CodecCapabilities {
- enum {
- kFlagSupportsAdaptivePlayback = 1 << 0,
- };
-
- String8 mComponentName;
- Vector<CodecProfileLevel> mProfileLevels;
- Vector<OMX_U32> mColorFormats;
- uint32_t mFlags;
-};
-
-// Return a vector of componentNames with supported profile/level pairs
-// supporting the given mime type, if queryDecoders==true, returns components
-// that decode content of the given type, otherwise returns components
-// that encode content of the given type.
-// profile and level indications only make sense for h.263, mpeg4 and avc
-// video.
-// If hwCodecOnly==true, only returns hardware-based components, software and
-// hardware otherwise.
-// The profile/level values correspond to
-// OMX_VIDEO_H263PROFILETYPE, OMX_VIDEO_MPEG4PROFILETYPE,
-// OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263LEVELTYPE, OMX_VIDEO_MPEG4LEVELTYPE
-// and OMX_VIDEO_AVCLEVELTYPE respectively.
-
-status_t QueryCodecs(
- const sp<IOMX> &omx,
- const char *mimeType, bool queryDecoders, bool hwCodecOnly,
- Vector<CodecCapabilities> *results);
-
-status_t QueryCodecs(
- const sp<IOMX> &omx,
- const char *mimeType, bool queryDecoders,
- Vector<CodecCapabilities> *results);
-
-status_t QueryCodec(
- const sp<IOMX> &omx,
- const char *componentName, const char *mime,
- bool isEncoder,
- CodecCapabilities *caps);
-
-status_t getOMXChannelMapping(size_t numChannels, OMX_AUDIO_CHANNELTYPE map[]);
-
-} // namespace android
-
-#endif // OMX_CODEC_H_
diff --git a/include/media/stagefright/SimpleDecodingSource.h b/include/media/stagefright/SimpleDecodingSource.h
new file mode 100644
index 0000000..534097b
--- /dev/null
+++ b/include/media/stagefright/SimpleDecodingSource.h
@@ -0,0 +1,108 @@
+/*
+ * 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 SIMPLE_DECODING_SOURCE_H_
+#define SIMPLE_DECODING_SOURCE_H_
+
+#include <system/window.h>
+
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/Mutexed.h>
+
+#include <utils/Condition.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+struct ALooper;
+struct AMessage;
+class MediaBuffer;
+struct MediaCodec;
+class MetaData;
+
+class SimpleDecodingSource : public MediaSource {
+public:
+ // Creates a MediaSource that uses MediaCodec to decode a compressed input |source|.
+ // The selected codec can be influenced using |flags|. This source only supports the
+ // kPreferGoogleCodec and kNonGoogleCodecsOnly |flags| - MediaCodecList.
+ // You can pass in a target |nativeWindow| to render video directly onto a surface. In this
+ // case the source will return empty buffers.
+ // This source cannot be restarted (hence the name "Simple"), all reads are blocking, and
+ // does not support secure input or pausing.
+ // if |desiredCodec| is given, use this specific codec.
+ static sp<SimpleDecodingSource> Create(
+ const sp<IMediaSource> &source, uint32_t flags = 0,
+ const sp<ANativeWindow> &nativeWindow = NULL,
+ const char *desiredCodec = NULL);
+
+ virtual ~SimpleDecodingSource();
+
+ // starts this source (and it's underlying source). |params| is ignored.
+ virtual status_t start(MetaData *params = NULL);
+
+ // stops this source (and it's underlying source).
+ virtual status_t stop();
+
+ // returns the output format of this source.
+ virtual sp<MetaData> getFormat();
+
+ // reads from the source. This call always blocks.
+ virtual status_t read(MediaBuffer **buffer, const ReadOptions *options);
+
+ // unsupported methods
+ virtual status_t pause() { return INVALID_OPERATION; }
+ virtual status_t setBuffers(const Vector<MediaBuffer *> &) { return INVALID_OPERATION; }
+
+private:
+ // Construct this using a codec, source and looper.
+ SimpleDecodingSource(
+ const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
+ bool usingSurface, const sp<AMessage> &format);
+
+ sp<MediaCodec> mCodec;
+ sp<IMediaSource> mSource;
+ sp<ALooper> mLooper;
+ bool mUsingSurface;
+ enum State {
+ INIT,
+ STARTED,
+ STOPPING,
+ STOPPED,
+ ERROR,
+ };
+ AString mComponentName;
+
+ struct ProtectedState {
+ ProtectedState(const sp<AMessage> &format);
+ bool mReading;
+ Condition mReadCondition;
+
+ sp<AMessage> mFormat;
+ State mState;
+ bool mQueuedInputEOS;
+ bool mGotOutputEOS;
+ };
+ Mutexed<ProtectedState> mProtectedState;
+
+ // do the actual reading
+ status_t doRead(
+ Mutexed<ProtectedState>::Locked &me, MediaBuffer **buffer, const ReadOptions *options);
+};
+
+} // namespace android
+
+#endif
diff --git a/include/media/stagefright/SkipCutBuffer.h b/include/media/stagefright/SkipCutBuffer.h
index 098aa69..61f9949 100644
--- a/include/media/stagefright/SkipCutBuffer.h
+++ b/include/media/stagefright/SkipCutBuffer.h
@@ -29,9 +29,10 @@
*/
class SkipCutBuffer: public RefBase {
public:
- // 'skip' is the number of bytes to skip from the beginning
- // 'cut' is the number of bytes to cut from the end
- SkipCutBuffer(int32_t skip, int32_t cut);
+ // 'skip' is the number of frames to skip from the beginning
+ // 'cut' is the number of frames to cut from the end
+ // 'num16BitChannels' is the number of channels, which are assumed to be 16 bit wide each
+ SkipCutBuffer(size_t skip, size_t cut, size_t num16Channels);
// Submit one MediaBuffer for skipping and cutting. This may consume all or
// some of the data in the buffer, or it may add data to it.
diff --git a/include/media/stagefright/TimeSource.h b/include/media/stagefright/TimeSource.h
deleted file mode 100644
index 8f11e14..0000000
--- a/include/media/stagefright/TimeSource.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TIME_SOURCE_H_
-
-#define TIME_SOURCE_H_
-
-#include <stdint.h>
-
-namespace android {
-
-class TimeSource {
-public:
- TimeSource() {}
- virtual ~TimeSource() {}
-
- virtual int64_t getRealTimeUs() = 0;
-
-private:
- TimeSource(const TimeSource &);
- TimeSource &operator=(const TimeSource &);
-};
-
-class SystemTimeSource : public TimeSource {
-public:
- SystemTimeSource();
-
- virtual int64_t getRealTimeUs();
-
-private:
- int64_t mStartTimeUs;
-};
-
-} // namespace android
-
-#endif // TIME_SOURCE_H_
diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h
index 5e9d7d4..17631a0 100644
--- a/include/media/stagefright/Utils.h
+++ b/include/media/stagefright/Utils.h
@@ -85,6 +85,8 @@
void readFromAMessage(
const sp<AMessage> &msg, AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
+AString nameForFd(int fd);
+
} // namespace android
#endif // UTILS_H_
diff --git a/include/media/stagefright/foundation/ABuffer.h b/include/media/stagefright/foundation/ABuffer.h
index 6294ee7..dc9c778 100644
--- a/include/media/stagefright/foundation/ABuffer.h
+++ b/include/media/stagefright/foundation/ABuffer.h
@@ -33,8 +33,6 @@
ABuffer(size_t capacity);
ABuffer(void *data, size_t capacity);
- void setFarewellMessage(const sp<AMessage> msg);
-
uint8_t *base() { return (uint8_t *)mData; }
uint8_t *data() { return (uint8_t *)mData + mRangeOffset; }
size_t capacity() const { return mCapacity; }
@@ -58,7 +56,6 @@
virtual ~ABuffer();
private:
- sp<AMessage> mFarewell;
sp<AMessage> mMeta;
MediaBufferBase *mMediaBufferBase;
diff --git a/include/media/stagefright/foundation/Mutexed.h b/include/media/stagefright/foundation/Mutexed.h
new file mode 100644
index 0000000..d4fd905
--- /dev/null
+++ b/include/media/stagefright/foundation/Mutexed.h
@@ -0,0 +1,195 @@
+/*
+ * 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 STAGEFRIGHT_FOUNDATION_MUTEXED_H_
+#define STAGEFRIGHT_FOUNDATION_MUTEXED_H_
+
+#include <utils/Mutex.h>
+#include <utils/Condition.h>
+
+namespace android {
+
+/*
+ * Wrapper class to programmatically protect a structure using a mutex.
+ *
+ * Mutexed<> objects contain a built-in mutex. Protection is enforced because the structure can
+ * only be accessed by locking the mutex first.
+ *
+ * Usage:
+ *
+ * struct DataToProtect {
+ * State(int var1) : mVar1(var1), mVar2(0) { }
+ * int mVar1;
+ * int mVar2;
+ * Condition mCondition1;
+ * };
+ *
+ * Mutexed<DataToProtect> mProtectedData;
+ *
+ * // members are inaccessible via mProtectedData directly
+ *
+ * void someFunction() {
+ * Mutexed<DataToProtect>::Locked data(mProtectedData); // access the protected data
+ *
+ * // the mutex is locked here, so accessing the data is safe
+ *
+ * if (data->mVar1 < 5) {
+ * ++data->mVar2;
+ * }
+ *
+ * // if you need to temporarily unlock the mutex, you can use unlock/relock mutex locally
+ * // using the accessor object.
+ *
+ * data.unlock();
+ *
+ * // data is inaccessible here
+ *
+ * doSomeLongOperation();
+ *
+ * data.lock();
+ *
+ * // data is now accessible again. Note: it may have changed since unlock().
+ *
+ * // you can use the integral mutex to wait for a condition
+ *
+ * data.waitForCondition(data->mCondition1);
+ *
+ * helper(&data);
+ * }
+ *
+ * void trigger() {
+ * Mutexed<DataToProtect>::Locked data(mProtectedData);
+ * data->mCondition1.signal();
+ * }
+ *
+ * void helper(const Mutexed<DataToProtect>::Locked &data) {
+ * data->mVar1 = 3;
+ * }
+ *
+ */
+
+template<typename T>
+class Mutexed {
+public:
+ /*
+ * Accessor-guard of the mutex-protected structure. This can be dereferenced to
+ * access the structure (using -> or * operators).
+ *
+ * Upon creation, the mutex is locked. You can use lock()/unlock() methods to
+ * temporarily lock/unlock the mutex. Using any references to the underlying
+ * structure or its members defeats the protection of this class, so don't do
+ * it.
+ *
+ * Note: The accessor-guard itself is not thread-safe. E.g. you should not call
+ * unlock() or lock() from different threads; they must be called from the thread
+ * that locked the original wrapper.
+ *
+ * Also note: Recursive locking/unlocking is not supported by the accessor. This
+ * is as intended, as it allows lenient locking/unlocking via multiple code paths.
+ */
+ class Locked {
+ public:
+ inline Locked(Mutexed<T> &mParent);
+ inline ~Locked();
+
+ // dereference the protected structure. This returns nullptr if the
+ // mutex is not locked by this accessor-guard.
+ inline T* operator->() const { return mLocked ? &mTreasure : nullptr; }
+ inline T& operator*() const { return mLocked ? mTreasure : *(T*)nullptr; }
+
+ // Wait on the condition variable using lock. Must be locked.
+ inline status_t waitForCondition(Condition &cond) { return cond.wait(mLock); }
+
+ // same with relative timeout
+ inline status_t waitForConditionRelative(Condition &cond, nsecs_t reltime) {
+ return cond.waitRelative(mLock, reltime);
+ }
+
+ // unlocks the integral mutex. No-op if the mutex was already unlocked.
+ inline void unlock();
+
+ // locks the integral mutex. No-op if the mutex was already locked.
+ inline void lock();
+
+ private:
+ Mutex &mLock;
+ T &mTreasure;
+ bool mLocked;
+
+ // disable copy constructors
+ Locked(const Locked&) = delete;
+ void operator=(const Locked&) = delete;
+ };
+
+ // Wrap all constructors of the underlying structure
+ template<typename ...Args>
+ Mutexed(Args... args) : mTreasure(args...) { }
+
+ ~Mutexed() { }
+
+ // Lock the mutex, and create an accessor-guard (a Locked object) to access the underlying
+ // structure. This returns an object that dereferences to the wrapped structure when the mutex
+ // is locked by it, or otherwise to "null".
+ inline Locked&& lock() {
+ // use rvalue as Locked has no copy constructor
+ return std::move(Locked(*this));
+ }
+
+private:
+ friend class Locked;
+ Mutex mLock;
+ T mTreasure;
+
+ // disable copy constructors
+ Mutexed(const Mutexed<T>&) = delete;
+ void operator=(const Mutexed<T>&) = delete;
+};
+
+template<typename T>
+inline Mutexed<T>::Locked::Locked(Mutexed<T> &mParent)
+ : mLock(mParent.mLock),
+ mTreasure(mParent.mTreasure),
+ mLocked(true) {
+ mLock.lock();
+
+}
+
+template<typename T>
+inline Mutexed<T>::Locked::~Locked() {
+ if (mLocked) {
+ mLock.unlock();
+ }
+}
+
+template<typename T>
+inline void Mutexed<T>::Locked::unlock() {
+ if (mLocked) {
+ mLocked = false;
+ mLock.unlock();
+ }
+}
+
+template<typename T>
+inline void Mutexed<T>::Locked::lock() {
+ if (!mLocked) {
+ mLock.lock();
+ mLocked = true;
+ }
+}
+
+} // namespace android
+
+#endif
diff --git a/include/media/stagefright/timedtext/TimedTextDriver.h b/include/media/stagefright/timedtext/TimedTextDriver.h
deleted file mode 100644
index 6f7c693..0000000
--- a/include/media/stagefright/timedtext/TimedTextDriver.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2012 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 TIMED_TEXT_DRIVER_H_
-#define TIMED_TEXT_DRIVER_H_
-
-#include <media/stagefright/foundation/ABase.h> // for DISALLOW_* macro
-#include <utils/Errors.h> // for status_t
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-
-namespace android {
-
-struct ALooper;
-struct IMediaHTTPService;
-class MediaPlayerBase;
-class MediaSource;
-class Parcel;
-class TimedTextPlayer;
-class TimedTextSource;
-class DataSource;
-
-class TimedTextDriver {
-public:
- TimedTextDriver(
- const wp<MediaPlayerBase> &listener,
- const sp<IMediaHTTPService> &httpService);
-
- ~TimedTextDriver();
-
- status_t start();
- status_t pause();
- status_t selectTrack(size_t index);
- status_t unselectTrack(size_t index);
-
- status_t seekToAsync(int64_t timeUs);
-
- status_t addInBandTextSource(
- size_t trackIndex, const sp<MediaSource>& source);
-
- status_t addOutOfBandTextSource(
- size_t trackIndex, const char *uri, const char *mimeType);
-
- // Caller owns the file desriptor and caller is responsible for closing it.
- status_t addOutOfBandTextSource(
- size_t trackIndex, int fd, off64_t offset,
- off64_t length, const char *mimeType);
-
- void getExternalTrackInfo(Parcel *parcel);
- size_t countExternalTracks() const;
-
-private:
- Mutex mLock;
-
- enum State {
- UNINITIALIZED,
- PREPARED,
- PLAYING,
- PAUSED,
- };
-
- enum TextSourceType {
- TEXT_SOURCE_TYPE_IN_BAND = 0,
- TEXT_SOURCE_TYPE_OUT_OF_BAND,
- };
-
- sp<ALooper> mLooper;
- sp<TimedTextPlayer> mPlayer;
- wp<MediaPlayerBase> mListener;
- sp<IMediaHTTPService> mHTTPService;
-
- // Variables to be guarded by mLock.
- State mState;
- size_t mCurrentTrackIndex;
- KeyedVector<size_t, sp<TimedTextSource> > mTextSourceVector;
- Vector<TextSourceType> mTextSourceTypeVector;
-
- // -- End of variables to be guarded by mLock
-
- status_t selectTrack_l(size_t index);
-
- status_t createOutOfBandTextSource(
- size_t trackIndex, const char* mimeType,
- const sp<DataSource>& dataSource);
-
- DISALLOW_EVIL_CONSTRUCTORS(TimedTextDriver);
-};
-
-} // namespace android
-
-#endif // TIMED_TEXT_DRIVER_H_
diff --git a/include/ndk/NdkImage.h b/include/ndk/NdkImage.h
new file mode 100644
index 0000000..5c92294
--- /dev/null
+++ b/include/ndk/NdkImage.h
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_IMAGE_H
+#define _NDK_IMAGE_H
+
+#include "NdkMediaError.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct AImage AImage;
+
+// Formats not listed here will not be supported by AImageReader
+enum {
+ AIMAGE_FORMAT_YUV_420_888 = 0x23,
+ AIMAGE_FORMAT_JPEG = 0x100,
+ AIMAGE_FORMAT_RAW16 = 0x20,
+ AIMAGE_FORMAT_RAW_PRIVATE = 0x24,
+ AIMAGE_FORMAT_RAW10 = 0x25,
+ AIMAGE_FORMAT_RAW12 = 0x26,
+ AIMAGE_FORMAT_DEPTH16 = 0x44363159,
+ AIMAGE_FORMAT_DEPTH_POINT_CLOUD = 0x101
+};
+
+typedef struct AImageCropRect {
+ int32_t left;
+ int32_t top;
+ int32_t right;
+ int32_t bottom;
+} AImageCropRect;
+
+// Return the image back to system and delete the AImage from memory
+// Do NOT use `image` after this call
+void AImage_delete(AImage* image);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getWidth(const AImage* image, /*out*/int32_t* width);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getHeight(const AImage* image, /*out*/int32_t* height);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getFormat(const AImage* image, /*out*/int32_t* format);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getCropRect(const AImage* image, /*out*/AImageCropRect* rect);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getTimestamp(const AImage* image, /*out*/int64_t* timestampNs);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getNumberOfPlanes(const AImage* image, /*out*/int32_t* numPlanes);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getPlanePixelStride(
+ const AImage* image, int planeIdx, /*out*/int32_t* pixelStride);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getPlaneRowStride(
+ const AImage* image, int planeIdx, /*out*/int32_t* rowStride);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+// Note that once the AImage or the parent AImageReader is deleted, the `*data` returned from
+// previous AImage_getPlaneData call becomes dangling pointer. Do NOT use it after
+// AImage or AImageReader is deleted
+media_status_t AImage_getPlaneData(
+ const AImage* image, int planeIdx,
+ /*out*/uint8_t** data, /*out*/int* dataLength);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif //_NDK_IMAGE_H
diff --git a/include/ndk/NdkImageReader.h b/include/ndk/NdkImageReader.h
new file mode 100644
index 0000000..041c378
--- /dev/null
+++ b/include/ndk/NdkImageReader.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_IMAGE_READER_H
+#define _NDK_IMAGE_READER_H
+
+#include <android/native_window.h>
+#include "NdkMediaError.h"
+#include "NdkImage.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct AImageReader AImageReader;
+
+media_status_t AImageReader_new(
+ int32_t width, int32_t height, int32_t format, int32_t maxImages,
+ /*out*/AImageReader** reader);
+
+// Return all images acquired from this AImageReader back to system and delete
+// the AImageReader instance from memory
+// Do NOT use `reader` after this call
+void AImageReader_delete(AImageReader* reader);
+
+// Do NOT call ANativeWindow_release on the output. Just use AImageReader_delete.
+media_status_t AImageReader_getWindow(AImageReader*, /*out*/ANativeWindow** window);
+
+media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width);
+media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height);
+media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format);
+media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages);
+
+media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image);
+
+media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image);
+
+// The callback happens on one dedicated thread per AImageReader instance
+// It's okay to use AImageReader_*/AImage_* APIs within the callback
+typedef void (*AImageReader_ImageCallback)(void* context, AImageReader* reader);
+
+typedef struct AImageReader_ImageListener {
+ void* context; // optional application context.
+ AImageReader_ImageCallback onImageAvailable;
+} AImageReader_ImageListener;
+
+media_status_t AImageReader_setImageListener(
+ AImageReader* reader, AImageReader_ImageListener* listener);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif //_NDK_IMAGE_READER_H
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index 4f6a1ef..c6035bd 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -154,6 +154,18 @@
media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool render);
/**
+ * Dynamically sets the output surface of a codec.
+ *
+ * This can only be used if the codec was configured with an output surface. The
+ * new output surface should have a compatible usage type to the original output surface.
+ * E.g. codecs may not support switching from a SurfaceTexture (GPU readable) output
+ * to ImageReader (software readable) output.
+ *
+ * For more details, see the Java documentation for MediaCodec.setOutputSurface.
+ */
+media_status_t AMediaCodec_setOutputSurface(AMediaCodec*, ANativeWindow* surface);
+
+/**
* If you are done with a buffer, use this call to update its surface timestamp
* and return it to the codec to render it on the output surface. If you
* have not specified an output surface when configuring this video codec,
@@ -164,12 +176,16 @@
media_status_t AMediaCodec_releaseOutputBufferAtTime(
AMediaCodec *mData, size_t idx, int64_t timestampNs);
-
typedef enum {
AMEDIACODECRYPTOINFO_MODE_CLEAR = 0,
AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1
} cryptoinfo_mode_t;
+typedef struct {
+ int32_t encryptBlocks;
+ int32_t skipBlocks;
+} cryptoinfo_pattern_t;
+
/**
* Create an AMediaCodecCryptoInfo from scratch. Use this if you need to use custom
* crypto info, rather than one obtained from AMediaExtractor.
@@ -199,6 +215,13 @@
media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo*);
/**
+ * Set the crypto pattern on an AMediaCryptoInfo object
+ */
+void AMediaCodecCryptoInfo_setPattern(
+ AMediaCodecCryptoInfo *info,
+ cryptoinfo_pattern_t *pattern);
+
+/**
* The number of subsamples that make up the buffer's contents.
*/
size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo*);
diff --git a/include/ndk/NdkMediaError.h b/include/ndk/NdkMediaError.h
index 12613eb..60d401b 100644
--- a/include/ndk/NdkMediaError.h
+++ b/include/ndk/NdkMediaError.h
@@ -53,6 +53,10 @@
AMEDIA_DRM_NEED_KEY = AMEDIA_DRM_ERROR_BASE - 8,
AMEDIA_DRM_LICENSE_EXPIRED = AMEDIA_DRM_ERROR_BASE - 9,
+ AMEDIA_IMGREADER_ERROR_BASE = -30000,
+ AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE = AMEDIA_IMGREADER_ERROR_BASE - 1,
+ AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED = AMEDIA_IMGREADER_ERROR_BASE - 2,
+
} media_status_t;
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 1e5064f..aa9e98c 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -26,6 +26,8 @@
#include <utils/RefBase.h>
#include <audio_utils/roundup.h>
#include <media/AudioResamplerPublic.h>
+#include <media/AudioTimestamp.h>
+#include <media/Modulo.h>
#include <media/SingleStateQueue.h>
namespace android {
@@ -58,7 +60,8 @@
volatile int32_t mRear; // written by producer (output: client, input: server)
volatile int32_t mFlush; // incremented by client to indicate a request to flush;
// server notices and discards all data between mFront and mRear
- volatile uint32_t mUnderrunFrames; // server increments for each unavailable but desired frame
+ volatile uint32_t mUnderrunFrames; // server increments for each unavailable but desired frame
+ volatile uint32_t mUnderrunCount; // server increments for each underrun occurrence
};
// Represents a single state of an AudioTrack that was created in static mode (shared memory buffer
@@ -116,6 +119,8 @@
typedef SingleStateQueue<AudioPlaybackRate> PlaybackRateQueue;
+typedef SingleStateQueue<ExtendedTimestamp> ExtendedTimestampQueue;
+
// ----------------------------------------------------------------------------
// Important: do not add any virtual methods, including ~
@@ -169,12 +174,12 @@
uint16_t mPad2; // unused
+ // server write-only, client read
+ ExtendedTimestampQueue::Shared mExtendedTimestampQueue;
public:
volatile int32_t mFlags; // combinations of CBLK_*
- // Cache line boundary (32 bytes)
-
public:
union {
AudioTrackSharedStreaming mStreaming;
@@ -203,6 +208,8 @@
size_t mNonContig; // number of additional non-contiguous frames available
};
+ size_t frameCount() const { return mFrameCount; }
+
protected:
// These refer to shared memory, and are virtual addresses with respect to the current process.
// They may have different virtual addresses within the other process.
@@ -280,11 +287,11 @@
// Call to force an obtainBuffer() to return quickly with -EINTR
void interrupt();
- size_t getPosition() {
+ Modulo<uint32_t> getPosition() {
return mEpoch + mCblk->mServer;
}
- void setEpoch(size_t epoch) {
+ void setEpoch(const Modulo<uint32_t> &epoch) {
mEpoch = epoch;
}
@@ -300,14 +307,40 @@
// in order for the client to be aligned at start of buffer
virtual size_t getMisalignment();
- size_t getEpoch() const {
+ Modulo<uint32_t> getEpoch() const {
return mEpoch;
}
- size_t getFramesFilled();
+ size_t getBufferSizeInFrames() const { return mBufferSizeInFrames; }
+ // See documentation for AudioTrack.setBufferSizeInFrames()
+ size_t setBufferSizeInFrames(size_t requestedSize);
+
+ status_t getTimestamp(ExtendedTimestamp *timestamp) {
+ if (timestamp == nullptr) {
+ return BAD_VALUE;
+ }
+ (void) mTimestampObserver.poll(mTimestamp);
+ *timestamp = mTimestamp;
+ return OK;
+ }
+
+ void clearTimestamp() {
+ mTimestamp.clear();
+ }
+
+protected:
+ // This is set by AudioTrack.setBufferSizeInFrames().
+ // A write will not fill the buffer above this limit.
+ size_t mBufferSizeInFrames; // effective size of the buffer
private:
- size_t mEpoch;
+ Modulo<uint32_t> mEpoch;
+
+ // The shared buffer contents referred to by the timestamp observer
+ // is initialized when the server proxy created. A local zero timestamp
+ // is initialized by the client constructor.
+ ExtendedTimestampQueue::Observer mTimestampObserver;
+ ExtendedTimestamp mTimestamp; // initialized by constructor
};
// ----------------------------------------------------------------------------
@@ -319,7 +352,9 @@
size_t frameSize, bool clientInServer = false)
: ClientProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/,
clientInServer),
- mPlaybackRateMutator(&cblk->mPlaybackRateQueue) { }
+ mPlaybackRateMutator(&cblk->mPlaybackRateQueue) {
+ }
+
virtual ~AudioTrackClientProxy() { }
// No barriers on the following operations, so the ordering of loads/stores
@@ -348,6 +383,9 @@
virtual uint32_t getUnderrunFrames() const {
return mCblk->u.mStreaming.mUnderrunFrames;
}
+ virtual uint32_t getUnderrunCount() const {
+ return mCblk->u.mStreaming.mUnderrunCount;
+ }
bool clearStreamEndDone(); // and return previous value
@@ -416,6 +454,16 @@
: ClientProxy(cblk, buffers, frameCount, frameSize,
false /*isOut*/, false /*clientInServer*/) { }
~AudioRecordClientProxy() { }
+
+ // Advances the client read pointer to the server write head pointer
+ // effectively flushing the client read buffer. The effect is
+ // instantaneous. Returns the number of frames flushed.
+ uint32_t flush() {
+ int32_t rear = android_atomic_acquire_load(&mCblk->u.mStreaming.mRear);
+ int32_t front = mCblk->u.mStreaming.mFront;
+ android_atomic_release_store(rear, &mCblk->u.mStreaming.mFront);
+ return (Modulo<int32_t>(rear) - front).unsignedValue();
+ }
};
// ----------------------------------------------------------------------------
@@ -461,9 +509,20 @@
// buffer->mRaw is NULL.
virtual void releaseBuffer(Buffer* buffer);
+ // Return the total number of frames that AudioFlinger has obtained and released
+ virtual int64_t framesReleased() const { return mReleased; }
+
+ // Expose timestamp to client proxy. Should only be called by a single thread.
+ virtual void setTimestamp(const ExtendedTimestamp ×tamp) {
+ mTimestampMutator.push(timestamp);
+ }
+
protected:
size_t mAvailToClient; // estimated frames available to client prior to releaseBuffer()
int32_t mFlush; // our copy of cblk->u.mStreaming.mFlush, for streaming output only
+ int64_t mReleased; // our copy of cblk->mServer, at 64 bit resolution
+
+ ExtendedTimestampQueue::Mutator mTimestampMutator;
};
// Proxy used by AudioFlinger for servicing AudioTrack
@@ -472,7 +531,8 @@
AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
size_t frameSize, bool clientInServer = false, uint32_t sampleRate = 0)
: ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer),
- mPlaybackRateObserver(&cblk->mPlaybackRateQueue) {
+ mPlaybackRateObserver(&cblk->mPlaybackRateQueue),
+ mUnderrunCount(0), mUnderrunning(false) {
mCblk->mSampleRate = sampleRate;
mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
}
@@ -506,15 +566,16 @@
// and thus which resulted in an underrun.
virtual uint32_t getUnderrunFrames() const { return mCblk->u.mStreaming.mUnderrunFrames; }
- // Return the total number of frames that AudioFlinger has obtained and released
- virtual size_t framesReleased() const { return mCblk->mServer; }
-
// Return the playback speed and pitch read atomically. Not multi-thread safe on server side.
AudioPlaybackRate getPlaybackRate();
private:
AudioPlaybackRate mPlaybackRate; // last observed playback rate
PlaybackRateQueue::Observer mPlaybackRateObserver;
+
+ // The server keeps a copy here where it is safe from the client.
+ uint32_t mUnderrunCount; // echoed to mCblk
+ bool mUnderrunning; // used to detect edge of underrun
};
class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
@@ -558,6 +619,7 @@
AudioRecordServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
size_t frameSize, bool clientInServer)
: ServerProxy(cblk, buffers, frameCount, frameSize, false /*isOut*/, clientInServer) { }
+
protected:
virtual ~AudioRecordServerProxy() { }
};
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
new file mode 100644
index 0000000..324ebbb
--- /dev/null
+++ b/media/audioserver/Android.mk
@@ -0,0 +1,35 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ main_audioserver.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libaudioflinger \
+ libaudiopolicyservice \
+ libbinder \
+ liblog \
+ libmedia \
+ libradioservice \
+ libsoundtriggerservice \
+ libutils \
+
+LOCAL_C_INCLUDES := \
+ frameworks/av/services/audioflinger \
+ frameworks/av/services/audiopolicy \
+ frameworks/av/services/audiopolicy/common/managerdefinitions/include \
+ frameworks/av/services/audiopolicy/common/include \
+ frameworks/av/services/audiopolicy/engine/interface \
+ frameworks/av/services/audiopolicy/service \
+ frameworks/av/services/radio \
+ frameworks/av/services/soundtrigger \
+ $(call include-path-for, audio-utils) \
+ external/sonic \
+
+LOCAL_MODULE := audioserver
+LOCAL_32_BIT_ONLY := true
+
+LOCAL_INIT_RC := audioserver.rc
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
new file mode 100644
index 0000000..1b39c8d
--- /dev/null
+++ b/media/audioserver/audioserver.rc
@@ -0,0 +1,6 @@
+service audioserver /system/bin/audioserver
+ class main
+ user audioserver
+ # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
+ group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
+ ioprio rt 4
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
new file mode 100644
index 0000000..a7123aa
--- /dev/null
+++ b/media/audioserver/main_audioserver.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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 "audioserver"
+//#define LOG_NDEBUG 0
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+// from LOCAL_C_INCLUDES
+#include "AudioFlinger.h"
+#include "AudioPolicyService.h"
+#include "RadioService.h"
+#include "SoundTriggerHwService.h"
+
+using namespace android;
+
+int main(int argc __unused, char **argv __unused)
+{
+ signal(SIGPIPE, SIG_IGN);
+
+ // TODO: add logging b/24511453#3
+
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm(defaultServiceManager());
+ ALOGI("ServiceManager: %p", sm.get());
+ AudioFlinger::instantiate();
+ AudioPolicyService::instantiate();
+ RadioService::instantiate();
+ SoundTriggerHwService::instantiate();
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+}
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 14a1a74..a1892e4 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -722,17 +722,20 @@
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE){
pOutTmp = pOut;
- }else if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
+ } 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 *)malloc(frameCount * sizeof(LVM_INT16) * 2);
+ (LVM_INT16 *)calloc(frameCount, sizeof(LVM_INT16) * 2);
+ if (pContext->pBundledContext->workBuffer == NULL) {
+ return -ENOMEM;
+ }
pContext->pBundledContext->frameCount = frameCount;
}
pOutTmp = pContext->pBundledContext->workBuffer;
- }else{
+ } else {
ALOGV("LVM_ERROR : LvmBundle_process invalid access mode");
return -EINVAL;
}
@@ -2872,7 +2875,7 @@
EffectContext * pContext = (EffectContext *) self;
LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
int status = 0;
- int lvmStatus = 0;
+ int processStatus = 0;
LVM_INT16 *in = (LVM_INT16 *)inBuffer->raw;
LVM_INT16 *out = (LVM_INT16 *)outBuffer->raw;
@@ -2960,19 +2963,22 @@
//pContext->pBundledContext->NumberEffectsEnabled,
//pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType);
- if(status == -ENODATA){
+ if (status == -ENODATA){
ALOGV("\tEffect_process() processing last frame");
}
pContext->pBundledContext->NumberEffectsCalled = 0;
/* Process all the available frames, block processing is
handled internalLY by the LVM bundle */
- lvmStatus = android::LvmBundle_process( (LVM_INT16 *)inBuffer->raw,
+ processStatus = android::LvmBundle_process( (LVM_INT16 *)inBuffer->raw,
(LVM_INT16 *)outBuffer->raw,
outBuffer->frameCount,
pContext);
- if(lvmStatus != LVM_SUCCESS){
- ALOGV("\tLVM_ERROR : LvmBundle_process returned error %d", lvmStatus);
- return lvmStatus;
+ if (processStatus != 0){
+ ALOGV("\tLVM_ERROR : LvmBundle_process returned error %d", processStatus);
+ if (status == 0) {
+ status = processStatus;
+ }
+ return status;
}
} else {
//ALOGV("\tEffect_process Not Calling process with %d effects enabled, %d called: Effect %d",
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
index ea3c59d..4e4b094 100644
--- a/media/libeffects/preprocessing/Android.mk
+++ b/media/libeffects/preprocessing/Android.mk
@@ -11,9 +11,9 @@
PreProcessing.cpp
LOCAL_C_INCLUDES += \
- external/webrtc/src \
- external/webrtc/src/modules/interface \
- external/webrtc/src/modules/audio_processing/interface \
+ external/webrtc \
+ external/webrtc/webrtc/modules/include \
+ external/webrtc/webrtc/modules/audio_processing/include \
$(call include-path-for, audio-effects)
LOCAL_C_INCLUDES += $(call include-path-for, speex)
@@ -25,6 +25,10 @@
liblog
LOCAL_SHARED_LIBRARIES += libdl
+
+LOCAL_CFLAGS += \
+ -DWEBRTC_POSIX
+
LOCAL_CFLAGS += -fvisibility=hidden
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 6dd4439..f48bac1 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -89,6 +89,7 @@
preproc_session_t *session; // session the effect is on
const preproc_ops_t *ops; // effect ops table
preproc_fx_handle_t engine; // handle on webRTC engine
+ uint32_t type; // subtype of effect
#ifdef DUAL_MIC_TEST
bool aux_channels_on; // support auxiliary channels
size_t cur_channel_config; // current auciliary channel configuration
@@ -559,6 +560,21 @@
ALOGV("NsInit");
webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
ns->set_level(kNsDefaultLevel);
+ webrtc::Config config;
+ std::vector<webrtc::Point> geometry;
+ // TODO(aluebs): Make the geometry settable.
+ geometry.push_back(webrtc::Point(-0.03f, 0.f, 0.f));
+ geometry.push_back(webrtc::Point(-0.01f, 0.f, 0.f));
+ geometry.push_back(webrtc::Point(0.01f, 0.f, 0.f));
+ geometry.push_back(webrtc::Point(0.03f, 0.f, 0.f));
+ // The geometry needs to be set with Beamforming enabled.
+ config.Set<webrtc::Beamforming>(
+ new webrtc::Beamforming(true, geometry));
+ effect->session->apm->SetExtraOptions(config);
+ config.Set<webrtc::Beamforming>(
+ new webrtc::Beamforming(false, geometry));
+ effect->session->apm->SetExtraOptions(config);
+ effect->type = NS_TYPE_SINGLE_CHANNEL;
return 0;
}
@@ -584,11 +600,35 @@
return status;
}
-int NsSetParameter (preproc_effect_t *effect __unused,
- void *pParam __unused,
- void *pValue __unused)
+int NsSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
{
int status = 0;
+ webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
+ uint32_t param = *(uint32_t *)pParam;
+ uint32_t value = *(uint32_t *)pValue;
+ switch(param) {
+ case NS_PARAM_LEVEL:
+ ns->set_level((webrtc::NoiseSuppression::Level)value);
+ ALOGV("NsSetParameter() level %d", value);
+ break;
+ case NS_PARAM_TYPE:
+ {
+ webrtc::Config config;
+ std::vector<webrtc::Point> geometry;
+ bool is_beamforming_enabled =
+ value == NS_TYPE_MULTI_CHANNEL && ns->is_enabled();
+ config.Set<webrtc::Beamforming>(
+ new webrtc::Beamforming(is_beamforming_enabled, geometry));
+ effect->session->apm->SetExtraOptions(config);
+ effect->type = value;
+ ALOGV("NsSetParameter() type %d", value);
+ break;
+ }
+ default:
+ ALOGW("NsSetParameter() unknown param %08x value %08x", param, value);
+ status = -EINVAL;
+ }
+
return status;
}
@@ -597,6 +637,12 @@
webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
ALOGV("NsEnable ns %p", ns);
ns->Enable(true);
+ if (effect->type == NS_TYPE_MULTI_CHANNEL) {
+ webrtc::Config config;
+ std::vector<webrtc::Point> geometry;
+ config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry));
+ effect->session->apm->SetExtraOptions(config);
+ }
}
void NsDisable(preproc_effect_t *effect)
@@ -604,6 +650,10 @@
ALOGV("NsDisable");
webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
ns->Enable(false);
+ webrtc::Config config;
+ std::vector<webrtc::Point> geometry;
+ config.Set<webrtc::Beamforming>(new webrtc::Beamforming(false, geometry));
+ effect->session->apm->SetExtraOptions(config);
}
static const preproc_ops_t sNsOps = {
@@ -777,14 +827,17 @@
ALOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
if (session->createdMsk == 0) {
- session->apm = webrtc::AudioProcessing::Create(session->io);
+ session->apm = webrtc::AudioProcessing::Create();
if (session->apm == NULL) {
ALOGW("Session_CreateEffect could not get apm engine");
goto error;
}
- session->apm->set_sample_rate_hz(kPreprocDefaultSr);
- session->apm->set_num_channels(kPreProcDefaultCnl, kPreProcDefaultCnl);
- session->apm->set_num_reverse_channels(kPreProcDefaultCnl);
+ const webrtc::ProcessingConfig processing_config = {
+ {{kPreprocDefaultSr, kPreProcDefaultCnl},
+ {kPreprocDefaultSr, kPreProcDefaultCnl},
+ {kPreprocDefaultSr, kPreProcDefaultCnl},
+ {kPreprocDefaultSr, kPreProcDefaultCnl}}};
+ session->apm->Initialize(processing_config);
session->procFrame = new webrtc::AudioFrame();
if (session->procFrame == NULL) {
ALOGW("Session_CreateEffect could not allocate audio frame");
@@ -801,11 +854,11 @@
session->samplingRate = kPreprocDefaultSr;
session->inChannelCount = kPreProcDefaultCnl;
session->outChannelCount = kPreProcDefaultCnl;
- session->procFrame->_frequencyInHz = kPreprocDefaultSr;
- session->procFrame->_audioChannel = kPreProcDefaultCnl;
+ session->procFrame->sample_rate_hz_ = kPreprocDefaultSr;
+ session->procFrame->num_channels_ = kPreProcDefaultCnl;
session->revChannelCount = kPreProcDefaultCnl;
- session->revFrame->_frequencyInHz = kPreprocDefaultSr;
- session->revFrame->_audioChannel = kPreProcDefaultCnl;
+ session->revFrame->sample_rate_hz_ = kPreprocDefaultSr;
+ session->revFrame->num_channels_ = kPreProcDefaultCnl;
session->enabledMsk = 0;
session->processedMsk = 0;
session->revEnabledMsk = 0;
@@ -834,7 +887,7 @@
session->revFrame = NULL;
delete session->procFrame;
session->procFrame = NULL;
- webrtc::AudioProcessing::Destroy(session->apm);
+ delete session->apm;
session->apm = NULL;
}
return status;
@@ -846,7 +899,7 @@
ALOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
session->createdMsk &= ~(1<<fx->procId);
if (session->createdMsk == 0) {
- webrtc::AudioProcessing::Destroy(session->apm);
+ delete session->apm;
session->apm = NULL;
delete session->procFrame;
session->procFrame = NULL;
@@ -881,8 +934,8 @@
int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
{
uint32_t sr;
- uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
- uint32_t outCnl = audio_channel_count_from_out_mask(config->outputCfg.channels);
+ uint32_t inCnl = audio_channel_count_from_in_mask(config->inputCfg.channels);
+ uint32_t outCnl = audio_channel_count_from_in_mask(config->outputCfg.channels);
if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
config->inputCfg.format != config->outputCfg.format ||
@@ -894,17 +947,6 @@
config->inputCfg.samplingRate, config->inputCfg.channels);
int status;
- // if at least one process is enabled, do not accept configuration changes
- if (session->enabledMsk) {
- if (session->samplingRate != config->inputCfg.samplingRate ||
- session->inChannelCount != inCnl ||
- session->outChannelCount != outCnl) {
- return -ENOSYS;
- } else {
- return 0;
- }
- }
-
// AEC implementation is limited to 16kHz
if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
session->apmSamplingRate = 32000;
@@ -914,15 +956,13 @@
} else if (config->inputCfg.samplingRate >= 8000) {
session->apmSamplingRate = 8000;
}
- status = session->apm->set_sample_rate_hz(session->apmSamplingRate);
- if (status < 0) {
- return -EINVAL;
- }
- status = session->apm->set_num_channels(inCnl, outCnl);
- if (status < 0) {
- return -EINVAL;
- }
- status = session->apm->set_num_reverse_channels(inCnl);
+
+ const webrtc::ProcessingConfig processing_config = {
+ {{static_cast<int>(session->apmSamplingRate), inCnl},
+ {static_cast<int>(session->apmSamplingRate), outCnl},
+ {static_cast<int>(session->apmSamplingRate), inCnl},
+ {static_cast<int>(session->apmSamplingRate), inCnl}}};
+ status = session->apm->Initialize(processing_config);
if (status < 0) {
return -EINVAL;
}
@@ -937,12 +977,12 @@
}
session->inChannelCount = inCnl;
session->outChannelCount = outCnl;
- session->procFrame->_audioChannel = inCnl;
- session->procFrame->_frequencyInHz = session->apmSamplingRate;
+ session->procFrame->num_channels_ = inCnl;
+ session->procFrame->sample_rate_hz_ = session->apmSamplingRate;
session->revChannelCount = inCnl;
- session->revFrame->_audioChannel = inCnl;
- session->revFrame->_frequencyInHz = session->apmSamplingRate;
+ session->revFrame->num_channels_ = inCnl;
+ session->revFrame->sample_rate_hz_ = session->apmSamplingRate;
// force process buffer reallocation
session->inBufSize = 0;
@@ -1038,13 +1078,18 @@
return -EINVAL;
}
uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
- int status = session->apm->set_num_reverse_channels(inCnl);
+ const webrtc::ProcessingConfig processing_config = {
+ {{static_cast<int>(session->apmSamplingRate), session->inChannelCount},
+ {static_cast<int>(session->apmSamplingRate), session->outChannelCount},
+ {static_cast<int>(session->apmSamplingRate), inCnl},
+ {static_cast<int>(session->apmSamplingRate), inCnl}}};
+ int status = session->apm->Initialize(processing_config);
if (status < 0) {
return -EINVAL;
}
session->revChannelCount = inCnl;
- session->revFrame->_audioChannel = inCnl;
- session->revFrame->_frequencyInHz = session->apmSamplingRate;
+ session->revFrame->num_channels_ = inCnl;
+ session->revFrame->sample_rate_hz_ = session->apmSamplingRate;
// force process buffer reallocation
session->revBufSize = 0;
session->framesRev = 0;
@@ -1214,9 +1259,17 @@
fr = inBuffer->frameCount;
}
if (session->inBufSize < session->framesIn + fr) {
+ int16_t *buf;
session->inBufSize = session->framesIn + fr;
- session->inBuf = (int16_t *)realloc(session->inBuf,
+ buf = (int16_t *)realloc(session->inBuf,
session->inBufSize * session->inChannelCount * sizeof(int16_t));
+ if (buf == NULL) {
+ session->framesIn = 0;
+ free(session->inBuf);
+ session->inBuf = NULL;
+ return -ENOMEM;
+ }
+ session->inBuf = buf;
}
memcpy(session->inBuf + session->framesIn * session->inChannelCount,
inBuffer->s16,
@@ -1242,13 +1295,13 @@
0,
session->inBuf,
&frIn,
- session->procFrame->_payloadData,
+ session->procFrame->data_,
&frOut);
} else {
speex_resampler_process_interleaved_int(session->inResampler,
session->inBuf,
&frIn,
- session->procFrame->_payloadData,
+ session->procFrame->data_,
&frOut);
}
memcpy(session->inBuf,
@@ -1260,7 +1313,7 @@
if (inBuffer->frameCount < fr) {
fr = inBuffer->frameCount;
}
- memcpy(session->procFrame->_payloadData + session->framesIn * session->inChannelCount,
+ memcpy(session->procFrame->data_ + session->framesIn * session->inChannelCount,
inBuffer->s16,
fr * session->inChannelCount * sizeof(int16_t));
@@ -1280,15 +1333,22 @@
}
session->framesIn = 0;
}
- session->procFrame->_payloadDataLengthInSamples =
- session->apmFrameCount * session->inChannelCount;
+ session->procFrame->samples_per_channel_ = session->apmFrameCount;
effect->session->apm->ProcessStream(session->procFrame);
if (session->outBufSize < session->framesOut + session->frameCount) {
+ int16_t *buf;
session->outBufSize = session->framesOut + session->frameCount;
- session->outBuf = (int16_t *)realloc(session->outBuf,
- session->outBufSize * session->outChannelCount * sizeof(int16_t));
+ buf = (int16_t *)realloc(session->outBuf,
+ session->outBufSize * session->outChannelCount * sizeof(int16_t));
+ if (buf == NULL) {
+ session->framesOut = 0;
+ free(session->outBuf);
+ session->outBuf = NULL;
+ return -ENOMEM;
+ }
+ session->outBuf = buf;
}
if (session->outResampler != NULL) {
@@ -1297,13 +1357,13 @@
if (session->inChannelCount == 1) {
speex_resampler_process_int(session->outResampler,
0,
- session->procFrame->_payloadData,
+ session->procFrame->data_,
&frIn,
session->outBuf + session->framesOut * session->outChannelCount,
&frOut);
} else {
speex_resampler_process_interleaved_int(session->outResampler,
- session->procFrame->_payloadData,
+ session->procFrame->data_,
&frIn,
session->outBuf + session->framesOut * session->outChannelCount,
&frOut);
@@ -1311,7 +1371,7 @@
session->framesOut += frOut;
} else {
memcpy(session->outBuf + session->framesOut * session->outChannelCount,
- session->procFrame->_payloadData,
+ session->procFrame->data_,
session->frameCount * session->outChannelCount * sizeof(int16_t));
session->framesOut += session->frameCount;
}
@@ -1744,9 +1804,17 @@
fr = inBuffer->frameCount;
}
if (session->revBufSize < session->framesRev + fr) {
+ int16_t *buf;
session->revBufSize = session->framesRev + fr;
- session->revBuf = (int16_t *)realloc(session->revBuf,
- session->revBufSize * session->inChannelCount * sizeof(int16_t));
+ buf = (int16_t *)realloc(session->revBuf,
+ session->revBufSize * session->inChannelCount * sizeof(int16_t));
+ if (buf == NULL) {
+ session->framesRev = 0;
+ free(session->revBuf);
+ session->revBuf = NULL;
+ return -ENOMEM;
+ }
+ session->revBuf = buf;
}
memcpy(session->revBuf + session->framesRev * session->inChannelCount,
inBuffer->s16,
@@ -1764,13 +1832,13 @@
0,
session->revBuf,
&frIn,
- session->revFrame->_payloadData,
+ session->revFrame->data_,
&frOut);
} else {
speex_resampler_process_interleaved_int(session->revResampler,
session->revBuf,
&frIn,
- session->revFrame->_payloadData,
+ session->revFrame->data_,
&frOut);
}
memcpy(session->revBuf,
@@ -1782,7 +1850,7 @@
if (inBuffer->frameCount < fr) {
fr = inBuffer->frameCount;
}
- memcpy(session->revFrame->_payloadData + session->framesRev * session->inChannelCount,
+ memcpy(session->revFrame->data_ + session->framesRev * session->inChannelCount,
inBuffer->s16,
fr * session->inChannelCount * sizeof(int16_t));
session->framesRev += fr;
@@ -1792,8 +1860,7 @@
}
session->framesRev = 0;
}
- session->revFrame->_payloadDataLengthInSamples =
- session->apmFrameCount * session->inChannelCount;
+ session->revFrame->samples_per_channel_ = session->apmFrameCount;
effect->session->apm->AnalyzeReverseStream(session->revFrame);
return 0;
} else {
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index a3c3d3c..479ccbb 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -30,14 +30,19 @@
AudioSystem.cpp \
mediaplayer.cpp \
IMediaCodecList.cpp \
+ IMediaCodecService.cpp \
+ IMediaDrmService.cpp \
IMediaHTTPConnection.cpp \
IMediaHTTPService.cpp \
IMediaLogService.cpp \
+ IMediaExtractor.cpp \
+ IMediaExtractorService.cpp \
IMediaPlayerService.cpp \
IMediaPlayerClient.cpp \
IMediaRecorderClient.cpp \
IMediaPlayer.cpp \
IMediaRecorder.cpp \
+ IMediaSource.cpp \
IRemoteDisplay.cpp \
IRemoteDisplayClient.cpp \
IResourceManagerClient.cpp \
@@ -89,6 +94,7 @@
LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/AudioPolicy.cpp b/media/libmedia/AudioPolicy.cpp
index 9d07011..ea22b6c 100644
--- a/media/libmedia/AudioPolicy.cpp
+++ b/media/libmedia/AudioPolicy.cpp
@@ -22,37 +22,37 @@
namespace android {
//
-// AttributeMatchCriterion implementation
+// AudioMixMatchCriterion implementation
//
-AttributeMatchCriterion::AttributeMatchCriterion(audio_usage_t usage,
+AudioMixMatchCriterion::AudioMixMatchCriterion(audio_usage_t usage,
audio_source_t source,
uint32_t rule)
: mRule(rule)
{
if (mRule == RULE_MATCH_ATTRIBUTE_USAGE ||
mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) {
- mAttr.mUsage = usage;
+ mValue.mUsage = usage;
} else {
- mAttr.mSource = source;
+ mValue.mSource = source;
}
}
-status_t AttributeMatchCriterion::readFromParcel(Parcel *parcel)
+status_t AudioMixMatchCriterion::readFromParcel(Parcel *parcel)
{
mRule = parcel->readInt32();
if (mRule == RULE_MATCH_ATTRIBUTE_USAGE ||
mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) {
- mAttr.mUsage = (audio_usage_t)parcel->readInt32();
+ mValue.mUsage = (audio_usage_t)parcel->readInt32();
} else {
- mAttr.mSource = (audio_source_t)parcel->readInt32();
+ mValue.mSource = (audio_source_t)parcel->readInt32();
}
return NO_ERROR;
}
-status_t AttributeMatchCriterion::writeToParcel(Parcel *parcel) const
+status_t AudioMixMatchCriterion::writeToParcel(Parcel *parcel) const
{
parcel->writeInt32(mRule);
- parcel->writeInt32(mAttr.mUsage);
+ parcel->writeInt32(mValue.mUsage);
return NO_ERROR;
}
@@ -74,7 +74,7 @@
size = MAX_CRITERIA_PER_MIX;
}
for (size_t i = 0; i < size; i++) {
- AttributeMatchCriterion criterion;
+ AudioMixMatchCriterion criterion;
if (criterion.readFromParcel(parcel) == NO_ERROR) {
mCriteria.add(criterion);
}
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 011b31f..ec57d96 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -284,6 +284,8 @@
mSequence = 1;
mObservedSequence = mSequence;
mInOverrun = false;
+ mFramesRead = 0;
+ mFramesReadServerOffset = 0;
return NO_ERROR;
}
@@ -299,6 +301,12 @@
return NO_ERROR;
}
+ // discard data in buffer
+ const uint32_t framesFlushed = mProxy->flush();
+ mFramesReadServerOffset -= mFramesRead + framesFlushed;
+ mFramesRead = 0;
+ mProxy->clearTimestamp(); // timestamp is invalid until next server push
+
// reset current position as seen by client to 0
mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
// force refresh of remaining frames by processAudioBuffer() as last
@@ -308,6 +316,10 @@
mNewPosition = mProxy->getPosition() + mUpdatePeriod;
int32_t flags = android_atomic_acquire_load(&mCblk->mFlags);
+ // we reactivate markers (mMarkerPosition != 0) as the position is reset to 0.
+ // This is legacy behavior. This is not done in stop() to avoid a race condition
+ // where the last marker event is issued twice.
+ mMarkerReached = false;
mActive = true;
status_t status = NO_ERROR;
@@ -348,9 +360,10 @@
mActive = false;
mProxy->interrupt();
mAudioRecord->stop();
- // the record head position will reset to 0, so if a marker is set, we need
- // to activate it again
- mMarkerReached = false;
+
+ // Note: legacy handling - stop does not clear record marker and
+ // periodic update position; we update those on start().
+
sp<AudioRecordThread> t = mAudioRecordThread;
if (t != 0) {
t->pause();
@@ -391,7 +404,7 @@
}
AutoMutex lock(mLock);
- *marker = mMarkerPosition;
+ mMarkerPosition.getValue(marker);
return NO_ERROR;
}
@@ -433,7 +446,7 @@
}
AutoMutex lock(mLock);
- *position = mProxy->getPosition();
+ mProxy->getPosition().getValue(position);
return NO_ERROR;
}
@@ -444,6 +457,27 @@
return AudioSystem::getInputFramesLost(getInputPrivate());
}
+status_t AudioRecord::getTimestamp(ExtendedTimestamp *timestamp)
+{
+ if (timestamp == nullptr) {
+ return BAD_VALUE;
+ }
+ AutoMutex lock(mLock);
+ status_t status = mProxy->getTimestamp(timestamp);
+ if (status == OK) {
+ timestamp->mPosition[ExtendedTimestamp::LOCATION_CLIENT] = mFramesRead;
+ timestamp->mTimeNs[ExtendedTimestamp::LOCATION_CLIENT] = 0;
+ // server side frame offset in case AudioRecord has been restored.
+ for (int i = ExtendedTimestamp::LOCATION_SERVER;
+ i < ExtendedTimestamp::LOCATION_MAX; ++i) {
+ if (timestamp->mTimeNs[i] >= 0) {
+ timestamp->mPosition[i] += mFramesReadServerOffset;
+ }
+ }
+ }
+ return status;
+}
+
// ---- Explicit Routing ---------------------------------------------------
status_t AudioRecord::setInputDevice(audio_port_handle_t deviceId) {
AutoMutex lock(mLock);
@@ -475,7 +509,7 @@
// -------------------------------------------------------------------------
// must be called with mLock held
-status_t AudioRecord::openRecord_l(size_t epoch, const String16& opPackageName)
+status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName)
{
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
if (audioFlinger == 0) {
@@ -832,7 +866,10 @@
releaseBuffer(&audioBuffer);
}
-
+ if (read > 0) {
+ mFramesRead += read / mFrameSize;
+ // mFramesReadTime = systemTime(SYSTEM_TIME_MONOTONIC); // not provided at this time.
+ }
return read;
}
@@ -885,23 +922,23 @@
}
// Get current position of server
- size_t position = mProxy->getPosition();
+ Modulo<uint32_t> position(mProxy->getPosition());
// Manage marker callback
bool markerReached = false;
- size_t markerPosition = mMarkerPosition;
+ Modulo<uint32_t> markerPosition(mMarkerPosition);
// FIXME fails for wraparound, need 64 bits
- if (!mMarkerReached && (markerPosition > 0) && (position >= markerPosition)) {
+ if (!mMarkerReached && markerPosition.value() > 0 && position >= markerPosition) {
mMarkerReached = markerReached = true;
}
// Determine the number of new position callback(s) that will be needed, while locked
size_t newPosCount = 0;
- size_t newPosition = mNewPosition;
+ Modulo<uint32_t> newPosition(mNewPosition);
uint32_t updatePeriod = mUpdatePeriod;
// FIXME fails for wraparound, need 64 bits
if (updatePeriod > 0 && position >= newPosition) {
- newPosCount = ((position - newPosition) / updatePeriod) + 1;
+ newPosCount = ((position - newPosition).value() / updatePeriod) + 1;
mNewPosition += updatePeriod * newPosCount;
}
@@ -928,7 +965,7 @@
mCbf(EVENT_MARKER, mUserData, &markerPosition);
}
while (newPosCount > 0) {
- size_t temp = newPosition;
+ size_t temp = newPosition.value(); // FIXME size_t != uint32_t
mCbf(EVENT_NEW_POS, mUserData, &temp);
newPosition += updatePeriod;
newPosCount--;
@@ -946,10 +983,10 @@
// Compute the estimated time until the next timed event (position, markers)
uint32_t minFrames = ~0;
if (!markerReached && position < markerPosition) {
- minFrames = markerPosition - position;
+ minFrames = (markerPosition - position).value();
}
if (updatePeriod > 0) {
- uint32_t remaining = newPosition - position;
+ uint32_t remaining = (newPosition - position).value();
if (remaining < minFrames) {
minFrames = remaining;
}
@@ -983,6 +1020,7 @@
requested = &timeout;
}
+ size_t readFrames = 0;
while (mRemainingFrames > 0) {
Buffer audioBuffer;
@@ -1044,6 +1082,7 @@
}
releaseBuffer(&audioBuffer);
+ readFrames += releasedFrames;
// FIXME here is where we would repeat EVENT_MORE_DATA again on same advanced buffer
// if callback doesn't like to accept the full chunk
@@ -1067,6 +1106,11 @@
#endif
}
+ if (readFrames > 0) {
+ AutoMutex lock(mLock);
+ mFramesRead += readFrames;
+ // mFramesReadTime = systemTime(SYSTEM_TIME_MONOTONIC); // not provided at this time.
+ }
mRemainingFrames = notificationFrames;
mRetryOnPartialBuffer = true;
@@ -1082,7 +1126,7 @@
// if the new IAudioRecord is created, openRecord_l() will modify the
// following member variables: mAudioRecord, mCblkMemory, mCblk, mBufferMemory.
// It will also delete the strong references on previous IAudioRecord and IMemory
- size_t position = mProxy->getPosition();
+ Modulo<uint32_t> position(mProxy->getPosition());
mNewPosition = position + mUpdatePeriod;
status_t result = openRecord_l(position, mOpPackageName);
if (result == NO_ERROR) {
@@ -1091,6 +1135,7 @@
// FIXME this fails if we have a new AudioFlinger instance
result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0);
}
+ mFramesReadServerOffset = mFramesRead; // server resets to zero so we need an offset.
}
if (result != NO_ERROR) {
ALOGW("restoreRecord_l() failed status %d", result);
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 9d645f0..1ea2003 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -37,6 +37,7 @@
sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL;
+record_config_callback AudioSystem::gRecordConfigCallback = NULL;
// establish binder interface to AudioFlinger service
@@ -652,6 +653,12 @@
gDynPolicyCallback = cb;
}
+/*static*/ void AudioSystem::setRecordConfigCallback(record_config_callback cb)
+{
+ Mutex::Autolock _l(gLock);
+ gRecordConfigCallback = cb;
+}
+
// client singleton for AudioPolicyService binder interface
// protected by gLockAPS
sp<IAudioPolicyService> AudioSystem::gAudioPolicyService;
@@ -1159,6 +1166,20 @@
return aps->stopAudioSource(handle);
}
+status_t AudioSystem::setMasterMono(bool mono)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->setMasterMono(mono);
+}
+
+status_t AudioSystem::getMasterMono(bool *mono)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->getMasterMono(mono);
+}
+
// ---------------------------------------------------------------------------
int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
@@ -1223,6 +1244,19 @@
}
}
+void AudioSystem::AudioPolicyServiceClient::onRecordingConfigurationUpdate(
+ int event, audio_session_t session, audio_source_t source) {
+ record_config_callback cb = NULL;
+ {
+ Mutex::Autolock _l(AudioSystem::gLock);
+ cb = gRecordConfigCallback;
+ }
+
+ if (cb != NULL) {
+ cb(event, session, source);
+ }
+}
+
void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused)
{
{
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index ff5fe1d..33dcc57 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -163,7 +163,6 @@
AudioTrack::AudioTrack()
: mStatus(NO_INIT),
- mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0),
@@ -193,7 +192,6 @@
const audio_attributes_t* pAttributes,
bool doNotReconnect)
: mStatus(NO_INIT),
- mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0),
@@ -223,7 +221,6 @@
const audio_attributes_t* pAttributes,
bool doNotReconnect)
: mStatus(NO_INIT),
- mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0),
@@ -288,6 +285,8 @@
streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames,
sessionId, transferType, uid, pid);
+ mThreadCanCallJava = threadCanCallJava;
+
switch (transferType) {
case TRANSFER_DEFAULT:
if (sharedBuffer != 0) {
@@ -356,11 +355,16 @@
if ((mAttributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
}
+ if ((mAttributes.flags & AUDIO_FLAG_LOW_LATENCY) != 0) {
+ flags = (audio_output_flags_t) (flags | AUDIO_OUTPUT_FLAG_FAST);
+ }
}
// these below should probably come from the audioFlinger too...
if (format == AUDIO_FORMAT_DEFAULT) {
format = AUDIO_FORMAT_PCM_16_BIT;
+ } else if (format == AUDIO_FORMAT_IEC61937) { // HDMI pass-through?
+ mAttributes.flags |= AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO;
}
// validate parameters
@@ -396,13 +400,13 @@
}
if (flags & AUDIO_OUTPUT_FLAG_DIRECT) {
- if (audio_is_linear_pcm(format)) {
+ if (audio_has_proportional_frames(format)) {
mFrameSize = channelCount * audio_bytes_per_sample(format);
} else {
mFrameSize = sizeof(uint8_t);
}
} else {
- ALOG_ASSERT(audio_is_linear_pcm(format));
+ ALOG_ASSERT(audio_has_proportional_frames(format));
mFrameSize = channelCount * audio_bytes_per_sample(format);
// createTrack will return an error if PCM format is not supported by server,
// so no need to check for specific PCM formats here
@@ -493,6 +497,7 @@
mPreviousTimestampValid = false;
mTimestampStartupGlitchReported = false;
mRetrogradeMotionReported = false;
+ mUnderrunCountOffset = 0;
return NO_ERROR;
}
@@ -523,12 +528,14 @@
mTimestampStartupGlitchReported = false;
mRetrogradeMotionReported = false;
- // If previousState == STATE_STOPPED, we reactivate markers (mMarkerPosition != 0)
+ // If previousState == STATE_STOPPED, we clear the timestamp so that it
+ // needs a new server push. We also reactivate markers (mMarkerPosition != 0)
// as the position is reset to 0. This is legacy behavior. This is not done
// in stop() to avoid a race condition where the last marker event is issued twice.
// Note: the if is technically unnecessary because previousState == STATE_FLUSHED
// is only for streaming tracks, and mMarkerReached is already set to false.
if (previousState == STATE_STOPPED) {
+ mProxy->clearTimestamp(); // need new server push for valid timestamp
mMarkerReached = false;
}
@@ -744,7 +751,7 @@
if (rate == mSampleRate) {
return NO_ERROR;
}
- if (mIsTimed || isOffloadedOrDirect_l() || (mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
+ if (isOffloadedOrDirect_l() || (mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
return INVALID_OPERATION;
}
if (mOutput == AUDIO_IO_HANDLE_NONE) {
@@ -771,10 +778,6 @@
uint32_t AudioTrack::getSampleRate() const
{
- if (mIsTimed) {
- return 0;
- }
-
AutoMutex lock(mLock);
// sample rate can be updated during playback by the offloaded decoder so we need to
@@ -794,10 +797,6 @@
uint32_t AudioTrack::getOriginalSampleRate() const
{
- if (mIsTimed) {
- return 0;
- }
-
return mOriginalSampleRate;
}
@@ -807,7 +806,7 @@
if (isAudioPlaybackRateEqual(playbackRate, mPlaybackRate)) {
return NO_ERROR;
}
- if (mIsTimed || isOffloadedOrDirect_l()) {
+ if (isOffloadedOrDirect_l()) {
return INVALID_OPERATION;
}
if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
@@ -831,13 +830,13 @@
}
// Check resampler ratios are within bounds
- if (effectiveRate > mSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
+ if ((uint64_t)effectiveRate > (uint64_t)mSampleRate * (uint64_t)AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
ALOGV("setPlaybackRate(%f, %f) failed. Resample rate exceeds max accepted value",
playbackRate.mSpeed, playbackRate.mPitch);
return BAD_VALUE;
}
- if (effectiveRate * AUDIO_RESAMPLER_UP_RATIO_MAX < mSampleRate) {
+ if ((uint64_t)effectiveRate * (uint64_t)AUDIO_RESAMPLER_UP_RATIO_MAX < (uint64_t)mSampleRate) {
ALOGV("setPlaybackRate(%f, %f) failed. Resample rate below min accepted value",
playbackRate.mSpeed, playbackRate.mPitch);
return BAD_VALUE;
@@ -855,9 +854,34 @@
return mPlaybackRate;
}
+ssize_t AudioTrack::getBufferSizeInFrames()
+{
+ AutoMutex lock(mLock);
+ if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
+ return NO_INIT;
+ }
+ return mProxy->getBufferSizeInFrames();
+}
+
+ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames)
+{
+ AutoMutex lock(mLock);
+ if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
+ return NO_INIT;
+ }
+ // Reject if timed track or compressed audio.
+ if (!audio_is_linear_pcm(mFormat)) {
+ return INVALID_OPERATION;
+ }
+ // TODO also need to inform the server side (through mAudioTrack) that
+ // the buffer count is reduced, otherwise the track may never start
+ // because the server thinks it is never filled.
+ return mProxy->setBufferSizeInFrames(bufferSizeInFrames);
+}
+
status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
{
- if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
+ if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
return INVALID_OPERATION;
}
@@ -920,7 +944,7 @@
}
AutoMutex lock(mLock);
- *marker = mMarkerPosition;
+ mMarkerPosition.getValue(marker);
return NO_ERROR;
}
@@ -960,7 +984,7 @@
status_t AudioTrack::setPosition(uint32_t position)
{
- if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
+ if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
return INVALID_OPERATION;
}
if (position > mFrameCount) {
@@ -1018,14 +1042,14 @@
// IAudioTrack::stop() isn't synchronous; we don't know when presentation completes
*position = (mState == STATE_STOPPED || mState == STATE_FLUSHED) ?
- 0 : updateAndGetPosition_l();
+ 0 : updateAndGetPosition_l().value();
}
return NO_ERROR;
}
status_t AudioTrack::getBufferPosition(uint32_t *position)
{
- if (mSharedBuffer == 0 || mIsTimed) {
+ if (mSharedBuffer == 0) {
return INVALID_OPERATION;
}
if (position == NULL) {
@@ -1039,7 +1063,7 @@
status_t AudioTrack::reload()
{
- if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
+ if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
return INVALID_OPERATION;
}
@@ -1168,22 +1192,27 @@
mSampleRate = mAfSampleRate;
mOriginalSampleRate = mAfSampleRate;
}
- // Client decides whether the track is TIMED (see below), but can only express a preference
- // for FAST. Server will perform additional tests.
- if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) && !((
+ // Client can only express a preference for FAST. Server will perform additional tests.
+ if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
+ bool useCaseAllowed =
// either of these use cases:
// use case 1: shared buffer
(mSharedBuffer != 0) ||
// use case 2: callback transfer mode
(mTransfer == TRANSFER_CALLBACK) ||
// use case 3: obtain/release mode
- (mTransfer == TRANSFER_OBTAIN)) &&
- // matching sample rate
- (mSampleRate == mAfSampleRate))) {
- ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client; transfer %d, track %u Hz, output %u Hz",
+ (mTransfer == TRANSFER_OBTAIN) ||
+ // use case 4: synchronous write
+ ((mTransfer == TRANSFER_SYNC) && mThreadCanCallJava);
+ // sample rates must also match
+ bool fastAllowed = useCaseAllowed && (mSampleRate == mAfSampleRate);
+ if (!fastAllowed) {
+ ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client; transfer %d,"
+ "track %u Hz, output %u Hz",
mTransfer, mSampleRate, mAfSampleRate);
- // once denied, do not request again if IAudioTrack is re-created
- mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
+ // once denied, do not request again if IAudioTrack is re-created
+ mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
+ }
}
// The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where
@@ -1196,7 +1225,7 @@
mNotificationFramesAct = mNotificationFramesReq;
size_t frameCount = mReqFrameCount;
- if (!audio_is_linear_pcm(mFormat)) {
+ if (!audio_has_proportional_frames(mFormat)) {
if (mSharedBuffer != 0) {
// Same comment as below about ignoring frameCount parameter for set()
@@ -1247,14 +1276,11 @@
}
IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
- if (mIsTimed) {
- trackFlags |= IAudioFlinger::TRACK_TIMED;
- }
pid_t tid = -1;
if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
trackFlags |= IAudioFlinger::TRACK_FAST;
- if (mAudioTrackThread != 0) {
+ if (mAudioTrackThread != 0 && !mThreadCanCallJava) {
tid = mAudioTrackThread->getTid();
}
}
@@ -1328,7 +1354,9 @@
if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
if (trackFlags & IAudioFlinger::TRACK_FAST) {
ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu", frameCount);
- mAwaitBoost = true;
+ if (!mThreadCanCallJava) {
+ mAwaitBoost = true;
+ }
} else {
ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu", frameCount);
// once denied, do not request again if IAudioTrack is re-created
@@ -1587,7 +1615,7 @@
ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
{
- if (mTransfer != TRANSFER_SYNC || mIsTimed) {
+ if (mTransfer != TRANSFER_SYNC) {
return INVALID_OPERATION;
}
@@ -1637,73 +1665,6 @@
// -------------------------------------------------------------------------
-TimedAudioTrack::TimedAudioTrack() {
- mIsTimed = true;
-}
-
-status_t TimedAudioTrack::allocateTimedBuffer(size_t size, sp<IMemory>* buffer)
-{
- AutoMutex lock(mLock);
- status_t result = UNKNOWN_ERROR;
-
-#if 1
- // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
- // while we are accessing the cblk
- sp<IAudioTrack> audioTrack = mAudioTrack;
- sp<IMemory> iMem = mCblkMemory;
-#endif
-
- // If the track is not invalid already, try to allocate a buffer. alloc
- // fails indicating that the server is dead, flag the track as invalid so
- // we can attempt to restore in just a bit.
- audio_track_cblk_t* cblk = mCblk;
- if (!(cblk->mFlags & CBLK_INVALID)) {
- result = mAudioTrack->allocateTimedBuffer(size, buffer);
- if (result == DEAD_OBJECT) {
- android_atomic_or(CBLK_INVALID, &cblk->mFlags);
- }
- }
-
- // If the track is invalid at this point, attempt to restore it. and try the
- // allocation one more time.
- if (cblk->mFlags & CBLK_INVALID) {
- result = restoreTrack_l("allocateTimedBuffer");
-
- if (result == NO_ERROR) {
- result = mAudioTrack->allocateTimedBuffer(size, buffer);
- }
- }
-
- return result;
-}
-
-status_t TimedAudioTrack::queueTimedBuffer(const sp<IMemory>& buffer,
- int64_t pts)
-{
- status_t status = mAudioTrack->queueTimedBuffer(buffer, pts);
- {
- AutoMutex lock(mLock);
- audio_track_cblk_t* cblk = mCblk;
- // restart track if it was disabled by audioflinger due to previous underrun
- if (buffer->size() != 0 && status == NO_ERROR &&
- (mState == STATE_ACTIVE) && (cblk->mFlags & CBLK_DISABLED)) {
- android_atomic_and(~CBLK_DISABLED, &cblk->mFlags);
- ALOGW("queueTimedBuffer() track %p disabled, restarting", this);
- // FIXME ignoring status
- mAudioTrack->start();
- }
- }
- return status;
-}
-
-status_t TimedAudioTrack::setMediaTimeTransform(const LinearTransform& xform,
- TargetTimeline target)
-{
- return mAudioTrack->setMediaTimeTransform(xform, target);
-}
-
-// -------------------------------------------------------------------------
-
nsecs_t AudioTrack::processAudioBuffer()
{
// Currently the AudioTrack thread is not created if there are no callbacks.
@@ -1774,23 +1735,23 @@
}
// Get current position of server
- size_t position = updateAndGetPosition_l();
+ Modulo<uint32_t> position(updateAndGetPosition_l());
// Manage marker callback
bool markerReached = false;
- size_t markerPosition = mMarkerPosition;
- // FIXME fails for wraparound, need 64 bits
- if (!mMarkerReached && (markerPosition > 0) && (position >= markerPosition)) {
+ Modulo<uint32_t> markerPosition(mMarkerPosition);
+ // uses 32 bit wraparound for comparison with position.
+ if (!mMarkerReached && markerPosition.value() > 0 && position >= markerPosition) {
mMarkerReached = markerReached = true;
}
// Determine number of new position callback(s) that will be needed, while locked
size_t newPosCount = 0;
- size_t newPosition = mNewPosition;
- size_t updatePeriod = mUpdatePeriod;
+ Modulo<uint32_t> newPosition(mNewPosition);
+ uint32_t updatePeriod = mUpdatePeriod;
// FIXME fails for wraparound, need 64 bits
if (updatePeriod > 0 && position >= newPosition) {
- newPosCount = ((position - newPosition) / updatePeriod) + 1;
+ newPosCount = ((position - newPosition).value() / updatePeriod) + 1;
mNewPosition += updatePeriod * newPosCount;
}
@@ -1891,7 +1852,7 @@
mCbf(EVENT_MARKER, mUserData, &markerPosition);
}
while (newPosCount > 0) {
- size_t temp = newPosition;
+ size_t temp = newPosition.value(); // FIXME size_t != uint32_t
mCbf(EVENT_NEW_POS, mUserData, &temp);
newPosition += updatePeriod;
newPosCount--;
@@ -1915,14 +1876,14 @@
// FIXME only for non-compressed audio
uint32_t minFrames = ~0;
if (!markerReached && position < markerPosition) {
- minFrames = markerPosition - position;
+ minFrames = (markerPosition - position).value();
}
if (loopPeriod > 0 && loopPeriod < minFrames) {
// loopPeriod is already adjusted for actual position.
minFrames = loopPeriod;
}
if (updatePeriod > 0) {
- minFrames = min(minFrames, uint32_t(newPosition - position));
+ minFrames = min(minFrames, (newPosition - position).value());
}
// If > 0, poll periodically to recover from a stuck server. A good value is 2.
@@ -1987,7 +1948,7 @@
return NS_NEVER;
}
- if (mRetryOnPartialBuffer && audio_is_linear_pcm(mFormat)) {
+ if (mRetryOnPartialBuffer && audio_has_proportional_frames(mFormat)) {
mRetryOnPartialBuffer = false;
if (avail < mRemainingFrames) {
if (ns > 0) { // account for obtain time
@@ -2033,7 +1994,7 @@
// buffer size and skip the loop entirely.
nsecs_t myns;
- if (audio_is_linear_pcm(mFormat)) {
+ if (audio_has_proportional_frames(mFormat)) {
// time to wait based on buffer occupancy
const nsecs_t datans = mRemainingFrames <= avail ? 0 :
framesToNanoseconds(mRemainingFrames - avail, sampleRate, speed);
@@ -2112,6 +2073,9 @@
return DEAD_OBJECT;
}
+ // Save so we can return count since creation.
+ mUnderrunCountOffset = getUnderrunCount_l();
+
// save the old static buffer position
size_t bufferPosition = 0;
int loopCount = 0;
@@ -2157,12 +2121,11 @@
return result;
}
-uint32_t AudioTrack::updateAndGetPosition_l()
+Modulo<uint32_t> AudioTrack::updateAndGetPosition_l()
{
// This is the sole place to read server consumed frames
- uint32_t newServer = mProxy->getPosition();
- int32_t delta = newServer - mServer;
- mServer = newServer;
+ Modulo<uint32_t> newServer(mProxy->getPosition());
+ const int32_t delta = (newServer - mServer).signedValue();
// TODO There is controversy about whether there can be "negative jitter" in server position.
// This should be investigated further, and if possible, it should be addressed.
// A more definite failure mode is infrequent polling by client.
@@ -2171,11 +2134,14 @@
// That should ensure delta never goes negative for infrequent polling
// unless the server has more than 2^31 frames in its buffer,
// in which case the use of uint32_t for these counters has bigger issues.
- if (delta < 0) {
- ALOGE("detected illegal retrograde motion by the server: mServer advanced by %d", delta);
- delta = 0;
+ ALOGE_IF(delta < 0,
+ "detected illegal retrograde motion by the server: mServer advanced by %d",
+ delta);
+ mServer = newServer;
+ if (delta > 0) { // avoid retrograde
+ mPosition += delta;
}
- return mPosition += (uint32_t) delta;
+ return mPosition;
}
bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const
@@ -2205,11 +2171,6 @@
// Set false here to cover all the error return cases.
mPreviousTimestampValid = false;
- // FIXME not implemented for fast tracks; should use proxy and SSQ
- if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
- return INVALID_OPERATION;
- }
-
switch (mState) {
case STATE_ACTIVE:
case STATE_PAUSED:
@@ -2239,7 +2200,22 @@
// The presented frame count must always lag behind the consumed frame count.
// To avoid a race, read the presented frames first. This ensures that presented <= consumed.
- status_t status = mAudioTrack->getTimestamp(timestamp);
+
+ status_t status;
+ if (!(mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
+ // use Binder to get timestamp
+ status = mAudioTrack->getTimestamp(timestamp);
+ } else {
+ // read timestamp from shared memory
+ ExtendedTimestamp ets;
+ status = mProxy->getTimestamp(&ets);
+ if (status == OK) {
+ status = ets.getBestTimestamp(×tamp);
+ }
+ if (status == INVALID_OPERATION) {
+ status = WOULD_BLOCK;
+ }
+ }
if (status != NO_ERROR) {
ALOGV_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status);
return status;
@@ -2309,15 +2285,19 @@
// If this delta between these is greater than the client position, it means that
// actually presented is still stuck at the starting line (figuratively speaking),
// waiting for the first frame to go by. So we can't report a valid timestamp yet.
- if ((uint32_t) (mServer - timestamp.mPosition) > mPosition) {
+ // Note: We explicitly use non-Modulo comparison here - potential wrap issue when
+ // mPosition exceeds 32 bits.
+ // TODO Remove when timestamp is updated to contain pipeline status info.
+ const int32_t pipelineDepthInFrames = (mServer - timestamp.mPosition).signedValue();
+ if (pipelineDepthInFrames > 0 /* should be true, but we check anyways */
+ && (uint32_t)pipelineDepthInFrames > mPosition.value()) {
return INVALID_OPERATION;
}
// Convert timestamp position from server time base to client time base.
// TODO The following code should work OK now because timestamp.mPosition is 32-bit.
// But if we change it to 64-bit then this could fail.
- // If (mPosition - mServer) can be negative then should use:
- // (int32_t)(mPosition - mServer)
- timestamp.mPosition += mPosition - mServer;
+ // Use Modulo computation here.
+ timestamp.mPosition = (mPosition - mServer + timestamp.mPosition).value();
// Immediately after a call to getPosition_l(), mPosition and
// mServer both represent the same frame position. mPosition is
// in client's point of view, and mServer is in server's point of
@@ -2331,9 +2311,9 @@
// This is sometimes caused by erratic reports of the available space in the ALSA drivers.
if (status == NO_ERROR) {
if (previousTimestampValid) {
-#define TIME_TO_NANOS(time) ((uint64_t)time.tv_sec * 1000000000 + time.tv_nsec)
- const uint64_t previousTimeNanos = TIME_TO_NANOS(mPreviousTimestamp.mTime);
- const uint64_t currentTimeNanos = TIME_TO_NANOS(timestamp.mTime);
+#define TIME_TO_NANOS(time) ((int64_t)time.tv_sec * 1000000000 + time.tv_nsec)
+ const int64_t previousTimeNanos = TIME_TO_NANOS(mPreviousTimestamp.mTime);
+ const int64_t currentTimeNanos = TIME_TO_NANOS(timestamp.mTime);
#undef TIME_TO_NANOS
if (currentTimeNanos < previousTimeNanos) {
ALOGW("retrograde timestamp time");
@@ -2342,8 +2322,8 @@
// Looking at signed delta will work even when the timestamps
// are wrapping around.
- int32_t deltaPosition = static_cast<int32_t>(timestamp.mPosition
- - mPreviousTimestamp.mPosition);
+ int32_t deltaPosition = (Modulo<uint32_t>(timestamp.mPosition)
+ - mPreviousTimestamp.mPosition).signedValue();
// position can bobble slightly as an artifact; this hides the bobble
static const int32_t MINIMUM_POSITION_DELTA = 8;
if (deltaPosition < 0) {
@@ -2421,6 +2401,17 @@
return NO_ERROR;
}
+uint32_t AudioTrack::getUnderrunCount() const
+{
+ AutoMutex lock(mLock);
+ return getUnderrunCount_l();
+}
+
+uint32_t AudioTrack::getUnderrunCount_l() const
+{
+ return mProxy->getUnderrunCount() + mUnderrunCountOffset;
+}
+
uint32_t AudioTrack::getUnderrunFrames() const
{
AutoMutex lock(mLock);
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index caa84fb..1d15495 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -38,7 +38,7 @@
// In general, this means (new_self) returned is max(self, other) + 1.
static uint32_t incrementSequence(uint32_t self, uint32_t other) {
- int32_t diff = self - other;
+ int32_t diff = (int32_t) self - (int32_t) other;
if (diff >= 0 && diff < INT32_MAX) {
return self + 1; // we're already ahead of other.
}
@@ -66,7 +66,10 @@
ClientProxy::ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
size_t frameSize, bool isOut, bool clientInServer)
- : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer), mEpoch(0)
+ : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer)
+ , mBufferSizeInFrames(frameCount)
+ , mEpoch(0)
+ , mTimestampObserver(&cblk->mExtendedTimestampQueue)
{
}
@@ -151,6 +154,7 @@
rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
front = cblk->u.mStreaming.mFront;
}
+ // write to rear, read from front
ssize_t filled = rear - front;
// pipe should not be overfull
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
@@ -166,9 +170,15 @@
cblk->u.mStreaming.mFront = rear;
(void) android_atomic_or(CBLK_OVERRUN, &cblk->mFlags);
}
- // don't allow filling pipe beyond the nominal size
- size_t avail = mIsOut ? mFrameCount - filled : filled;
- if (avail > 0) {
+ // Don't allow filling pipe beyond the user settable size.
+ // The calculation for avail can go negative if the buffer size
+ // is suddenly dropped below the amount already in the buffer.
+ // So use a signed calculation to prevent a numeric overflow abort.
+ ssize_t adjustableSize = (ssize_t) mBufferSizeInFrames;
+ ssize_t avail = (mIsOut) ? adjustableSize - filled : filled;
+ if (avail < 0) {
+ avail = 0;
+ } else if (avail > 0) {
// 'avail' may be non-contiguous, so return only the first contiguous chunk
size_t part1;
if (mIsOut) {
@@ -178,7 +188,7 @@
front &= mFrameCountP2 - 1;
part1 = mFrameCountP2 - front;
}
- if (part1 > avail) {
+ if (part1 > (size_t)avail) {
part1 = avail;
}
if (part1 > buffer->mFrameCount) {
@@ -240,6 +250,7 @@
errno = 0;
(void) syscall(__NR_futex, &cblk->mFutex,
mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts);
+ status_t error = errno; // clock_gettime can affect errno
// update total elapsed time spent waiting
if (measure) {
struct timespec after;
@@ -257,7 +268,7 @@
before = after;
beforeIsValid = true;
}
- switch (errno) {
+ switch (error) {
case 0: // normal wakeup by server, or by binderDied()
case EWOULDBLOCK: // benign race condition with server
case EINTR: // wait was interrupted by signal or other spurious wakeup
@@ -265,7 +276,7 @@
// FIXME these error/non-0 status are being dropped
break;
default:
- status = errno;
+ status = error;
ALOGE("%s unexpected error %s", __func__, strerror(status));
goto end;
}
@@ -338,6 +349,7 @@
}
}
+__attribute__((no_sanitize("integer")))
size_t ClientProxy::getMisalignment()
{
audio_track_cblk_t* cblk = mCblk;
@@ -345,25 +357,18 @@
(mFrameCountP2 - 1);
}
-size_t ClientProxy::getFramesFilled() {
- audio_track_cblk_t* cblk = mCblk;
- int32_t front;
- int32_t rear;
-
- if (mIsOut) {
- front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
- rear = cblk->u.mStreaming.mRear;
- } else {
- rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
- front = cblk->u.mStreaming.mFront;
+size_t ClientProxy::setBufferSizeInFrames(size_t size)
+{
+ // TODO set minimum to 2X the fast mixer buffer size.
+ size_t minimum = 128 * 2; // arbitrary
+ size_t maximum = frameCount();
+ if (size < minimum) {
+ size = minimum;
+ } else if (size > maximum) {
+ size = maximum;
}
- ssize_t filled = rear - front;
- // pipe should not be overfull
- if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
- ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled);
- return 0;
- }
- return (size_t)filled;
+ mBufferSizeInFrames = size;
+ return size;
}
// ---------------------------------------------------------------------------
@@ -593,7 +598,8 @@
ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
size_t frameSize, bool isOut, bool clientInServer)
: Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer),
- mAvailToClient(0), mFlush(0)
+ mAvailToClient(0), mFlush(0), mReleased(0)
+ , mTimestampMutator(&cblk->mExtendedTimestampQueue)
{
}
@@ -729,6 +735,7 @@
}
cblk->mServer += stepCount;
+ mReleased += stepCount;
size_t half = mFrameCount / 2;
if (half == 0) {
@@ -800,10 +807,25 @@
void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
{
audio_track_cblk_t* cblk = mCblk;
- cblk->u.mStreaming.mUnderrunFrames += frameCount;
+ if (frameCount > 0) {
+ cblk->u.mStreaming.mUnderrunFrames += frameCount;
- // FIXME also wake futex so that underrun is noticed more quickly
- (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags);
+ if (!mUnderrunning) { // start of underrun?
+ mUnderrunCount++;
+ cblk->u.mStreaming.mUnderrunCount = mUnderrunCount;
+ mUnderrunning = true;
+ ALOGV("tallyUnderrunFrames(%3u) at uf = %u, bump mUnderrunCount = %u",
+ frameCount, cblk->u.mStreaming.mUnderrunFrames, mUnderrunCount);
+ }
+
+ // FIXME also wake futex so that underrun is noticed more quickly
+ (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags);
+ } else {
+ ALOGV_IF(mUnderrunning,
+ "tallyUnderrunFrames(%3u) at uf = %u, underrun finished",
+ frameCount, cblk->u.mStreaming.mUnderrunFrames);
+ mUnderrunning = false; // so we can detect the next edge
+ }
}
AudioPlaybackRate AudioTrackServerProxy::getPlaybackRate()
@@ -893,7 +915,7 @@
if (mObserver.poll(state)) {
StaticAudioTrackState trystate = mState;
bool result;
- const int32_t diffSeq = state.mLoopSequence - state.mPositionSequence;
+ const int32_t diffSeq = (int32_t) state.mLoopSequence - (int32_t) state.mPositionSequence;
if (diffSeq < 0) {
result = updateStateWithLoop(&trystate, state) == OK &&
@@ -1014,6 +1036,8 @@
mFramesReadySafe = clampToSize(mFramesReady);
cblk->mServer += stepCount;
+ mReleased += stepCount;
+
// This may overflow, but client is not supposed to rely on it
StaticAudioTrackPosLoop posLoop;
posLoop.mBufferPosition = mState.mPosition;
@@ -1029,7 +1053,7 @@
buffer->mNonContig = 0;
}
-void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount __unused)
+void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
{
// Unlike AudioTrackServerProxy::tallyUnderrunFrames() used for streaming tracks,
// we don't have a location to count underrun frames. The underrun frame counter
@@ -1037,7 +1061,9 @@
// possible for static buffer tracks other than at end of buffer, so this is not a loss.
// FIXME also wake futex so that underrun is noticed more quickly
- (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
+ if (frameCount > 0) {
+ (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
+ }
}
// ---------------------------------------------------------------------------
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 76b5924..c95d4c4 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -74,6 +74,8 @@
START_AUDIO_SOURCE,
STOP_AUDIO_SOURCE,
SET_AUDIO_PORT_CALLBACK_ENABLED,
+ SET_MASTER_MONO,
+ GET_MASTER_MONO,
};
#define MAX_ITEMS_PER_LIST 1024
@@ -767,6 +769,37 @@
status = (status_t)reply.readInt32();
return status;
}
+
+ virtual status_t setMasterMono(bool mono)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast<int32_t>(mono));
+ status_t status = remote()->transact(SET_MASTER_MONO, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return static_cast<status_t>(reply.readInt32());
+ }
+
+ virtual status_t getMasterMono(bool *mono)
+ {
+ if (mono == nullptr) {
+ return BAD_VALUE;
+ }
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+
+ status_t status = remote()->transact(GET_MASTER_MONO, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = static_cast<status_t>(reply.readInt32());
+ if (status == NO_ERROR) {
+ *mono = static_cast<bool>(reply.readInt32());
+ }
+ return status;
+ }
};
IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1311,6 +1344,25 @@
return NO_ERROR;
} break;
+ case SET_MASTER_MONO: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ bool mono = static_cast<bool>(data.readInt32());
+ status_t status = setMasterMono(mono);
+ reply->writeInt32(status);
+ return NO_ERROR;
+ } break;
+
+ case GET_MASTER_MONO: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ bool mono;
+ status_t status = getMasterMono(&mono);
+ reply->writeInt32(status);
+ if (status == NO_ERROR) {
+ reply->writeInt32(static_cast<int32_t>(mono));
+ }
+ return NO_ERROR;
+ } break;
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/IAudioPolicyServiceClient.cpp b/media/libmedia/IAudioPolicyServiceClient.cpp
index 65cc7d6..fe5df28 100644
--- a/media/libmedia/IAudioPolicyServiceClient.cpp
+++ b/media/libmedia/IAudioPolicyServiceClient.cpp
@@ -30,7 +30,8 @@
enum {
PORT_LIST_UPDATE = IBinder::FIRST_CALL_TRANSACTION,
PATCH_LIST_UPDATE,
- MIX_STATE_UPDATE
+ MIX_STATE_UPDATE,
+ RECORDING_CONFIGURATION_UPDATE
};
class BpAudioPolicyServiceClient : public BpInterface<IAudioPolicyServiceClient>
@@ -63,6 +64,16 @@
data.writeInt32(state);
remote()->transact(MIX_STATE_UPDATE, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ void onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyServiceClient::getInterfaceDescriptor());
+ data.writeInt32(event);
+ data.writeInt32(session);
+ data.writeInt32(source);
+ remote()->transact(RECORDING_CONFIGURATION_UPDATE, data, &reply, IBinder::FLAG_ONEWAY);
+ }
};
IMPLEMENT_META_INTERFACE(AudioPolicyServiceClient, "android.media.IAudioPolicyServiceClient");
@@ -89,7 +100,15 @@
int32_t state = data.readInt32();
onDynamicPolicyMixStateUpdate(regId, state);
return NO_ERROR;
- }
+ } break;
+ 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();
+ onRecordingConfigurationUpdate(event, session, source);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index 651cb61..636e3bb 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -36,9 +36,6 @@
RESERVED, // was MUTE
PAUSE,
ATTACH_AUX_EFFECT,
- ALLOCATE_TIMED_BUFFER,
- QUEUE_TIMED_BUFFER,
- SET_MEDIA_TIME_TRANSFORM,
SET_PARAMETERS,
GET_TIMESTAMP,
SIGNAL,
@@ -115,55 +112,6 @@
return status;
}
- virtual status_t allocateTimedBuffer(size_t size, sp<IMemory>* buffer) {
- Parcel data, reply;
- data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
- data.writeInt64(size);
- status_t status = remote()->transact(ALLOCATE_TIMED_BUFFER,
- data, &reply);
- if (status == NO_ERROR) {
- status = reply.readInt32();
- if (status == NO_ERROR) {
- *buffer = interface_cast<IMemory>(reply.readStrongBinder());
- if (*buffer != 0 && (*buffer)->pointer() == NULL) {
- (*buffer).clear();
- }
- }
- }
- return status;
- }
-
- virtual status_t queueTimedBuffer(const sp<IMemory>& buffer,
- int64_t pts) {
- Parcel data, reply;
- data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(buffer));
- data.writeInt64(pts);
- status_t status = remote()->transact(QUEUE_TIMED_BUFFER,
- data, &reply);
- if (status == NO_ERROR) {
- status = reply.readInt32();
- }
- return status;
- }
-
- virtual status_t setMediaTimeTransform(const LinearTransform& xform,
- int target) {
- Parcel data, reply;
- data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
- data.writeInt64(xform.a_zero);
- data.writeInt64(xform.b_zero);
- data.writeInt32(xform.a_to_b_numer);
- data.writeInt32(xform.a_to_b_denom);
- data.writeInt32(target);
- status_t status = remote()->transact(SET_MEDIA_TIME_TRANSFORM,
- data, &reply);
- if (status == NO_ERROR) {
- status = reply.readInt32();
- }
- return status;
- }
-
virtual status_t setParameters(const String8& keyValuePairs) {
Parcel data, reply;
data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
@@ -235,35 +183,6 @@
reply->writeInt32(attachAuxEffect(data.readInt32()));
return NO_ERROR;
} break;
- case ALLOCATE_TIMED_BUFFER: {
- CHECK_INTERFACE(IAudioTrack, data, reply);
- sp<IMemory> buffer;
- status_t status = allocateTimedBuffer(data.readInt64(), &buffer);
- reply->writeInt32(status);
- if (status == NO_ERROR) {
- reply->writeStrongBinder(IInterface::asBinder(buffer));
- }
- return NO_ERROR;
- } break;
- case QUEUE_TIMED_BUFFER: {
- CHECK_INTERFACE(IAudioTrack, data, reply);
- sp<IMemory> buffer = interface_cast<IMemory>(
- data.readStrongBinder());
- uint64_t pts = data.readInt64();
- reply->writeInt32(queueTimedBuffer(buffer, pts));
- return NO_ERROR;
- } break;
- case SET_MEDIA_TIME_TRANSFORM: {
- CHECK_INTERFACE(IAudioTrack, data, reply);
- LinearTransform xform;
- xform.a_zero = data.readInt64();
- xform.b_zero = data.readInt64();
- xform.a_to_b_numer = data.readInt32();
- xform.a_to_b_denom = data.readInt32();
- int target = data.readInt32();
- reply->writeInt32(setMediaTimeTransform(xform, target));
- return NO_ERROR;
- } break;
case SET_PARAMETERS: {
CHECK_INTERFACE(IAudioTrack, data, reply);
String8 keyValuePairs(data.readString8());
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index 22f8af7..26dd2c9 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -95,18 +95,20 @@
}
virtual ssize_t decrypt(
- bool secure,
+ DestinationType dstType,
const uint8_t key[16],
const uint8_t iv[16],
- CryptoPlugin::Mode mode,
+ CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
const sp<IMemory> &sharedBuffer, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
AString *errorDetailMsg) {
Parcel data, reply;
data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
- data.writeInt32(secure);
+ data.writeInt32((int32_t)dstType);
data.writeInt32(mode);
+ data.writeInt32(pattern.mEncryptBlocks);
+ data.writeInt32(pattern.mSkipBlocks);
static const uint8_t kDummy[16] = { 0 };
@@ -134,8 +136,12 @@
data.writeInt32(numSubSamples);
data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples);
- if (secure) {
+ if (dstType == kDestinationTypeNativeHandle) {
+ data.writeNativeHandle(static_cast<native_handle_t *>(dstPtr));
+ } else if (dstType == kDestinationTypeOpaqueHandle) {
data.writeInt64(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(dstPtr)));
+ } else {
+ dstType = kDestinationTypeVmPointer;
}
remote()->transact(DECRYPT, data, &reply);
@@ -146,7 +152,7 @@
errorDetailMsg->setTo(reply.readCString());
}
- if (!secure && result >= 0) {
+ if (dstType == kDestinationTypeVmPointer && result >= 0) {
reply.read(dstPtr, result);
}
@@ -261,7 +267,11 @@
CHECK_INTERFACE(ICrypto, data, reply);
const char *mime = data.readCString();
- reply->writeInt32(requiresSecureDecoderComponent(mime));
+ if (mime == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ } else {
+ reply->writeInt32(requiresSecureDecoderComponent(mime));
+ }
return OK;
}
@@ -270,8 +280,11 @@
{
CHECK_INTERFACE(ICrypto, data, reply);
- bool secure = data.readInt32() != 0;
+ DestinationType dstType = (DestinationType)data.readInt32();
CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
+ CryptoPlugin::Pattern pattern;
+ pattern.mEncryptBlocks = data.readInt32();
+ pattern.mSkipBlocks = data.readInt32();
uint8_t key[16];
data.read(key, sizeof(key));
@@ -282,6 +295,10 @@
size_t totalSize = data.readInt32();
sp<IMemory> sharedBuffer =
interface_cast<IMemory>(data.readStrongBinder());
+ if (sharedBuffer == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ return OK;
+ }
int32_t offset = data.readInt32();
int32_t numSubSamples = data.readInt32();
@@ -293,11 +310,17 @@
subSamples,
sizeof(CryptoPlugin::SubSample) * numSubSamples);
- void *secureBufferId, *dstPtr;
- if (secure) {
+ native_handle_t *nativeHandle = NULL;
+ void *secureBufferId = NULL, *dstPtr;
+ if (dstType == kDestinationTypeNativeHandle) {
+ nativeHandle = data.readNativeHandle();
+ dstPtr = static_cast<void *>(nativeHandle);
+ } else if (dstType == kDestinationTypeOpaqueHandle) {
secureBufferId = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64()));
+ dstPtr = secureBufferId;
} else {
- dstPtr = calloc(1, totalSize);
+ dstType = kDestinationTypeVmPointer;
+ dstPtr = malloc(totalSize);
}
AString errorDetailMsg;
@@ -327,13 +350,13 @@
result = -EINVAL;
} else {
result = decrypt(
- secure,
+ dstType,
key,
iv,
- mode,
+ mode, pattern,
sharedBuffer, offset,
subSamples, numSubSamples,
- secure ? secureBufferId : dstPtr,
+ dstPtr,
&errorDetailMsg);
}
@@ -343,13 +366,21 @@
reply->writeCString(errorDetailMsg.c_str());
}
- if (!secure) {
+ if (dstType == kDestinationTypeVmPointer) {
if (result >= 0) {
CHECK_LE(result, static_cast<ssize_t>(totalSize));
reply->write(dstPtr, result);
}
free(dstPtr);
dstPtr = NULL;
+ } else if (dstType == kDestinationTypeNativeHandle) {
+ int err;
+ if ((err = native_handle_close(nativeHandle)) < 0) {
+ ALOGW("secure buffer native_handle_close failed: %d", err);
+ }
+ if ((err = native_handle_delete(nativeHandle)) < 0) {
+ ALOGW("secure buffer native_handle_delete failed: %d", err);
+ }
}
delete[] subSamples;
diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
index 76d1d68..ac864a4 100644
--- a/media/libmedia/IDataSource.cpp
+++ b/media/libmedia/IDataSource.cpp
@@ -32,6 +32,7 @@
READ_AT,
GET_SIZE,
CLOSE,
+ GET_FLAGS,
};
struct BpDataSource : public BpInterface<IDataSource> {
@@ -68,6 +69,13 @@
data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
remote()->transact(CLOSE, data, &reply);
}
+
+ virtual uint32_t getFlags() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
+ remote()->transact(GET_FLAGS, data, &reply);
+ return reply.readUint32();
+ }
};
IMPLEMENT_META_INTERFACE(DataSource, "android.media.IDataSource");
@@ -100,6 +108,11 @@
close();
return NO_ERROR;
} break;
+ case GET_FLAGS: {
+ CHECK_INTERFACE(IDataSource, data, reply);
+ reply->writeUint32(getFlags());
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
index 7c709cd..7f131f4 100644
--- a/media/libmedia/IDrm.cpp
+++ b/media/libmedia/IDrm.cpp
@@ -54,7 +54,6 @@
SIGN_RSA,
VERIFY,
SET_LISTENER,
- UNPROVISION_DEVICE,
GET_SECURE_STOP,
RELEASE_ALL_SECURE_STOPS
};
@@ -277,18 +276,6 @@
return reply.readInt32();
}
- virtual status_t unprovisionDevice() {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- status_t status = remote()->transact(UNPROVISION_DEVICE, data, &reply);
- if (status != OK) {
- return status;
- }
-
- return reply.readInt32();
- }
-
virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
@@ -749,14 +736,6 @@
return OK;
}
- case UNPROVISION_DEVICE:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- status_t result = unprovisionDevice();
- reply->writeInt32(result);
- return OK;
- }
-
case GET_SECURE_STOPS:
{
CHECK_INTERFACE(IDrm, data, reply);
diff --git a/media/libmedia/IMediaCodecList.cpp b/media/libmedia/IMediaCodecList.cpp
index e2df104..737f50c 100644
--- a/media/libmedia/IMediaCodecList.cpp
+++ b/media/libmedia/IMediaCodecList.cpp
@@ -157,6 +157,10 @@
{
CHECK_INTERFACE(IMediaCodecList, data, reply);
const char *type = data.readCString();
+ if (type == NULL) {
+ reply->writeInt32(NAME_NOT_FOUND);
+ return NO_ERROR;
+ }
bool isEncoder = static_cast<bool>(data.readInt32());
size_t startIndex = static_cast<size_t>(data.readInt32());
ssize_t index = findCodecByType(type, isEncoder, startIndex);
@@ -172,6 +176,10 @@
{
CHECK_INTERFACE(IMediaCodecList, data, reply);
const char *name = data.readCString();
+ if (name == NULL) {
+ reply->writeInt32(NAME_NOT_FOUND);
+ return NO_ERROR;
+ }
ssize_t index = findCodecByName(name);
if (index > INT32_MAX || index < 0) {
index = NAME_NOT_FOUND;
diff --git a/media/libmedia/IMediaCodecService.cpp b/media/libmedia/IMediaCodecService.cpp
new file mode 100644
index 0000000..dcf2b27
--- /dev/null
+++ b/media/libmedia/IMediaCodecService.cpp
@@ -0,0 +1,72 @@
+/*
+**
+** 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 "IMediaCodecService"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+#include <media/IMediaCodecService.h>
+
+namespace android {
+
+enum {
+ GET_OMX = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMediaCodecService : public BpInterface<IMediaCodecService>
+{
+public:
+ BpMediaCodecService(const sp<IBinder>& impl)
+ : BpInterface<IMediaCodecService>(impl)
+ {
+ }
+
+ virtual sp<IOMX> getOMX() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaCodecService::getInterfaceDescriptor());
+ remote()->transact(GET_OMX, data, &reply);
+ return interface_cast<IOMX>(reply.readStrongBinder());
+ }
+
+};
+
+IMPLEMENT_META_INTERFACE(MediaCodecService, "android.media.IMediaCodecService");
+
+// ----------------------------------------------------------------------
+
+status_t BnMediaCodecService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+
+ case GET_OMX: {
+ CHECK_INTERFACE(IMediaCodecService, data, reply);
+ sp<IOMX> omx = getOMX();
+ reply->writeStrongBinder(IInterface::asBinder(omx));
+ return NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+} // namespace android
diff --git a/media/libmedia/IMediaDrmService.cpp b/media/libmedia/IMediaDrmService.cpp
new file mode 100644
index 0000000..9b6ecfd
--- /dev/null
+++ b/media/libmedia/IMediaDrmService.cpp
@@ -0,0 +1,88 @@
+/*
+**
+** 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/Parcel.h>
+#include <binder/IMemory.h>
+#include <media/ICrypto.h>
+#include <media/IDrm.h>
+#include <media/IMediaDrmService.h>
+
+#include <utils/Errors.h> // for status_t
+#include <utils/String8.h>
+
+namespace android {
+
+enum {
+ MAKE_CRYPTO = IBinder::FIRST_CALL_TRANSACTION,
+ MAKE_DRM,
+};
+
+class BpMediaDrmService: public BpInterface<IMediaDrmService>
+{
+public:
+ BpMediaDrmService(const sp<IBinder>& impl)
+ : BpInterface<IMediaDrmService>(impl)
+ {
+ }
+
+ virtual sp<ICrypto> makeCrypto() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaDrmService::getInterfaceDescriptor());
+ remote()->transact(MAKE_CRYPTO, data, &reply);
+ return interface_cast<ICrypto>(reply.readStrongBinder());
+ }
+
+ virtual sp<IDrm> makeDrm() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaDrmService::getInterfaceDescriptor());
+ remote()->transact(MAKE_DRM, data, &reply);
+ return interface_cast<IDrm>(reply.readStrongBinder());
+ }
+
+};
+
+IMPLEMENT_META_INTERFACE(MediaDrmService, "android.media.IMediaDrmService");
+
+// ----------------------------------------------------------------------
+
+status_t BnMediaDrmService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case MAKE_CRYPTO: {
+ CHECK_INTERFACE(IMediaDrmService, data, reply);
+ sp<ICrypto> crypto = makeCrypto();
+ reply->writeStrongBinder(IInterface::asBinder(crypto));
+ return NO_ERROR;
+ } break;
+ case MAKE_DRM: {
+ CHECK_INTERFACE(IMediaDrmService, data, reply);
+ sp<IDrm> drm = makeDrm();
+ reply->writeStrongBinder(IInterface::asBinder(drm));
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+} // namespace android
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
new file mode 100644
index 0000000..76d5648
--- /dev/null
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -0,0 +1,182 @@
+/*
+ * 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 "BpMediaExtractor"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <media/IMediaExtractor.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+enum {
+ COUNTTRACKS = IBinder::FIRST_CALL_TRANSACTION,
+ GETTRACK,
+ GETTRACKMETADATA,
+ GETMETADATA,
+ FLAGS,
+ SETDRMFLAG,
+ GETDRMFLAG,
+ GETDRMTRACKINFO,
+ SETUID,
+ NAME
+};
+
+class BpMediaExtractor : public BpInterface<IMediaExtractor> {
+public:
+ BpMediaExtractor(const sp<IBinder>& impl)
+ : BpInterface<IMediaExtractor>(impl)
+ {
+ }
+
+ virtual size_t countTracks() {
+ ALOGV("countTracks");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ status_t ret = remote()->transact(COUNTTRACKS, data, &reply);
+ size_t numTracks = 0;
+ if (ret == NO_ERROR) {
+ numTracks = reply.readUint32();
+ }
+ return numTracks;
+ }
+ virtual sp<IMediaSource> getTrack(size_t index) {
+ ALOGV("getTrack(%zu)", index);
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ data.writeUint32(index);
+ status_t ret = remote()->transact(GETTRACK, data, &reply);
+ if (ret == NO_ERROR) {
+ return interface_cast<IMediaSource>(reply.readStrongBinder());
+ }
+ return NULL;
+ }
+
+ virtual sp<MetaData> getTrackMetaData(
+ size_t index, uint32_t flags) {
+ ALOGV("getTrackMetaData(%zu, %u)", index, flags);
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ data.writeUint32(index);
+ data.writeUint32(flags);
+ status_t ret = remote()->transact(GETTRACKMETADATA, data, &reply);
+ if (ret == NO_ERROR) {
+ return MetaData::createFromParcel(reply);
+ }
+ return NULL;
+ }
+
+ virtual sp<MetaData> getMetaData() {
+ ALOGV("getMetaData");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ status_t ret = remote()->transact(GETMETADATA, data, &reply);
+ if (ret == NO_ERROR) {
+ return MetaData::createFromParcel(reply);
+ }
+ return NULL;
+ }
+
+ virtual uint32_t flags() const {
+ ALOGV("flags NOT IMPLEMENTED");
+ return 0;
+ }
+
+ virtual void setDrmFlag(bool flag __unused) {
+ ALOGV("setDrmFlag NOT IMPLEMENTED");
+ }
+ virtual bool getDrmFlag() {
+ ALOGV("getDrmFlag NOT IMPLEMENTED");
+ return false;
+ }
+ virtual char* getDrmTrackInfo(size_t trackID __unused, int *len __unused) {
+ ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
+ return NULL;
+ }
+ virtual void setUID(uid_t uid __unused) {
+ ALOGV("setUID NOT IMPLEMENTED");
+ }
+
+ virtual const char * name() {
+ ALOGV("name NOT IMPLEMENTED");
+ return NULL;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
+
+#undef LOG_TAG
+#define LOG_TAG "BnMediaExtractor"
+
+status_t BnMediaExtractor::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case COUNTTRACKS: {
+ ALOGV("countTracks");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ size_t numTracks = countTracks();
+ if (numTracks > INT32_MAX) {
+ numTracks = 0;
+ }
+ reply->writeUint32(uint32_t(numTracks));
+ return NO_ERROR;
+ }
+ case GETTRACK: {
+ ALOGV("getTrack()");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ uint32_t idx;
+ if (data.readUint32(&idx) == NO_ERROR) {
+ return reply->writeStrongBinder(IInterface::asBinder(getTrack((size_t(idx)))));
+ }
+ return UNKNOWN_ERROR;
+ }
+ case GETTRACKMETADATA: {
+ ALOGV("getTrackMetaData");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ uint32_t idx;
+ uint32_t flags;
+ if (data.readUint32(&idx) == NO_ERROR &&
+ data.readUint32(&flags) == NO_ERROR) {
+ sp<MetaData> meta = getTrackMetaData(idx, flags);
+ meta->writeToParcel(*reply);
+ return NO_ERROR;
+ }
+ return UNKNOWN_ERROR;
+ }
+ case GETMETADATA: {
+ ALOGV("getMetaData");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ sp<MetaData> meta = getMetaData();
+ if (meta != NULL) {
+ meta->writeToParcel(*reply);
+ return NO_ERROR;
+ }
+ return UNKNOWN_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+
+} // namespace android
+
diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
new file mode 100644
index 0000000..dcbbde2
--- /dev/null
+++ b/media/libmedia/IMediaExtractorService.cpp
@@ -0,0 +1,87 @@
+/*
+**
+** Copyright 2007, 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 "IMediaExtractorService"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+#include <media/IMediaExtractorService.h>
+
+namespace android {
+
+enum {
+ MAKE_EXTRACTOR = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMediaExtractorService : public BpInterface<IMediaExtractorService>
+{
+public:
+ BpMediaExtractorService(const sp<IBinder>& impl)
+ : BpInterface<IMediaExtractorService>(impl)
+ {
+ }
+
+ virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(source));
+ if (mime != NULL) {
+ data.writeCString(mime);
+ }
+ status_t ret = remote()->transact(MAKE_EXTRACTOR, data, &reply);
+ if (ret == NO_ERROR) {
+ return interface_cast<IMediaExtractor>(reply.readStrongBinder());
+ }
+ return NULL;
+ }
+
+};
+
+IMPLEMENT_META_INTERFACE(MediaExtractorService, "android.media.IMediaExtractorService");
+
+// ----------------------------------------------------------------------
+
+status_t BnMediaExtractorService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+
+ case MAKE_EXTRACTOR: {
+ CHECK_INTERFACE(IMediaExtractorService, data, reply);
+ sp<IBinder> b;
+ status_t ret = data.readStrongBinder(&b);
+ if (ret != NO_ERROR || b == NULL) {
+ ALOGE("Error reading source from parcel");
+ return ret;
+ }
+ sp<IDataSource> source = interface_cast<IDataSource>(b);
+ const char *mime = data.readCString();
+ sp<IMediaExtractor> ex = makeExtractor(source, mime);
+ reply->writeStrongBinder(IInterface::asBinder(ex));
+ return NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+} // namespace android
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 9765f0d..0bee8d3 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -224,6 +224,11 @@
const char* srcUrl = data.readCString();
+ if (httpService == NULL || srcUrl == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ return NO_ERROR;
+ }
+
KeyedVector<String8, String8> headers;
size_t numHeaders = (size_t) data.readInt64();
for (size_t i = 0; i < numHeaders; ++i) {
@@ -240,7 +245,7 @@
} break;
case SET_DATA_SOURCE_FD: {
CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
- int fd = dup(data.readFileDescriptor());
+ int fd = data.readFileDescriptor();
int64_t offset = data.readInt64();
int64_t length = data.readInt64();
reply->writeInt32(setDataSource(fd, offset, length));
@@ -250,7 +255,11 @@
CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
sp<IDataSource> source =
interface_cast<IDataSource>(data.readStrongBinder());
- reply->writeInt32(setDataSource(source));
+ if (source == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ } else {
+ reply->writeInt32(setDataSource(source));
+ }
return NO_ERROR;
} break;
case GET_FRAME_AT_TIME: {
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 942aec3..519a1fd 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -444,6 +444,10 @@
}
const char* url = data.readCString();
+ if (url == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ return NO_ERROR;
+ }
KeyedVector<String8, String8> headers;
int32_t numHeaders = data.readInt32();
for (int i = 0; i < numHeaders; ++i) {
@@ -467,14 +471,22 @@
CHECK_INTERFACE(IMediaPlayer, data, reply);
sp<IStreamSource> source =
interface_cast<IStreamSource>(data.readStrongBinder());
- reply->writeInt32(setDataSource(source));
+ if (source == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ } else {
+ reply->writeInt32(setDataSource(source));
+ }
return NO_ERROR;
}
case SET_DATA_SOURCE_CALLBACK: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
sp<IDataSource> source =
interface_cast<IDataSource>(data.readStrongBinder());
- reply->writeInt32(setDataSource(source));
+ if (source == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ } else {
+ reply->writeInt32(setDataSource(source));
+ }
return NO_ERROR;
}
case SET_VIDEO_SURFACETEXTURE: {
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 05f8670..afc94ab 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -220,6 +220,10 @@
const String16 opPackageName = data.readString16();
sp<IRemoteDisplayClient> client(
interface_cast<IRemoteDisplayClient>(data.readStrongBinder()));
+ if (client == NULL) {
+ reply->writeStrongBinder(NULL);
+ return NO_ERROR;
+ }
String8 iface(data.readString8());
sp<IRemoteDisplay> display(listenForRemoteDisplay(opPackageName, client, iface));
reply->writeStrongBinder(IInterface::asBinder(display));
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index ee3b584..0eea820 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -54,7 +54,9 @@
SET_PREVIEW_SURFACE,
SET_CAMERA,
SET_LISTENER,
- SET_CLIENT_NAME
+ SET_CLIENT_NAME,
+ PAUSE,
+ RESUME
};
class BpMediaRecorder: public BpInterface<IMediaRecorder>
@@ -276,6 +278,24 @@
return reply.readInt32();
}
+ status_t pause()
+ {
+ ALOGV("pause");
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ remote()->transact(PAUSE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t resume()
+ {
+ ALOGV("resume");
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ remote()->transact(RESUME, data, &reply);
+ return reply.readInt32();
+ }
+
status_t close()
{
ALOGV("close");
@@ -340,6 +360,18 @@
reply->writeInt32(start());
return NO_ERROR;
} break;
+ case PAUSE: {
+ ALOGV("PAUSE");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(pause());
+ return NO_ERROR;
+ } break;
+ case RESUME: {
+ ALOGV("RESUME");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(resume());
+ return NO_ERROR;
+ } break;
case PREPARE: {
ALOGV("PREPARE");
CHECK_INTERFACE(IMediaRecorder, data, reply);
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
new file mode 100644
index 0000000..b988c46
--- /dev/null
+++ b/media/libmedia/IMediaSource.cpp
@@ -0,0 +1,393 @@
+/*
+ * 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 "BpMediaSource"
+#include <utils/Log.h>
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <media/IMediaSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+enum {
+ START = IBinder::FIRST_CALL_TRANSACTION,
+ STOP,
+ PAUSE,
+ GETFORMAT,
+ READ,
+ RELEASE_BUFFER
+};
+
+enum {
+ NULL_BUFFER,
+ SHARED_BUFFER,
+ INLINE_BUFFER
+};
+
+class RemoteMediaBufferReleaser : public BBinder {
+public:
+ RemoteMediaBufferReleaser(MediaBuffer *buf, sp<BnMediaSource> owner) {
+ mBuf = buf;
+ mOwner = owner;
+ }
+ ~RemoteMediaBufferReleaser() {
+ if (mBuf) {
+ ALOGW("RemoteMediaBufferReleaser dtor called while still holding buffer");
+ mBuf->release();
+ }
+ }
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0) {
+ if (code == RELEASE_BUFFER) {
+ mBuf->release();
+ mBuf = NULL;
+ return OK;
+ } else {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ }
+private:
+ MediaBuffer *mBuf;
+ // Keep a ref to ensure MediaBuffer is released before the owner, i.e., BnMediaSource,
+ // because BnMediaSource needs to delete MediaBufferGroup in its dtor and
+ // MediaBufferGroup dtor requires all MediaBuffer's have 0 ref count.
+ sp<BnMediaSource> mOwner;
+};
+
+
+class RemoteMediaBufferWrapper : public MediaBuffer {
+public:
+ RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source);
+protected:
+ virtual ~RemoteMediaBufferWrapper();
+private:
+ sp<IMemory> mMemory;
+ sp<IBinder> mRemoteSource;
+};
+
+RemoteMediaBufferWrapper::RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source)
+: MediaBuffer(mem->pointer(), mem->size()) {
+ mMemory = mem;
+ mRemoteSource = source;
+}
+
+RemoteMediaBufferWrapper::~RemoteMediaBufferWrapper() {
+ mMemory.clear();
+ // Explicitly ask the remote side to release the buffer. We could also just clear
+ // mRemoteSource, but that doesn't immediately release the reference on the remote side.
+ Parcel data, reply;
+ mRemoteSource->transact(RELEASE_BUFFER, data, &reply);
+ mRemoteSource.clear();
+}
+
+class BpMediaSource : public BpInterface<IMediaSource> {
+public:
+ BpMediaSource(const sp<IBinder>& impl)
+ : BpInterface<IMediaSource>(impl)
+ {
+ }
+
+ virtual status_t start(MetaData *params) {
+ ALOGV("start");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ if (params) {
+ params->writeToParcel(data);
+ }
+ status_t ret = remote()->transact(START, data, &reply);
+ if (ret == NO_ERROR && params) {
+ ALOGW("ignoring potentially modified MetaData from start");
+ ALOGW("input:");
+ params->dumpToLog();
+ sp<MetaData> meta = MetaData::createFromParcel(reply);
+ ALOGW("output:");
+ meta->dumpToLog();
+ }
+ return ret;
+ }
+
+ virtual status_t stop() {
+ ALOGV("stop");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ return remote()->transact(STOP, data, &reply);
+ }
+
+ virtual sp<MetaData> getFormat() {
+ ALOGV("getFormat");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ status_t ret = remote()->transact(GETFORMAT, data, &reply);
+ if (ret == NO_ERROR) {
+ mMetaData = MetaData::createFromParcel(reply);
+ return mMetaData;
+ }
+ return NULL;
+ }
+
+ virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
+ ALOGV("read");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ if (options) {
+ data.writeByteArray(sizeof(*options), (uint8_t*) options);
+ }
+ status_t ret = remote()->transact(READ, data, &reply);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ // wrap the returned data in a MediaBuffer
+ ret = reply.readInt32();
+ int32_t buftype = reply.readInt32();
+ if (buftype == SHARED_BUFFER) {
+ sp<IBinder> remote = reply.readStrongBinder();
+ sp<IBinder> binder = reply.readStrongBinder();
+ sp<IMemory> mem = interface_cast<IMemory>(binder);
+ if (mem == NULL) {
+ ALOGE("received NULL IMemory for shared buffer");
+ }
+ size_t offset = reply.readInt32();
+ size_t length = reply.readInt32();
+ MediaBuffer *buf = new RemoteMediaBufferWrapper(mem, remote);
+ buf->set_range(offset, length);
+ buf->meta_data()->updateFromParcel(reply);
+ *buffer = buf;
+ } else if (buftype == NULL_BUFFER) {
+ ALOGV("got status %d and NULL buffer", ret);
+ *buffer = NULL;
+ } else {
+ int32_t len = reply.readInt32();
+ ALOGV("got status %d and len %d", ret, len);
+ *buffer = new MediaBuffer(len);
+ reply.read((*buffer)->data(), len);
+ (*buffer)->meta_data()->updateFromParcel(reply);
+ }
+ return ret;
+ }
+
+ virtual status_t pause() {
+ ALOGV("pause");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ return remote()->transact(PAUSE, data, &reply);
+ }
+
+ virtual status_t setBuffers(const Vector<MediaBuffer *> & buffers __unused) {
+ ALOGV("setBuffers NOT IMPLEMENTED");
+ return ERROR_UNSUPPORTED; // default
+ }
+
+private:
+ // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive
+ // XXX: could we use this for caching, or does metadata change on the fly?
+ sp<MetaData> mMetaData;
+
+};
+
+IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
+
+#undef LOG_TAG
+#define LOG_TAG "BnMediaSource"
+
+BnMediaSource::BnMediaSource()
+ : mGroup(NULL) {
+}
+
+BnMediaSource::~BnMediaSource() {
+ delete mGroup;
+ mGroup = NULL;
+}
+
+status_t BnMediaSource::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case START: {
+ ALOGV("start");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ sp<MetaData> meta;
+ if (data.dataAvail()) {
+ meta = MetaData::createFromParcel(data);
+ }
+ status_t ret = start(meta.get());
+ if (ret == NO_ERROR && meta != NULL) {
+ meta->writeToParcel(*reply);
+ }
+ return ret;
+ }
+ case STOP: {
+ ALOGV("stop");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ return stop();
+ }
+ case PAUSE: {
+ ALOGV("pause");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ return pause();
+ }
+ case GETFORMAT: {
+ ALOGV("getFormat");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ sp<MetaData> meta = getFormat();
+ if (meta != NULL) {
+ meta->writeToParcel(*reply);
+ return NO_ERROR;
+ }
+ return UNKNOWN_ERROR;
+ }
+ case READ: {
+ ALOGV("read");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ status_t ret;
+ MediaBuffer *buf = NULL;
+ ReadOptions opts;
+ uint32_t len;
+ if (data.readUint32(&len) == NO_ERROR &&
+ len == sizeof(opts) && data.read((void*)&opts, len) == NO_ERROR) {
+ ret = read(&buf, &opts);
+ } else {
+ ret = read(&buf, NULL);
+ }
+
+ reply->writeInt32(ret);
+ if (buf != NULL) {
+ size_t usedSize = buf->range_length();
+ // even if we're using shared memory, we might not want to use it, since for small
+ // sizes it's faster to copy data through the Binder transaction
+ // On the other hand, if the data size is large enough, it's better to use shared
+ // memory. When data is too large, binder can't handle it.
+ if (usedSize >= MediaBuffer::kSharedMemThreshold) {
+ ALOGV("use shared memory: %zu", usedSize);
+
+ MediaBuffer *transferBuf = buf;
+ size_t offset = buf->range_offset();
+ if (transferBuf->mMemory == NULL) {
+ if (mGroup == NULL) {
+ mGroup = new MediaBufferGroup;
+ size_t allocateSize = usedSize;
+ if (usedSize < SIZE_MAX / 3) {
+ allocateSize = usedSize * 3 / 2;
+ }
+ mGroup->add_buffer(new MediaBuffer(allocateSize));
+ }
+
+ ret = mGroup->acquire_buffer(
+ &transferBuf, false /* nonBlocking */, usedSize);
+ if (ret != OK || transferBuf == NULL || transferBuf->mMemory == NULL) {
+ ALOGW("failed to acquire shared memory, ret %d", ret);
+ reply->writeInt32(NULL_BUFFER);
+ return NO_ERROR;
+ }
+ memcpy(transferBuf->data(), (uint8_t*)buf->data() + buf->range_offset(),
+ buf->range_length());
+ offset = 0;
+ }
+
+ reply->writeInt32(SHARED_BUFFER);
+ RemoteMediaBufferReleaser *wrapper =
+ new RemoteMediaBufferReleaser(transferBuf, this);
+ reply->writeStrongBinder(wrapper);
+ reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
+ reply->writeInt32(offset);
+ reply->writeInt32(usedSize);
+ buf->meta_data()->writeToParcel(*reply);
+ } else {
+ // buffer is small: copy it
+ if (buf->mMemory != NULL) {
+ ALOGV("%zu shared mem available, but only %zu used", buf->mMemory->size(), buf->range_length());
+ }
+ reply->writeInt32(INLINE_BUFFER);
+ reply->writeByteArray(buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
+ buf->meta_data()->writeToParcel(*reply);
+ buf->release();
+ }
+ } else {
+ ALOGV("ret %d, buf %p", ret, buf);
+ reply->writeInt32(NULL_BUFFER);
+ }
+ return NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+IMediaSource::ReadOptions::ReadOptions() {
+ reset();
+}
+
+void IMediaSource::ReadOptions::reset() {
+ mOptions = 0;
+ mSeekTimeUs = 0;
+ mLatenessUs = 0;
+ mNonBlocking = false;
+}
+
+void IMediaSource::ReadOptions::setNonBlocking() {
+ mNonBlocking = true;
+}
+
+void IMediaSource::ReadOptions::clearNonBlocking() {
+ mNonBlocking = false;
+}
+
+bool IMediaSource::ReadOptions::getNonBlocking() const {
+ return mNonBlocking;
+}
+
+void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
+ mOptions |= kSeekTo_Option;
+ mSeekTimeUs = time_us;
+ mSeekMode = mode;
+}
+
+void IMediaSource::ReadOptions::clearSeekTo() {
+ mOptions &= ~kSeekTo_Option;
+ mSeekTimeUs = 0;
+ mSeekMode = SEEK_CLOSEST_SYNC;
+}
+
+bool IMediaSource::ReadOptions::getSeekTo(
+ int64_t *time_us, SeekMode *mode) const {
+ *time_us = mSeekTimeUs;
+ *mode = mSeekMode;
+ return (mOptions & kSeekTo_Option) != 0;
+}
+
+void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
+ mLatenessUs = lateness_us;
+}
+
+int64_t IMediaSource::ReadOptions::getLateBy() const {
+ return mLatenessUs;
+}
+
+
+} // namespace android
+
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 07f3697..6a941c1 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -37,7 +37,7 @@
GET_CONFIG,
SET_CONFIG,
GET_STATE,
- ENABLE_GRAPHIC_BUFFERS,
+ ENABLE_NATIVE_BUFFERS,
USE_BUFFER,
USE_GRAPHIC_BUFFER,
CREATE_INPUT_SURFACE,
@@ -46,7 +46,7 @@
SIGNAL_END_OF_INPUT_STREAM,
STORE_META_DATA_IN_BUFFERS,
PREPARE_FOR_ADAPTIVE_PLAYBACK,
- ALLOC_BUFFER,
+ ALLOC_SECURE_BUFFER,
ALLOC_BUFFER_WITH_BACKUP,
FREE_BUFFER,
FILL_BUFFER,
@@ -98,7 +98,9 @@
}
virtual status_t allocateNode(
- const char *name, const sp<IOMXObserver> &observer, node_id *node) {
+ const char *name, const sp<IOMXObserver> &observer,
+ sp<IBinder> *nodeBinder,
+ node_id *node) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
data.writeCString(name);
@@ -108,6 +110,9 @@
status_t err = reply.readInt32();
if (err == OK) {
*node = (node_id)reply.readInt32();
+ if (nodeBinder != NULL) {
+ *nodeBinder = remote();
+ }
} else {
*node = 0;
}
@@ -217,14 +222,15 @@
return reply.readInt32();
}
- virtual status_t enableGraphicBuffers(
- node_id node, OMX_U32 port_index, OMX_BOOL enable) {
+ virtual status_t enableNativeBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL graphic, OMX_BOOL enable) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
data.writeInt32((int32_t)node);
data.writeInt32(port_index);
+ data.writeInt32((uint32_t)graphic);
data.writeInt32((uint32_t)enable);
- remote()->transact(ENABLE_GRAPHIC_BUFFERS, data, &reply);
+ remote()->transact(ENABLE_NATIVE_BUFFERS, data, &reply);
status_t err = reply.readInt32();
return err;
@@ -453,26 +459,31 @@
}
- virtual status_t allocateBuffer(
+ virtual status_t allocateSecureBuffer(
node_id node, OMX_U32 port_index, size_t size,
- buffer_id *buffer, void **buffer_data) {
+ buffer_id *buffer, void **buffer_data, native_handle_t **native_handle) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
data.writeInt32((int32_t)node);
data.writeInt32(port_index);
data.writeInt64(size);
- remote()->transact(ALLOC_BUFFER, data, &reply);
+ remote()->transact(ALLOC_SECURE_BUFFER, data, &reply);
status_t err = reply.readInt32();
if (err != OK) {
*buffer = 0;
-
+ *buffer_data = NULL;
+ *native_handle = NULL;
return err;
}
*buffer = (buffer_id)reply.readInt32();
*buffer_data = (void *)reply.readInt64();
-
+ if (*buffer_data == NULL) {
+ *native_handle = reply.readNativeHandle();
+ } else {
+ *native_handle = NULL;
+ }
return err;
}
@@ -642,9 +653,16 @@
sp<IOMXObserver> observer =
interface_cast<IOMXObserver>(data.readStrongBinder());
+ if (name == NULL || observer == NULL) {
+ ALOGE("b/26392700");
+ reply->writeInt32(INVALID_OPERATION);
+ return NO_ERROR;
+ }
+
node_id node;
- status_t err = allocateNode(name, observer, &node);
+ status_t err = allocateNode(name, observer,
+ NULL /* nodeBinder */, &node);
reply->writeInt32(err);
if (err == OK) {
reply->writeInt32((int32_t)node);
@@ -748,15 +766,16 @@
return NO_ERROR;
}
- case ENABLE_GRAPHIC_BUFFERS:
+ case ENABLE_NATIVE_BUFFERS:
{
CHECK_OMX_INTERFACE(IOMX, data, reply);
node_id node = (node_id)data.readInt32();
OMX_U32 port_index = data.readInt32();
+ OMX_BOOL graphic = (OMX_BOOL)data.readInt32();
OMX_BOOL enable = (OMX_BOOL)data.readInt32();
- status_t err = enableGraphicBuffers(node, port_index, enable);
+ status_t err = enableNativeBuffers(node, port_index, graphic, enable);
reply->writeInt32(err);
return NO_ERROR;
@@ -787,6 +806,12 @@
interface_cast<IMemory>(data.readStrongBinder());
OMX_U32 allottedSize = data.readInt32();
+ if (params == NULL) {
+ ALOGE("b/26392700");
+ reply->writeInt32(INVALID_OPERATION);
+ return NO_ERROR;
+ }
+
buffer_id buffer;
status_t err = useBuffer(node, port_index, params, &buffer, allottedSize);
reply->writeInt32(err);
@@ -891,10 +916,16 @@
interface_cast<IGraphicBufferConsumer>(data.readStrongBinder());
MetadataBufferType type = kMetadataBufferTypeInvalid;
- status_t err = setInputSurface(node, port_index, bufferConsumer, &type);
- if ((err != OK) && (type == kMetadataBufferTypeInvalid)) {
- android_errorWriteLog(0x534e4554, "26324358");
+ status_t err = INVALID_OPERATION;
+ if (bufferConsumer == NULL) {
+ ALOGE("b/26392700");
+ } else {
+ err = setInputSurface(node, port_index, bufferConsumer, &type);
+
+ if ((err != OK) && (type == kMetadataBufferTypeInvalid)) {
+ android_errorWriteLog(0x534e4554, "26324358");
+ }
}
reply->writeInt32(type);
@@ -972,7 +1003,7 @@
return NO_ERROR;
}
- case ALLOC_BUFFER:
+ case ALLOC_SECURE_BUFFER:
{
CHECK_OMX_INTERFACE(IOMX, data, reply);
@@ -987,14 +1018,18 @@
size_t size = data.readInt64();
buffer_id buffer;
- void *buffer_data;
- status_t err = allocateBuffer(
- node, port_index, size, &buffer, &buffer_data);
+ void *buffer_data = NULL;
+ native_handle_t *native_handle = NULL;
+ status_t err = allocateSecureBuffer(
+ node, port_index, size, &buffer, &buffer_data, &native_handle);
reply->writeInt32(err);
if (err == OK) {
reply->writeInt32((int32_t)buffer);
reply->writeInt64((uintptr_t)buffer_data);
+ if (buffer_data == NULL) {
+ reply->writeNativeHandle(native_handle);
+ }
}
return NO_ERROR;
@@ -1010,6 +1045,12 @@
interface_cast<IMemory>(data.readStrongBinder());
OMX_U32 allottedSize = data.readInt32();
+ if (params == NULL) {
+ ALOGE("b/26392700");
+ reply->writeInt32(INVALID_OPERATION);
+ return NO_ERROR;
+ }
+
buffer_id buffer;
status_t err = allocateBufferWithBackup(
node, port_index, params, &buffer, allottedSize);
@@ -1073,6 +1114,12 @@
node_id node = (node_id)data.readInt32();
const char *parameter_name = data.readCString();
+ if (parameter_name == NULL) {
+ ALOGE("b/26392700");
+ reply->writeInt32(INVALID_OPERATION);
+ return NO_ERROR;
+ }
+
OMX_INDEXTYPE index;
status_t err = getExtensionIndex(node, parameter_name, &index);
diff --git a/media/libmedia/IResourceManagerService.cpp b/media/libmedia/IResourceManagerService.cpp
index 4598686..6cb4440 100644
--- a/media/libmedia/IResourceManagerService.cpp
+++ b/media/libmedia/IResourceManagerService.cpp
@@ -132,6 +132,9 @@
int64_t clientId = data.readInt64();
sp<IResourceManagerClient> client(
interface_cast<IResourceManagerClient>(data.readStrongBinder()));
+ if (client == NULL) {
+ return NO_ERROR;
+ }
Vector<MediaResource> resources;
readFromParcel(data, &resources);
addResource(pid, clientId, client, resources);
diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp
index 840e453..8c0905c 100644
--- a/media/libmedia/IStreamSource.cpp
+++ b/media/libmedia/IStreamSource.cpp
@@ -111,7 +111,11 @@
sp<IMemory> mem =
interface_cast<IMemory>(data.readStrongBinder());
- buffers.push(mem);
+ if (mem != NULL) {
+ buffers.push(mem);
+ } else if (data.dataAvail() == 0) {
+ break;
+ }
}
setBuffers(buffers);
break;
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index 8d3fa7b..06abd8d 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -26,8 +26,6 @@
#include <media/stagefright/foundation/AMessage.h>
#include <binder/Parcel.h>
-#include <media/stagefright/OMXCodec.h>
-
namespace android {
void MediaCodecInfo::Capabilities::getSupportedProfileLevels(
@@ -101,6 +99,21 @@
return OK;
}
+void MediaCodecInfo::CapabilitiesBuilder::addProfileLevel(uint32_t profile, uint32_t level) {
+ ProfileLevel profileLevel;
+ profileLevel.mProfile = profile;
+ profileLevel.mLevel = level;
+ mProfileLevels.push_back(profileLevel);
+}
+
+void MediaCodecInfo::CapabilitiesBuilder::addColorFormat(uint32_t format) {
+ mColorFormats.push(format);
+}
+
+void MediaCodecInfo::CapabilitiesBuilder::addFlags(uint32_t flags) {
+ mFlags |= flags;
+}
+
bool MediaCodecInfo::isEncoder() const {
return mIsEncoder;
}
@@ -225,26 +238,15 @@
}
}
-status_t MediaCodecInfo::initializeCapabilities(const CodecCapabilities &caps) {
- mCurrentCaps->mProfileLevels.clear();
+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();
-
- for (size_t i = 0; i < caps.mProfileLevels.size(); ++i) {
- const CodecProfileLevel &src = caps.mProfileLevels.itemAt(i);
-
- ProfileLevel profileLevel;
- profileLevel.mProfile = src.mProfile;
- profileLevel.mLevel = src.mLevel;
- mCurrentCaps->mProfileLevels.push_back(profileLevel);
- }
-
- for (size_t i = 0; i < caps.mColorFormats.size(); ++i) {
- mCurrentCaps->mColorFormats.push_back(caps.mColorFormats.itemAt(i));
- }
-
- mCurrentCaps->mFlags = caps.mFlags;
- mCurrentCaps->mDetails = new AMessage;
-
+ mCurrentCaps->mColorFormats.appendVector(caps->mColorFormats);
+ mCurrentCaps->mProfileLevels.clear();
+ mCurrentCaps->mProfileLevels.appendVector(caps->mProfileLevels);
+ mCurrentCaps->mFlags = caps->mFlags;
+ mCurrentCaps->mDetails = caps->mDetails;
return OK;
}
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index c5790fb..ff0e52e 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -23,7 +23,7 @@
#include <utils/Log.h>
#include <utils/Vector.h>
#include <cutils/properties.h>
-#include <libexpat/expat.h>
+#include <expat.h>
#include <media/MediaProfiles.h>
#include <media/stagefright/foundation/ADebug.h>
#include <OMX_Video.h>
@@ -37,7 +37,8 @@
const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = {
{"h263", VIDEO_ENCODER_H263},
{"h264", VIDEO_ENCODER_H264},
- {"m4v", VIDEO_ENCODER_MPEG_4_SP}
+ {"m4v", VIDEO_ENCODER_MPEG_4_SP},
+ {"hevc", VIDEO_ENCODER_HEVC}
};
const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index 5197ce2..faae954 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -42,7 +42,7 @@
MidiIoWrapper::MidiIoWrapper(int fd, off64_t offset, int64_t size) {
ALOGV("MidiIoWrapper(fd=%d)", fd);
- mFd = dup(fd);
+ mFd = fd < 0 ? -1 : dup(fd);
mBase = offset;
mLength = size;
}
@@ -61,7 +61,9 @@
MidiIoWrapper::~MidiIoWrapper() {
ALOGV("~MidiIoWrapper");
- close(mFd);
+ if (mFd >= 0) {
+ close(mFd);
+ }
}
int MidiIoWrapper::readAt(void *buffer, int offset, int size) {
@@ -70,6 +72,10 @@
if (mDataSource != NULL) {
return mDataSource->readAt(offset, buffer, size);
}
+ if (mFd < 0) {
+ errno = EBADF;
+ return -1; // as per failed read.
+ }
lseek(mFd, mBase + offset, SEEK_SET);
if (offset + size > mLength) {
size = mLength - offset;
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 6da5348..9f4b4de 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -1580,7 +1580,8 @@
}
long dec = lAmplitude/count;
// loop generation
- while (count--) {
+ while (count) {
+ count--;
Sample = ((lA1 * lS1) >> S_Q14) - lS2;
// shift delay
lS2 = lS1;
@@ -1591,7 +1592,8 @@
}
} else {
// loop generation
- while (count--) {
+ while (count) {
+ count--;
Sample = ((lA1 * lS1) >> S_Q14) - lS2;
// shift delay
lS2 = lS1;
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 502ab2d..337e963 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -181,22 +181,6 @@
return err;
}
-status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)
-{
- ALOGV("setDataSource");
- status_t err = UNKNOWN_ERROR;
- const sp<IMediaPlayerService>& service(getMediaPlayerService());
- if (service != 0) {
- sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
- if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
- (NO_ERROR != player->setDataSource(source))) {
- player.clear();
- }
- err = attachNewPlayer(player);
- }
- return err;
-}
-
status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)
{
ALOGV("setDataSource(IDataSource)");
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 8bbd8f1..bfdf41d 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -561,6 +561,50 @@
return ret;
}
+status_t MediaRecorder::pause()
+{
+ ALOGV("pause");
+ if (mMediaRecorder == NULL) {
+ ALOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_RECORDING)) {
+ ALOGE("stop called in an invalid state: %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->pause();
+ if (OK != ret) {
+ ALOGE("pause failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return ret;
+ }
+
+ return ret;
+}
+
+status_t MediaRecorder::resume()
+{
+ ALOGV("resume");
+ if (mMediaRecorder == NULL) {
+ ALOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_RECORDING)) {
+ ALOGE("resume called in an invalid state: %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->resume();
+ if (OK != ret) {
+ ALOGE("resume failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return ret;
+ }
+
+ return ret;
+}
+
status_t MediaRecorder::close()
{
ALOGV("close");
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 4d1b587..81f2af3 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -18,7 +18,6 @@
MetadataRetrieverClient.cpp \
RemoteDisplay.cpp \
SharedLibrary.cpp \
- StagefrightPlayer.cpp \
StagefrightRecorder.cpp \
TestPlayerStub.cpp \
@@ -45,6 +44,7 @@
LOCAL_STATIC_LIBRARIES := \
libstagefright_nuplayer \
libstagefright_rtsp \
+ libstagefright_timedtext \
LOCAL_C_INCLUDES := \
$(TOP)/frameworks/av/media/libstagefright/include \
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index 147d35f..9165b9d 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -235,10 +235,11 @@
}
ssize_t Crypto::decrypt(
- bool secure,
+ DestinationType dstType,
const uint8_t key[16],
const uint8_t iv[16],
CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern &pattern,
const sp<IMemory> &sharedBuffer, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
@@ -256,7 +257,8 @@
const void *srcPtr = static_cast<uint8_t *>(sharedBuffer->pointer()) + offset;
return mPlugin->decrypt(
- secure, key, iv, mode, srcPtr, subSamples, numSubSamples, dstPtr,
+ dstType != kDestinationTypeVmPointer,
+ key, iv, mode, pattern, srcPtr, subSamples, numSubSamples, dstPtr,
errorDetailMsg);
}
diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h
index 99ea95d..7d181d3 100644
--- a/media/libmediaplayerservice/Crypto.h
+++ b/media/libmediaplayerservice/Crypto.h
@@ -50,10 +50,11 @@
virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
virtual ssize_t decrypt(
- bool secure,
+ DestinationType dstType,
const uint8_t key[16],
const uint8_t iv[16],
CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern &pattern,
const sp<IMemory> &sharedBuffer, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index a7f6f8b..321ccbf 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -40,9 +40,6 @@
}
static bool checkPermission(const char* permissionString) {
-#ifndef HAVE_ANDROID_OS
- return true;
-#endif
if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
bool ok = checkCallingPermission(String16(permissionString));
if (!ok) ALOGE("Request requires %s", permissionString);
@@ -519,24 +516,6 @@
return mPlugin->provideProvisionResponse(response, certificate, wrappedKey);
}
-status_t Drm::unprovisionDevice() {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- if (mPlugin == NULL) {
- return -EINVAL;
- }
-
- if (!checkPermission("android.permission.REMOVE_DRM_CERTIFICATES")) {
- return -EPERM;
- }
-
- return mPlugin->unprovisionDevice();
-}
-
status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
Mutex::Autolock autoLock(mLock);
diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h
index 056723c..d40019b 100644
--- a/media/libmediaplayerservice/Drm.h
+++ b/media/libmediaplayerservice/Drm.h
@@ -77,8 +77,6 @@
Vector<uint8_t> &certificate,
Vector<uint8_t> &wrappedKey);
- virtual status_t unprovisionDevice();
-
virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index d5d12f7..605c710 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -31,7 +31,6 @@
#include "MediaPlayerFactory.h"
#include "TestPlayerStub.h"
-#include "StagefrightPlayer.h"
#include "nuplayer/NuPlayerDriver.h"
namespace android {
@@ -64,12 +63,6 @@
}
static player_type getDefaultPlayerType() {
- char value[PROPERTY_VALUE_MAX];
- if (property_get("media.stagefright.use-awesome", value, NULL)
- && (!strcmp("1", value) || !strcasecmp("true", value))) {
- return STAGEFRIGHT_PLAYER;
- }
-
return NU_PLAYER;
}
@@ -176,63 +169,6 @@
* *
*****************************************************************************/
-class StagefrightPlayerFactory :
- public MediaPlayerFactory::IFactory {
- public:
- virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
- int fd,
- int64_t offset,
- int64_t length,
- float /*curScore*/) {
- if (legacyDrm()) {
- sp<DataSource> source = new FileSource(dup(fd), offset, length);
- String8 mimeType;
- float confidence;
- if (SniffWVM(source, &mimeType, &confidence, NULL /* format */)) {
- return 1.0;
- }
- }
-
- if (getDefaultPlayerType() == STAGEFRIGHT_PLAYER) {
- char buf[20];
- lseek(fd, offset, SEEK_SET);
- read(fd, buf, sizeof(buf));
- lseek(fd, offset, SEEK_SET);
-
- uint32_t ident = *((uint32_t*)buf);
-
- // Ogg vorbis?
- if (ident == 0x5367674f) // 'OggS'
- return 1.0;
- }
-
- return 0.0;
- }
-
- virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
- const char* url,
- float /*curScore*/) {
- if (legacyDrm() && !strncasecmp("widevine://", url, 11)) {
- return 1.0;
- }
- return 0.0;
- }
-
- virtual sp<MediaPlayerBase> createPlayer(pid_t /* pid */) {
- ALOGV(" create StagefrightPlayer");
- return new StagefrightPlayer();
- }
- private:
- bool legacyDrm() {
- char value[PROPERTY_VALUE_MAX];
- if (property_get("persist.sys.media.legacy-drm", value, NULL)
- && (!strcmp("1", value) || !strcasecmp("true", value))) {
- return true;
- }
- return false;
- }
-};
-
class NuPlayerFactory : public MediaPlayerFactory::IFactory {
public:
virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
@@ -310,7 +246,6 @@
if (sInitComplete)
return;
- registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index f0baf69..bb24403 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -57,7 +57,7 @@
#include <media/MemoryLeakTrackUtil.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/Utils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooperRoster.h>
#include <mediautils/BatteryNotifier.h>
@@ -73,7 +73,6 @@
#include "MediaPlayerFactory.h"
#include "TestPlayerStub.h"
-#include "StagefrightPlayer.h"
#include "nuplayer/NuPlayerDriver.h"
#include <OMX.h>
@@ -253,9 +252,6 @@
static bool checkPermission(const char* permissionString) {
-#ifndef HAVE_ANDROID_OS
- return true;
-#endif
if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
bool ok = checkCallingPermission(String16(permissionString));
if (!ok) ALOGE("Request requires %s", permissionString);
@@ -288,9 +284,7 @@
// reset battery stats
// if the mediaserver has crashed, battery stats could be left
// in bad state, reset the state upon service start.
- BatteryNotifier& notifier(BatteryNotifier::getInstance());
- notifier.noteResetVideo();
- notifier.noteResetAudio();
+ BatteryNotifier::getInstance().noteResetVideo();
MediaPlayerFactory::registerBuiltinFactories();
}
@@ -352,6 +346,7 @@
}
sp<IOMX> MediaPlayerService::getOMX() {
+ ALOGI("MediaPlayerService::getOMX");
Mutex::Autolock autoLock(mLock);
if (mOMX.get() == NULL) {
@@ -733,7 +728,8 @@
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
- ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
+ ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
+ fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
struct stat sb;
int ret = fstat(fd, &sb);
if (ret != 0) {
@@ -749,7 +745,6 @@
if (offset >= sb.st_size) {
ALOGE("offset error");
- ::close(fd);
return UNKNOWN_ERROR;
}
if (offset + length > sb.st_size) {
@@ -1250,7 +1245,10 @@
if (client->mAudioOutput != NULL)
client->mAudioOutput->switchToNextOutput();
client->mNextClient->start();
- client->mNextClient->mClient->notify(MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
+ if (client->mNextClient->mClient != NULL) {
+ client->mNextClient->mClient->notify(
+ MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
+ }
}
}
@@ -1454,6 +1452,76 @@
return mTrack->getTimestamp(ts);
}
+// TODO: Remove unnecessary calls to getPlayedOutDurationUs()
+// as it acquires locks and may query the audio driver.
+//
+// Some calls could conceivably retrieve extrapolated data instead of
+// accessing getTimestamp() or getPosition() every time a data buffer with
+// a media time is received.
+//
+// Calculate duration of played samples if played at normal rate (i.e., 1.0).
+int64_t MediaPlayerService::AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const
+{
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0 || mSampleRateHz == 0) {
+ return 0;
+ }
+
+ uint32_t numFramesPlayed;
+ int64_t numFramesPlayedAt;
+ AudioTimestamp ts;
+ static const int64_t kStaleTimestamp100ms = 100000;
+
+ status_t res = mTrack->getTimestamp(ts);
+ if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
+ numFramesPlayed = ts.mPosition;
+ numFramesPlayedAt = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
+ const int64_t timestampAge = nowUs - numFramesPlayedAt;
+ if (timestampAge > kStaleTimestamp100ms) {
+ // This is an audio FIXME.
+ // getTimestamp returns a timestamp which may come from audio mixing threads.
+ // After pausing, the MixerThread may go idle, thus the mTime estimate may
+ // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms,
+ // the max latency should be about 25ms with an average around 12ms (to be verified).
+ // For safety we use 100ms.
+ ALOGV("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)",
+ (long long)nowUs, (long long)numFramesPlayedAt);
+ numFramesPlayedAt = nowUs - kStaleTimestamp100ms;
+ }
+ //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAt);
+ } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
+ numFramesPlayed = 0;
+ numFramesPlayedAt = nowUs;
+ //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
+ // numFramesPlayed, (long long)numFramesPlayedAt);
+ } else { // case 3: transitory at new track or audio fast tracks.
+ res = mTrack->getPosition(&numFramesPlayed);
+ CHECK_EQ(res, (status_t)OK);
+ numFramesPlayedAt = nowUs;
+ numFramesPlayedAt += 1000LL * mTrack->latency() / 2; /* XXX */
+ //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAt);
+ }
+
+ // CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
+ // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
+ int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000000LL / mSampleRateHz)
+ + nowUs - numFramesPlayedAt;
+ if (durationUs < 0) {
+ // Occurs when numFramesPlayed position is very small and the following:
+ // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
+ // numFramesPlayedAt is greater than nowUs by time more than numFramesPlayed.
+ // (2) In case 3, using getPosition and adding mAudioSink->latency() to
+ // numFramesPlayedAt, by a time amount greater than numFramesPlayed.
+ //
+ // Both of these are transitory conditions.
+ ALOGV("getPlayedOutDurationUs: negative duration %lld set to zero", (long long)durationUs);
+ durationUs = 0;
+ }
+ ALOGV("getPlayedOutDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
+ (long long)durationUs, (long long)nowUs, numFramesPlayed, (long long)numFramesPlayedAt);
+ return durationUs;
+}
+
status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const
{
Mutex::Autolock lock(mLock);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 60d4617..bd98ef1 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -88,6 +88,7 @@
virtual float msecsPerFrame() const;
virtual status_t getPosition(uint32_t *position) const;
virtual status_t getTimestamp(AudioTimestamp &ts) const;
+ virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const;
virtual status_t getFramesWritten(uint32_t *frameswritten) const;
virtual int getSessionId() const;
virtual uint32_t getSampleRate() const;
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index f761dec..3b4e148 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -46,9 +46,6 @@
const char* recordAudioPermission = "android.permission.RECORD_AUDIO";
static bool checkPermission(const char* permissionString) {
-#ifndef HAVE_ANDROID_OS
- return true;
-#endif
if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
bool ok = checkCallingPermission(String16(permissionString));
if (!ok) ALOGE("Request requires %s", permissionString);
@@ -253,6 +250,29 @@
return mRecorder->stop();
}
+status_t MediaRecorderClient::pause()
+{
+ ALOGV("pause");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ ALOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->pause();
+
+}
+
+status_t MediaRecorderClient::resume()
+{
+ ALOGV("resume");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ ALOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->resume();
+}
+
status_t MediaRecorderClient::init()
{
ALOGV("init");
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 05130d4..c0d9c4c 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -51,6 +51,8 @@
virtual status_t start();
virtual status_t stop();
virtual status_t reset();
+ virtual status_t pause();
+ virtual status_t resume();
virtual status_t init();
virtual status_t close();
virtual status_t release();
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index a5a1fa5..b5e5225 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -35,6 +35,7 @@
#include <media/MediaMetadataRetrieverInterface.h>
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/DataSource.h>
+#include <media/stagefright/Utils.h>
#include <private/media/VideoFrame.h>
#include "MetadataRetrieverClient.h"
#include "StagefrightMetadataRetriever.h"
@@ -133,7 +134,8 @@
status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
{
- ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
+ ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
+ fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
Mutex::Autolock lock(mLock);
struct stat sb;
int ret = fstat(fd, &sb);
@@ -149,7 +151,6 @@
if (offset >= sb.st_size) {
ALOGE("offset (%lld) bigger than file size (%llu)", offset, sb.st_size);
- ::close(fd);
return BAD_VALUE;
}
if (offset + length > sb.st_size) {
@@ -165,12 +166,10 @@
ALOGV("player type = %d", playerType);
sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
if (p == NULL) {
- ::close(fd);
return NO_INIT;
}
status_t status = p->setDataSource(fd, offset, length);
if (status == NO_ERROR) mRetriever = p;
- ::close(fd);
return status;
}
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
deleted file mode 100644
index 3fedd9b..0000000
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "StagefrightPlayer"
-#include <utils/Log.h>
-
-#include "StagefrightPlayer.h"
-
-#include "AwesomePlayer.h"
-
-#include <media/Metadata.h>
-#include <media/stagefright/MediaExtractor.h>
-
-namespace android {
-
-StagefrightPlayer::StagefrightPlayer()
- : mPlayer(new AwesomePlayer) {
- ALOGV("StagefrightPlayer");
-
- mPlayer->setListener(this);
-}
-
-StagefrightPlayer::~StagefrightPlayer() {
- ALOGV("~StagefrightPlayer");
- reset();
-
- delete mPlayer;
- mPlayer = NULL;
-}
-
-status_t StagefrightPlayer::initCheck() {
- ALOGV("initCheck");
- return OK;
-}
-
-status_t StagefrightPlayer::setUID(uid_t uid) {
- mPlayer->setUID(uid);
-
- return OK;
-}
-
-status_t StagefrightPlayer::setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers) {
- return mPlayer->setDataSource(httpService, url, headers);
-}
-
-// Warning: The filedescriptor passed into this method will only be valid until
-// the method returns, if you want to keep it, dup it!
-status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
- ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
- return mPlayer->setDataSource(dup(fd), offset, length);
-}
-
-status_t StagefrightPlayer::setDataSource(const sp<IStreamSource> &source) {
- return mPlayer->setDataSource(source);
-}
-
-status_t StagefrightPlayer::setVideoSurfaceTexture(
- const sp<IGraphicBufferProducer> &bufferProducer) {
- ALOGV("setVideoSurfaceTexture");
-
- return mPlayer->setSurfaceTexture(bufferProducer);
-}
-
-status_t StagefrightPlayer::prepare() {
- return mPlayer->prepare();
-}
-
-status_t StagefrightPlayer::prepareAsync() {
- return mPlayer->prepareAsync();
-}
-
-status_t StagefrightPlayer::start() {
- ALOGV("start");
-
- return mPlayer->play();
-}
-
-status_t StagefrightPlayer::stop() {
- ALOGV("stop");
-
- return pause(); // what's the difference?
-}
-
-status_t StagefrightPlayer::pause() {
- ALOGV("pause");
-
- return mPlayer->pause();
-}
-
-bool StagefrightPlayer::isPlaying() {
- ALOGV("isPlaying");
- return mPlayer->isPlaying();
-}
-
-status_t StagefrightPlayer::seekTo(int msec) {
- ALOGV("seekTo %.2f secs", msec / 1E3);
-
- status_t err = mPlayer->seekTo((int64_t)msec * 1000);
-
- return err;
-}
-
-status_t StagefrightPlayer::getCurrentPosition(int *msec) {
- ALOGV("getCurrentPosition");
-
- int64_t positionUs;
- status_t err = mPlayer->getPosition(&positionUs);
-
- if (err != OK) {
- return err;
- }
-
- *msec = (positionUs + 500) / 1000;
-
- return OK;
-}
-
-status_t StagefrightPlayer::getDuration(int *msec) {
- ALOGV("getDuration");
-
- int64_t durationUs;
- status_t err = mPlayer->getDuration(&durationUs);
-
- if (err != OK) {
- *msec = 0;
- return OK;
- }
-
- *msec = (durationUs + 500) / 1000;
-
- return OK;
-}
-
-status_t StagefrightPlayer::reset() {
- ALOGV("reset");
-
- mPlayer->reset();
-
- return OK;
-}
-
-status_t StagefrightPlayer::setLooping(int loop) {
- ALOGV("setLooping");
-
- return mPlayer->setLooping(loop);
-}
-
-player_type StagefrightPlayer::playerType() {
- ALOGV("playerType");
- return STAGEFRIGHT_PLAYER;
-}
-
-status_t StagefrightPlayer::invoke(const Parcel &request, Parcel *reply) {
- ALOGV("invoke()");
- return mPlayer->invoke(request, reply);
-}
-
-void StagefrightPlayer::setAudioSink(const sp<AudioSink> &audioSink) {
- MediaPlayerInterface::setAudioSink(audioSink);
-
- mPlayer->setAudioSink(audioSink);
-}
-
-status_t StagefrightPlayer::setParameter(int key, const Parcel &request) {
- ALOGV("setParameter(key=%d)", key);
- return mPlayer->setParameter(key, request);
-}
-
-status_t StagefrightPlayer::getParameter(int key, Parcel *reply) {
- ALOGV("getParameter");
- return mPlayer->getParameter(key, reply);
-}
-
-status_t StagefrightPlayer::setPlaybackSettings(const AudioPlaybackRate &rate) {
- return mPlayer->setPlaybackSettings(rate);
-}
-
-status_t StagefrightPlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- return mPlayer->getPlaybackSettings(rate);
-}
-
-status_t StagefrightPlayer::getMetadata(
- const media::Metadata::Filter& /* ids */, Parcel *records) {
- using media::Metadata;
-
- uint32_t flags = mPlayer->flags();
-
- Metadata metadata(records);
-
- metadata.appendBool(
- Metadata::kPauseAvailable,
- flags & MediaExtractor::CAN_PAUSE);
-
- metadata.appendBool(
- Metadata::kSeekBackwardAvailable,
- flags & MediaExtractor::CAN_SEEK_BACKWARD);
-
- metadata.appendBool(
- Metadata::kSeekForwardAvailable,
- flags & MediaExtractor::CAN_SEEK_FORWARD);
-
- metadata.appendBool(
- Metadata::kSeekAvailable,
- flags & MediaExtractor::CAN_SEEK);
-
- return OK;
-}
-
-status_t StagefrightPlayer::dump(int fd, const Vector<String16> &args) const {
- return mPlayer->dump(fd, args);
-}
-
-} // namespace android
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
deleted file mode 100644
index 96013df..0000000
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-**
-** Copyright 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_STAGEFRIGHTPLAYER_H
-#define ANDROID_STAGEFRIGHTPLAYER_H
-
-#include <media/MediaPlayerInterface.h>
-
-namespace android {
-
-struct AwesomePlayer;
-
-class StagefrightPlayer : public MediaPlayerInterface {
-public:
- StagefrightPlayer();
- virtual ~StagefrightPlayer();
-
- virtual status_t initCheck();
-
- virtual status_t setUID(uid_t uid);
-
- virtual status_t setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers);
-
- virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
-
- virtual status_t setDataSource(const sp<IStreamSource> &source);
-
- virtual status_t setVideoSurfaceTexture(
- const sp<IGraphicBufferProducer> &bufferProducer);
- virtual status_t prepare();
- virtual status_t prepareAsync();
- virtual status_t start();
- virtual status_t stop();
- virtual status_t pause();
- virtual bool isPlaying();
- virtual status_t seekTo(int msec);
- virtual status_t getCurrentPosition(int *msec);
- virtual status_t getDuration(int *msec);
- virtual status_t reset();
- virtual status_t setLooping(int loop);
- virtual player_type playerType();
- virtual status_t invoke(const Parcel &request, Parcel *reply);
- virtual void setAudioSink(const sp<AudioSink> &audioSink);
- virtual status_t setParameter(int key, const Parcel &request);
- virtual status_t getParameter(int key, Parcel *reply);
- virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate);
- virtual status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
-
- virtual status_t getMetadata(
- const media::Metadata::Filter& ids, Parcel *records);
-
- virtual status_t dump(int fd, const Vector<String16> &args) const;
-
-private:
- AwesomePlayer *mPlayer;
-
- StagefrightPlayer(const StagefrightPlayer &);
- StagefrightPlayer &operator=(const StagefrightPlayer &);
-};
-
-} // namespace android
-
-#endif // ANDROID_STAGEFRIGHTPLAYER_H
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index e521fae..b335d09 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -41,8 +41,6 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaCodecSource.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
#include <media/MediaProfiles.h>
#include <camera/ICamera.h>
#include <camera/CameraParameters.h>
@@ -782,8 +780,9 @@
return INVALID_OPERATION;
}
- // Get UID here for permission checking
+ // Get UID and PID here for permission checking
mClientUid = IPCThreadState::self()->getCallingUid();
+ mClientPid = IPCThreadState::self()->getCallingPid();
status_t status = OK;
@@ -907,7 +906,7 @@
return status;
}
-sp<MediaSource> StagefrightRecorder::createAudioSource() {
+sp<MediaCodecSource> StagefrightRecorder::createAudioSource() {
int32_t sourceSampleRate = mSampleRate;
if (mCaptureFpsEnable && mCaptureFps >= mFrameRate) {
@@ -982,7 +981,7 @@
}
format->setInt32("priority", 0 /* realtime */);
- sp<MediaSource> audioEncoder =
+ sp<MediaCodecSource> audioEncoder =
MediaCodecSource::Create(mLooper, format, audioSource);
mAudioSourceNode = audioSource;
@@ -1041,13 +1040,14 @@
return status;
}
- sp<MediaSource> audioEncoder = createAudioSource();
+ sp<MediaCodecSource> audioEncoder = createAudioSource();
if (audioEncoder == NULL) {
return UNKNOWN_ERROR;
}
CHECK(mWriter != 0);
mWriter->addSource(audioEncoder);
+ mAudioEncoderSource = audioEncoder;
if (mMaxFileDurationUs != 0) {
mWriter->setMaxFileDuration(mMaxFileDurationUs);
@@ -1075,10 +1075,11 @@
return BAD_VALUE;
}
- sp<MediaSource> source;
+ sp<MediaCodecSource> source;
if (mAudioSource != AUDIO_SOURCE_CNT) {
source = createAudioSource();
+ mAudioEncoderSource = source;
} else {
setDefaultVideoEncoderIfNecessary();
@@ -1092,6 +1093,7 @@
if (err != OK) {
return err;
}
+ mVideoEncoderSource = source;
}
mWriter = new ARTPWriter(mOutputFd);
@@ -1132,7 +1134,7 @@
return err;
}
- sp<MediaSource> encoder;
+ sp<MediaCodecSource> encoder;
err = setupVideoEncoder(mediaSource, &encoder);
if (err != OK) {
@@ -1140,6 +1142,7 @@
}
writer->addSource(encoder);
+ mVideoEncoderSource = encoder;
}
if (mMaxFileDurationUs != 0) {
@@ -1213,18 +1216,6 @@
}
status_t StagefrightRecorder::checkVideoEncoderCapabilities() {
- /* hardware codecs must support camera source meta data mode */
- Vector<CodecCapabilities> codecs;
- OMXClient client;
- CHECK_EQ(client.connect(), (status_t)OK);
- QueryCodecs(
- client.interface(),
- (mVideoEncoder == VIDEO_ENCODER_H263 ? MEDIA_MIMETYPE_VIDEO_H263 :
- mVideoEncoder == VIDEO_ENCODER_MPEG_4_SP ? MEDIA_MIMETYPE_VIDEO_MPEG4 :
- mVideoEncoder == VIDEO_ENCODER_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8 :
- mVideoEncoder == VIDEO_ENCODER_H264 ? MEDIA_MIMETYPE_VIDEO_AVC : ""),
- false /* decoder */, true /* hwCodec */, &codecs);
-
if (!mCaptureFpsEnable) {
// Dont clip for time lapse capture as encoder will have enough
// time to encode because of slow capture rate of time lapse.
@@ -1446,13 +1437,13 @@
}
mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
- mCamera, mCameraProxy, mCameraId, mClientName, mClientUid,
+ mCamera, mCameraProxy, mCameraId, mClientName, mClientUid, mClientPid,
videoSize, mFrameRate, mPreviewSurface,
mTimeBetweenCaptureUs);
*cameraSource = mCameraSourceTimeLapse;
} else {
*cameraSource = CameraSource::CreateFromCamera(
- mCamera, mCameraProxy, mCameraId, mClientName, mClientUid,
+ mCamera, mCameraProxy, mCameraId, mClientName, mClientUid, mClientPid,
videoSize, mFrameRate,
mPreviewSurface);
}
@@ -1489,7 +1480,7 @@
status_t StagefrightRecorder::setupVideoEncoder(
sp<MediaSource> cameraSource,
- sp<MediaSource> *source) {
+ sp<MediaCodecSource> *source) {
source->clear();
sp<AMessage> format = new AMessage();
@@ -1511,6 +1502,10 @@
format->setString("mime", MEDIA_MIMETYPE_VIDEO_VP8);
break;
+ case VIDEO_ENCODER_HEVC:
+ format->setString("mime", MEDIA_MIMETYPE_VIDEO_HEVC);
+ break;
+
default:
CHECK(!"Should not be here, unsupported video encoding.");
break;
@@ -1535,7 +1530,7 @@
format->setInt32("width", mVideoWidth);
format->setInt32("height", mVideoHeight);
format->setInt32("stride", mVideoWidth);
- format->setInt32("slice-height", mVideoWidth);
+ format->setInt32("slice-height", mVideoHeight);
format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
// set up time lapse/slow motion for surface source
@@ -1618,12 +1613,13 @@
return UNKNOWN_ERROR;
}
- sp<MediaSource> audioEncoder = createAudioSource();
+ sp<MediaCodecSource> audioEncoder = createAudioSource();
if (audioEncoder == NULL) {
return UNKNOWN_ERROR;
}
writer->addSource(audioEncoder);
+ mAudioEncoderSource = audioEncoder;
return OK;
}
@@ -1649,13 +1645,14 @@
return err;
}
- sp<MediaSource> encoder;
+ sp<MediaCodecSource> encoder;
err = setupVideoEncoder(mediaSource, &encoder);
if (err != OK) {
return err;
}
writer->addSource(encoder);
+ mVideoEncoderSource = encoder;
mTotalBitRate += mVideoBitRate;
}
@@ -1726,25 +1723,49 @@
status_t StagefrightRecorder::pause() {
ALOGV("pause");
- if (mWriter == NULL) {
- return UNKNOWN_ERROR;
- }
- mWriter->pause();
-
- if (mStarted) {
- mStarted = false;
-
- uint32_t params = 0;
- if (mAudioSource != AUDIO_SOURCE_CNT) {
- params |= IMediaPlayerService::kBatteryDataTrackAudio;
- }
- if (mVideoSource != VIDEO_SOURCE_LIST_END) {
- params |= IMediaPlayerService::kBatteryDataTrackVideo;
- }
-
- addBatteryData(params);
+ if (!mStarted) {
+ return INVALID_OPERATION;
}
+ // Already paused --- no-op.
+ if (mPauseStartTimeUs != 0) {
+ return OK;
+ }
+
+ if (mAudioEncoderSource != NULL) {
+ mAudioEncoderSource->pause();
+ }
+ if (mVideoEncoderSource != NULL) {
+ mVideoEncoderSource->pause();
+ }
+
+ mPauseStartTimeUs = systemTime() / 1000;
+
+ return OK;
+}
+
+status_t StagefrightRecorder::resume() {
+ ALOGV("resume");
+ if (!mStarted) {
+ return INVALID_OPERATION;
+ }
+
+ // Not paused --- no-op.
+ if (mPauseStartTimeUs == 0) {
+ return OK;
+ }
+
+ // 30 ms buffer to avoid timestamp overlap
+ mTotalPausedDurationUs += (systemTime() / 1000) - mPauseStartTimeUs - 30000;
+ if (mAudioEncoderSource != NULL) {
+ mAudioEncoderSource->setInputBufferTimeOffset(-mTotalPausedDurationUs);
+ mAudioEncoderSource->start();
+ }
+ if (mVideoEncoderSource != NULL) {
+ mVideoEncoderSource->setInputBufferTimeOffset(-mTotalPausedDurationUs);
+ mVideoEncoderSource->start();
+ }
+ mPauseStartTimeUs = 0;
return OK;
}
@@ -1762,9 +1783,12 @@
err = mWriter->stop();
mWriter.clear();
}
+ mTotalPausedDurationUs = 0;
mGraphicBufferProducer.clear();
mPersistentSurface.clear();
+ mAudioEncoderSource.clear();
+ mVideoEncoderSource.clear();
if (mOutputFd >= 0) {
::close(mOutputFd);
@@ -1840,6 +1864,7 @@
mTotalBitRate = 0;
mOutputFd = -1;
+ mPauseStartTimeUs = 0;
return OK;
}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index da00bc7..761e987 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -30,6 +30,7 @@
class ICameraRecordingProxy;
class CameraSource;
class CameraSourceTimeLapse;
+struct MediaCodecSource;
struct MediaSource;
struct MediaWriter;
class MetaData;
@@ -62,6 +63,7 @@
virtual status_t prepare();
virtual status_t start();
virtual status_t pause();
+ virtual status_t resume();
virtual status_t stop();
virtual status_t close();
virtual status_t reset();
@@ -78,6 +80,7 @@
sp<IMediaRecorderClient> mListener;
String16 mClientName;
uid_t mClientUid;
+ pid_t mClientPid;
sp<MediaWriter> mWriter;
int mOutputFd;
sp<AudioSource> mAudioSourceNode;
@@ -121,6 +124,11 @@
bool mIsMetaDataStoredInVideoBuffers;
MediaProfiles *mEncoderProfiles;
+ int64_t mPauseStartTimeUs;
+ int64_t mTotalPausedDurationUs;
+ sp<MediaCodecSource> mAudioEncoderSource;
+ sp<MediaCodecSource> mVideoEncoderSource;
+
bool mStarted;
// Needed when GLFrames are encoded.
// An <IGraphicBufferProducer> pointer
@@ -139,7 +147,7 @@
status_t setupRawAudioRecording();
status_t setupRTPRecording();
status_t setupMPEG2TSRecording();
- sp<MediaSource> createAudioSource();
+ sp<MediaCodecSource> createAudioSource();
status_t checkVideoEncoderCapabilities();
status_t checkAudioEncoderCapabilities();
// Generic MediaSource set-up. Returns the appropriate
@@ -148,7 +156,7 @@
status_t setupMediaSource(sp<MediaSource> *mediaSource);
status_t setupCameraSource(sp<CameraSource> *cameraSource);
status_t setupAudioEncoder(const sp<MediaWriter>& writer);
- status_t setupVideoEncoder(sp<MediaSource> cameraSource, sp<MediaSource> *source);
+ status_t setupVideoEncoder(sp<MediaSource> cameraSource, sp<MediaCodecSource> *source);
// Encoding parameter handling utilities
status_t setParameter(const String8 &key, const String8 &value);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 45da218..baa95fa 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -42,6 +42,7 @@
static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
static int64_t kHighWaterMarkUs = 5000000ll; // 5secs
+static int64_t kHighWaterMarkRebufferUs = 15000000ll; // 15secs
static const ssize_t kLowWaterMarkBytes = 40000;
static const ssize_t kHighWaterMarkBytes = 200000;
@@ -66,11 +67,8 @@
mFd(-1),
mDrmManagerClient(NULL),
mBitrate(-1ll),
- mPollBufferingGeneration(0),
- mPendingReadBufferTypes(0),
- mBuffering(false),
- mPrepareBuffering(false),
- mPrevBufferPercentage(-1) {
+ mPendingReadBufferTypes(0) {
+ mBufferingMonitor = new BufferingMonitor(notify);
resetDataSource();
DataSource::RegisterDefaultSniffers();
}
@@ -91,6 +89,13 @@
mDrmManagerClient = NULL;
mStarted = false;
mStopRead = true;
+
+ if (mBufferingMonitorLooper != NULL) {
+ mBufferingMonitorLooper->unregisterHandler(mBufferingMonitor->id());
+ mBufferingMonitorLooper->stop();
+ mBufferingMonitorLooper = NULL;
+ }
+ mBufferingMonitor->stop();
}
status_t NuPlayer::GenericSource::setDataSource(
@@ -135,7 +140,7 @@
}
status_t NuPlayer::GenericSource::initFromDataSource() {
- sp<MediaExtractor> extractor;
+ sp<IMediaExtractor> extractor;
String8 mimeType;
float confidence;
sp<AMessage> dummy;
@@ -210,9 +215,16 @@
}
for (size_t i = 0; i < numtracks; ++i) {
- sp<MediaSource> track = extractor->getTrack(i);
+ sp<IMediaSource> track = extractor->getTrack(i);
+ if (track == NULL) {
+ continue;
+ }
sp<MetaData> meta = extractor->getTrackMetaData(i);
+ if (meta == NULL) {
+ ALOGE("no metadata for track %zu", i);
+ return UNKNOWN_ERROR;
+ }
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -253,22 +265,25 @@
}
}
- if (track != NULL) {
- mSources.push(track);
- int64_t durationUs;
- if (meta->findInt64(kKeyDuration, &durationUs)) {
- if (durationUs > mDurationUs) {
- mDurationUs = durationUs;
- }
- }
-
- int32_t bitrate;
- if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
- totalBitrate += bitrate;
- } else {
- totalBitrate = -1;
+ mSources.push(track);
+ int64_t durationUs;
+ if (meta->findInt64(kKeyDuration, &durationUs)) {
+ if (durationUs > mDurationUs) {
+ mDurationUs = durationUs;
}
}
+
+ int32_t bitrate;
+ if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
+ totalBitrate += bitrate;
+ } else {
+ totalBitrate = -1;
+ }
+ }
+
+ if (mSources.size() == 0) {
+ ALOGE("b/23705695");
+ return UNKNOWN_ERROR;
}
mBitrate = totalBitrate;
@@ -318,7 +333,7 @@
status_t NuPlayer::GenericSource::setBuffers(
bool audio, Vector<MediaBuffer *> &buffers) {
- if (mIsSecure && !audio) {
+ if (mIsSecure && !audio && mVideoTrack.mSource != NULL) {
return mVideoTrack.mSource->setBuffers(buffers);
}
return INVALID_OPERATION;
@@ -328,6 +343,10 @@
return mIsStreaming;
}
+void NuPlayer::GenericSource::setOffloadAudio(bool offload) {
+ mBufferingMonitor->setOffloadAudio(offload);
+}
+
NuPlayer::GenericSource::~GenericSource() {
if (mLooper != NULL) {
mLooper->unregisterHandler(id());
@@ -456,10 +475,18 @@
}
if (mIsStreaming) {
- mPrepareBuffering = true;
+ if (mBufferingMonitorLooper == NULL) {
+ mBufferingMonitor->prepare(mCachedSource, mWVMExtractor, mDurationUs, mBitrate,
+ mIsStreaming);
- ensureCacheIsFetching();
- restartPollBuffering();
+ mBufferingMonitorLooper = new ALooper;
+ mBufferingMonitorLooper->setName("GSBMonitor");
+ mBufferingMonitorLooper->start();
+ mBufferingMonitorLooper->registerHandler(mBufferingMonitor);
+ }
+
+ mBufferingMonitor->ensureCacheIsFetching();
+ mBufferingMonitor->restartPollBuffering();
} else {
notifyPrepared();
}
@@ -482,7 +509,7 @@
}
mBitrate = -1;
- cancelPollBuffering();
+ mBufferingMonitor->cancelPollBuffering();
}
notifyPrepared(err);
}
@@ -561,182 +588,6 @@
return OK;
}
-void NuPlayer::GenericSource::schedulePollBuffering() {
- sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
- msg->setInt32("generation", mPollBufferingGeneration);
- msg->post(1000000ll);
-}
-
-void NuPlayer::GenericSource::cancelPollBuffering() {
- mBuffering = false;
- ++mPollBufferingGeneration;
- mPrevBufferPercentage = -1;
-}
-
-void NuPlayer::GenericSource::restartPollBuffering() {
- if (mIsStreaming) {
- cancelPollBuffering();
- onPollBuffering();
- }
-}
-
-void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) {
- // Buffering percent could go backward as it's estimated from remaining
- // data and last access time. This could cause the buffering position
- // drawn on media control to jitter slightly. Remember previously reported
- // percentage and don't allow it to go backward.
- if (percentage < mPrevBufferPercentage) {
- percentage = mPrevBufferPercentage;
- } else if (percentage > 100) {
- percentage = 100;
- }
-
- mPrevBufferPercentage = percentage;
-
- ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
-
- sp<AMessage> msg = dupNotify();
- msg->setInt32("what", kWhatBufferingUpdate);
- msg->setInt32("percentage", percentage);
- msg->post();
-}
-
-void NuPlayer::GenericSource::startBufferingIfNecessary() {
- ALOGV("startBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
- mPrepareBuffering, mBuffering);
-
- if (mPrepareBuffering) {
- return;
- }
-
- if (!mBuffering) {
- mBuffering = true;
-
- ensureCacheIsFetching();
- sendCacheStats();
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatPauseOnBufferingStart);
- notify->post();
- }
-}
-
-void NuPlayer::GenericSource::stopBufferingIfNecessary() {
- ALOGV("stopBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
- mPrepareBuffering, mBuffering);
-
- if (mPrepareBuffering) {
- mPrepareBuffering = false;
- notifyPrepared();
- return;
- }
-
- if (mBuffering) {
- mBuffering = false;
-
- sendCacheStats();
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatResumeOnBufferingEnd);
- notify->post();
- }
-}
-
-void NuPlayer::GenericSource::sendCacheStats() {
- int32_t kbps = 0;
- status_t err = UNKNOWN_ERROR;
-
- if (mWVMExtractor != NULL) {
- err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
- } else if (mCachedSource != NULL) {
- err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
- }
-
- if (err == OK) {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatCacheStats);
- notify->setInt32("bandwidth", kbps);
- notify->post();
- }
-}
-
-void NuPlayer::GenericSource::ensureCacheIsFetching() {
- if (mCachedSource != NULL) {
- mCachedSource->resumeFetchingIfNecessary();
- }
-}
-
-void NuPlayer::GenericSource::onPollBuffering() {
- status_t finalStatus = UNKNOWN_ERROR;
- int64_t cachedDurationUs = -1ll;
- ssize_t cachedDataRemaining = -1;
-
- ALOGW_IF(mWVMExtractor != NULL && mCachedSource != NULL,
- "WVMExtractor and NuCachedSource both present");
-
- if (mWVMExtractor != NULL) {
- cachedDurationUs =
- mWVMExtractor->getCachedDurationUs(&finalStatus);
- } else if (mCachedSource != NULL) {
- cachedDataRemaining =
- mCachedSource->approxDataRemaining(&finalStatus);
-
- if (finalStatus == OK) {
- off64_t size;
- int64_t bitrate = 0ll;
- if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
- bitrate = size * 8000000ll / mDurationUs;
- } else if (mBitrate > 0) {
- bitrate = mBitrate;
- }
- if (bitrate > 0) {
- cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
- }
- }
- }
-
- if (finalStatus != OK) {
- ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
-
- if (finalStatus == ERROR_END_OF_STREAM) {
- notifyBufferingUpdate(100);
- }
-
- stopBufferingIfNecessary();
- return;
- } else if (cachedDurationUs >= 0ll) {
- if (mDurationUs > 0ll) {
- int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
- int percentage = 100.0 * cachedPosUs / mDurationUs;
- if (percentage > 100) {
- percentage = 100;
- }
-
- notifyBufferingUpdate(percentage);
- }
-
- ALOGV("onPollBuffering: cachedDurationUs %.1f sec",
- cachedDurationUs / 1000000.0f);
-
- if (cachedDurationUs < kLowWaterMarkUs) {
- startBufferingIfNecessary();
- } else if (cachedDurationUs > kHighWaterMarkUs) {
- stopBufferingIfNecessary();
- }
- } else if (cachedDataRemaining >= 0) {
- ALOGV("onPollBuffering: cachedDataRemaining %zd bytes",
- cachedDataRemaining);
-
- if (cachedDataRemaining < kLowWaterMarkBytes) {
- startBufferingIfNecessary();
- } else if (cachedDataRemaining > kHighWaterMarkBytes) {
- stopBufferingIfNecessary();
- }
- }
-
- schedulePollBuffering();
-}
-
void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatPrepareAsync:
@@ -765,6 +616,11 @@
break;
}
+ case kWhatSendGlobalTimedTextData:
+ {
+ sendGlobalTextData(kWhatTimedTextData, mFetchTimedTextDataGeneration, msg);
+ break;
+ }
case kWhatSendTimedTextData:
{
sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
@@ -776,7 +632,7 @@
{
int32_t trackIndex;
CHECK(msg->findInt32("trackIndex", &trackIndex));
- const sp<MediaSource> source = mSources.itemAt(trackIndex);
+ const sp<IMediaSource> source = mSources.itemAt(trackIndex);
Track* track;
const char *mime;
@@ -819,17 +675,7 @@
case kWhatStart:
case kWhatResume:
{
- restartPollBuffering();
- break;
- }
-
- case kWhatPollBuffering:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- if (generation == mPollBufferingGeneration) {
- onPollBuffering();
- }
+ mBufferingMonitor->restartPollBuffering();
break;
}
@@ -959,16 +805,47 @@
}
}
+void NuPlayer::GenericSource::sendGlobalTextData(
+ uint32_t what,
+ int32_t curGen,
+ sp<AMessage> msg) {
+ int32_t msgGeneration;
+ CHECK(msg->findInt32("generation", &msgGeneration));
+ if (msgGeneration != curGen) {
+ // stale
+ return;
+ }
+
+ uint32_t textType;
+ const void *data;
+ size_t size = 0;
+ if (mTimedTextTrack.mSource->getFormat()->findData(
+ kKeyTextFormatData, &textType, &data, &size)) {
+ mGlobalTimedText = new ABuffer(size);
+ if (mGlobalTimedText->data()) {
+ memcpy(mGlobalTimedText->data(), data, size);
+ sp<AMessage> globalMeta = mGlobalTimedText->meta();
+ globalMeta->setInt64("timeUs", 0);
+ globalMeta->setString("mime", MEDIA_MIMETYPE_TEXT_3GPP);
+ globalMeta->setInt32("global", 1);
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", what);
+ notify->setBuffer("buffer", mGlobalTimedText);
+ notify->post();
+ }
+ }
+}
+
sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
msg->setInt32("audio", audio);
sp<AMessage> response;
- void *format;
+ sp<RefBase> format;
status_t err = msg->postAndAwaitResponse(&response);
if (err == OK && response != NULL) {
- CHECK(response->findPointer("format", &format));
- return (MetaData *)format;
+ CHECK(response->findObject("format", &format));
+ return static_cast<MetaData*>(format.get());
} else {
return NULL;
}
@@ -980,7 +857,7 @@
sp<AMessage> response = new AMessage;
sp<MetaData> format = doGetFormatMeta(audio);
- response->setPointer("format", format.get());
+ response->setObject("format", format);
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
@@ -988,7 +865,7 @@
}
sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
- sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
+ sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
if (source == NULL) {
return NULL;
@@ -999,6 +876,10 @@
status_t NuPlayer::GenericSource::dequeueAccessUnit(
bool audio, sp<ABuffer> *accessUnit) {
+ if (!mStarted) {
+ return -EWOULDBLOCK;
+ }
+
Track *track = audio ? &mAudioTrack : &mVideoTrack;
if (track->mSource == NULL) {
@@ -1045,6 +926,7 @@
CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
if (audio) {
mAudioLastDequeueTimeUs = timeUs;
+ mBufferingMonitor->updateDequeuedBufferTime(timeUs);
} else {
mVideoLastDequeueTimeUs = timeUs;
}
@@ -1085,6 +967,10 @@
sp<AMessage> format = new AMessage();
sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
+ if (meta == NULL) {
+ ALOGE("no metadata for track %zu", trackIndex);
+ return NULL;
+ }
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -1232,7 +1118,7 @@
return OK;
}
- const sp<MediaSource> source = mSources.itemAt(trackIndex);
+ const sp<IMediaSource> source = mSources.itemAt(trackIndex);
sp<MetaData> meta = source->getFormat();
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -1271,6 +1157,10 @@
msg->post();
}
+ sp<AMessage> msg2 = new AMessage(kWhatSendGlobalTimedTextData, this);
+ msg2->setInt32("generation", mFetchTimedTextDataGeneration);
+ msg2->post();
+
if (mTimedTextTrack.mSource != NULL
&& !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
@@ -1323,6 +1213,8 @@
}
status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
+ mBufferingMonitor->updateDequeuedBufferTime(-1ll);
+
// If the Widevine source is stopped, do not attempt to read any
// more buffers.
if (mStopRead) {
@@ -1349,8 +1241,8 @@
// If currently buffering, post kWhatBufferingEnd first, so that
// NuPlayer resumes. Otherwise, if cache hits high watermark
// before new polling happens, no one will resume the playback.
- stopBufferingIfNecessary();
- restartPollBuffering();
+ mBufferingMonitor->stopBufferingIfNecessary();
+ mBufferingMonitor->restartPollBuffering();
return OK;
}
@@ -1430,6 +1322,14 @@
meta->setBuffer("sei", sei);
}
+ const void *mpegUserDataPointer;
+ size_t mpegUserDataLength;
+ if (mb->meta_data()->findData(
+ kKeyMpegUserData, &dataType, &mpegUserDataPointer, &mpegUserDataLength)) {
+ sp<ABuffer> mpegUserData = ABuffer::CreateAsCopy(mpegUserDataPointer, mpegUserDataLength);
+ meta->setBuffer("mpegUserData", mpegUserData);
+ }
+
if (actualTimeUs) {
*actualTimeUs = timeUs;
}
@@ -1531,14 +1431,17 @@
CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
mAudioTimeUs = timeUs;
+ mBufferingMonitor->updateQueuedTime(true /* isAudio */, timeUs);
} else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
mVideoTimeUs = timeUs;
+ mBufferingMonitor->updateQueuedTime(false /* isAudio */, timeUs);
}
queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
sp<ABuffer> buffer = mediaBufferToABuffer(
- mbuf, trackType, seekTimeUs, actualTimeUs);
+ mbuf, trackType, seekTimeUs,
+ numBuffers == 0 ? actualTimeUs : NULL);
track->mPackets->queueAccessUnit(buffer);
formatChange = false;
seeking = false;
@@ -1575,4 +1478,330 @@
}
}
+NuPlayer::GenericSource::BufferingMonitor::BufferingMonitor(const sp<AMessage> ¬ify)
+ : mNotify(notify),
+ mDurationUs(-1ll),
+ mBitrate(-1ll),
+ mIsStreaming(false),
+ mAudioTimeUs(0),
+ mVideoTimeUs(0),
+ mPollBufferingGeneration(0),
+ mPrepareBuffering(false),
+ mBuffering(false),
+ mPrevBufferPercentage(-1),
+ mOffloadAudio(false),
+ mFirstDequeuedBufferRealUs(-1ll),
+ mFirstDequeuedBufferMediaUs(-1ll),
+ mlastDequeuedBufferMediaUs(-1ll) {
+}
+
+NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() {
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::prepare(
+ const sp<NuCachedSource2> &cachedSource,
+ const sp<WVMExtractor> &wvmExtractor,
+ int64_t durationUs,
+ int64_t bitrate,
+ bool isStreaming) {
+ Mutex::Autolock _l(mLock);
+ prepare_l(cachedSource, wvmExtractor, durationUs, bitrate, isStreaming);
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::stop() {
+ Mutex::Autolock _l(mLock);
+ prepare_l(NULL /* cachedSource */, NULL /* wvmExtractor */, -1 /* durationUs */,
+ -1 /* bitrate */, false /* isStreaming */);
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering() {
+ Mutex::Autolock _l(mLock);
+ cancelPollBuffering_l();
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::restartPollBuffering() {
+ Mutex::Autolock _l(mLock);
+ if (mIsStreaming) {
+ cancelPollBuffering_l();
+ onPollBuffering_l();
+ }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary() {
+ Mutex::Autolock _l(mLock);
+ stopBufferingIfNecessary_l();
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching() {
+ Mutex::Autolock _l(mLock);
+ ensureCacheIsFetching_l();
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::updateQueuedTime(bool isAudio, int64_t timeUs) {
+ Mutex::Autolock _l(mLock);
+ if (isAudio) {
+ mAudioTimeUs = timeUs;
+ } else {
+ mVideoTimeUs = timeUs;
+ }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::setOffloadAudio(bool offload) {
+ Mutex::Autolock _l(mLock);
+ mOffloadAudio = offload;
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::updateDequeuedBufferTime(int64_t mediaUs) {
+ Mutex::Autolock _l(mLock);
+ if (mediaUs < 0) {
+ mFirstDequeuedBufferRealUs = -1ll;
+ mFirstDequeuedBufferMediaUs = -1ll;
+ } else if (mFirstDequeuedBufferRealUs < 0) {
+ mFirstDequeuedBufferRealUs = ALooper::GetNowUs();
+ mFirstDequeuedBufferMediaUs = mediaUs;
+ }
+ mlastDequeuedBufferMediaUs = mediaUs;
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::prepare_l(
+ const sp<NuCachedSource2> &cachedSource,
+ const sp<WVMExtractor> &wvmExtractor,
+ int64_t durationUs,
+ int64_t bitrate,
+ bool isStreaming) {
+ ALOGW_IF(wvmExtractor != NULL && cachedSource != NULL,
+ "WVMExtractor and NuCachedSource are both present when "
+ "BufferingMonitor::prepare_l is called, ignore NuCachedSource");
+
+ mCachedSource = cachedSource;
+ mWVMExtractor = wvmExtractor;
+ mDurationUs = durationUs;
+ mBitrate = bitrate;
+ mIsStreaming = isStreaming;
+ mAudioTimeUs = 0;
+ mVideoTimeUs = 0;
+ mPrepareBuffering = (cachedSource != NULL || wvmExtractor != NULL);
+ cancelPollBuffering_l();
+ mOffloadAudio = false;
+ mFirstDequeuedBufferRealUs = -1ll;
+ mFirstDequeuedBufferMediaUs = -1ll;
+ mlastDequeuedBufferMediaUs = -1ll;
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering_l() {
+ mBuffering = false;
+ ++mPollBufferingGeneration;
+ mPrevBufferPercentage = -1;
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::notifyBufferingUpdate_l(int32_t percentage) {
+ // Buffering percent could go backward as it's estimated from remaining
+ // data and last access time. This could cause the buffering position
+ // drawn on media control to jitter slightly. Remember previously reported
+ // percentage and don't allow it to go backward.
+ if (percentage < mPrevBufferPercentage) {
+ percentage = mPrevBufferPercentage;
+ } else if (percentage > 100) {
+ percentage = 100;
+ }
+
+ mPrevBufferPercentage = percentage;
+
+ ALOGV("notifyBufferingUpdate_l: buffering %d%%", percentage);
+
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatBufferingUpdate);
+ msg->setInt32("percentage", percentage);
+ msg->post();
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::startBufferingIfNecessary_l() {
+ ALOGD("startBufferingIfNecessary_l: mPrepareBuffering=%d, mBuffering=%d",
+ mPrepareBuffering, mBuffering);
+
+ if (mPrepareBuffering) {
+ return;
+ }
+
+ if (!mBuffering) {
+ mBuffering = true;
+
+ ensureCacheIsFetching_l();
+ sendCacheStats_l();
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatPauseOnBufferingStart);
+ notify->post();
+ }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary_l() {
+ ALOGD("stopBufferingIfNecessary_l: mPrepareBuffering=%d, mBuffering=%d",
+ mPrepareBuffering, mBuffering);
+
+ if (mPrepareBuffering) {
+ mPrepareBuffering = false;
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatPrepared);
+ notify->setInt32("err", OK);
+ notify->post();
+
+ return;
+ }
+
+ if (mBuffering) {
+ mBuffering = false;
+
+ sendCacheStats_l();
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatResumeOnBufferingEnd);
+ notify->post();
+ }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::sendCacheStats_l() {
+ int32_t kbps = 0;
+ status_t err = UNKNOWN_ERROR;
+
+ if (mWVMExtractor != NULL) {
+ err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
+ } else if (mCachedSource != NULL) {
+ err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
+ }
+
+ if (err == OK) {
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatCacheStats);
+ notify->setInt32("bandwidth", kbps);
+ notify->post();
+ }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching_l() {
+ if (mCachedSource != NULL) {
+ mCachedSource->resumeFetchingIfNecessary();
+ }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::schedulePollBuffering_l() {
+ sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
+ msg->setInt32("generation", mPollBufferingGeneration);
+ // Enquires buffering status every second.
+ msg->post(1000000ll);
+}
+
+int64_t NuPlayer::GenericSource::BufferingMonitor::getLastReadPosition_l() {
+ if (mAudioTimeUs > 0) {
+ return mAudioTimeUs;
+ } else if (mVideoTimeUs > 0) {
+ return mVideoTimeUs;
+ } else {
+ return 0;
+ }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() {
+ status_t finalStatus = UNKNOWN_ERROR;
+ int64_t cachedDurationUs = -1ll;
+ ssize_t cachedDataRemaining = -1;
+
+ if (mWVMExtractor != NULL) {
+ cachedDurationUs =
+ mWVMExtractor->getCachedDurationUs(&finalStatus);
+ } else if (mCachedSource != NULL) {
+ cachedDataRemaining =
+ mCachedSource->approxDataRemaining(&finalStatus);
+
+ if (finalStatus == OK) {
+ off64_t size;
+ int64_t bitrate = 0ll;
+ if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
+ // |bitrate| uses bits/second unit, while size is number of bytes.
+ bitrate = size * 8000000ll / mDurationUs;
+ } else if (mBitrate > 0) {
+ bitrate = mBitrate;
+ }
+ if (bitrate > 0) {
+ cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
+ }
+ }
+ }
+
+ if (finalStatus != OK) {
+ ALOGV("onPollBuffering_l: EOS (finalStatus = %d)", finalStatus);
+
+ if (finalStatus == ERROR_END_OF_STREAM) {
+ notifyBufferingUpdate_l(100);
+ }
+
+ stopBufferingIfNecessary_l();
+ return;
+ } else if (cachedDurationUs >= 0ll) {
+ if (mDurationUs > 0ll) {
+ int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs;
+ int percentage = 100.0 * cachedPosUs / mDurationUs;
+ if (percentage > 100) {
+ percentage = 100;
+ }
+
+ notifyBufferingUpdate_l(percentage);
+ }
+
+ ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec",
+ cachedDurationUs / 1000000.0f);
+
+ if (cachedDurationUs < kLowWaterMarkUs) {
+ // Take into account the data cached in downstream components to try to avoid
+ // unnecessary pause.
+ if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) {
+ int64_t downStreamCacheUs = mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs
+ - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs);
+ if (downStreamCacheUs > 0) {
+ cachedDurationUs += downStreamCacheUs;
+ }
+ }
+
+ if (cachedDurationUs < kLowWaterMarkUs) {
+ startBufferingIfNecessary_l();
+ }
+ } else {
+ int64_t highWaterMark = mPrepareBuffering ? kHighWaterMarkUs : kHighWaterMarkRebufferUs;
+ if (cachedDurationUs > highWaterMark) {
+ stopBufferingIfNecessary_l();
+ }
+ }
+ } else if (cachedDataRemaining >= 0) {
+ ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes",
+ cachedDataRemaining);
+
+ if (cachedDataRemaining < kLowWaterMarkBytes) {
+ startBufferingIfNecessary_l();
+ } else if (cachedDataRemaining > kHighWaterMarkBytes) {
+ stopBufferingIfNecessary_l();
+ }
+ }
+
+ schedulePollBuffering_l();
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatPollBuffering:
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+ Mutex::Autolock _l(mLock);
+ if (generation == mPollBufferingGeneration) {
+ onPollBuffering_l();
+ }
+ break;
+ }
+ default:
+ TRESPASS();
+ break;
+ }
+}
+
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index ac980ef..2fd703e 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -77,6 +77,8 @@
virtual bool isStreaming() const;
+ virtual void setOffloadAudio(bool offload);
+
protected:
virtual ~GenericSource();
@@ -90,6 +92,7 @@
kWhatFetchSubtitleData,
kWhatFetchTimedTextData,
kWhatSendSubtitleData,
+ kWhatSendGlobalTimedTextData,
kWhatSendTimedTextData,
kWhatChangeAVSource,
kWhatPollBuffering,
@@ -106,11 +109,88 @@
struct Track {
size_t mIndex;
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
sp<AnotherPacketSource> mPackets;
};
- Vector<sp<MediaSource> > mSources;
+ // Helper to monitor buffering status. The polling happens every second.
+ // When necessary, it will send out buffering events to the player.
+ struct BufferingMonitor : public AHandler {
+ public:
+ BufferingMonitor(const sp<AMessage> ¬ify);
+
+ // Set up state.
+ void prepare(const sp<NuCachedSource2> &cachedSource,
+ const sp<WVMExtractor> &wvmExtractor,
+ int64_t durationUs,
+ int64_t bitrate,
+ bool isStreaming);
+ // Stop and reset buffering monitor.
+ void stop();
+ // Cancel the current monitor task.
+ void cancelPollBuffering();
+ // Restart the monitor task.
+ void restartPollBuffering();
+ // Stop buffering task and send out corresponding events.
+ void stopBufferingIfNecessary();
+ // Make sure data source is getting data.
+ void ensureCacheIsFetching();
+ // Update media time of just extracted buffer from data source.
+ void updateQueuedTime(bool isAudio, int64_t timeUs);
+
+ // Set the offload mode.
+ void setOffloadAudio(bool offload);
+ // Update media time of last dequeued buffer which is sent to the decoder.
+ void updateDequeuedBufferTime(int64_t mediaUs);
+
+ protected:
+ virtual ~BufferingMonitor();
+ virtual void onMessageReceived(const sp<AMessage> &msg);
+
+ private:
+ enum {
+ kWhatPollBuffering,
+ };
+
+ sp<AMessage> mNotify;
+
+ sp<NuCachedSource2> mCachedSource;
+ sp<WVMExtractor> mWVMExtractor;
+ int64_t mDurationUs;
+ int64_t mBitrate;
+ bool mIsStreaming;
+
+ int64_t mAudioTimeUs;
+ int64_t mVideoTimeUs;
+ int32_t mPollBufferingGeneration;
+ bool mPrepareBuffering;
+ bool mBuffering;
+ int32_t mPrevBufferPercentage;
+
+ mutable Mutex mLock;
+
+ bool mOffloadAudio;
+ int64_t mFirstDequeuedBufferRealUs;
+ int64_t mFirstDequeuedBufferMediaUs;
+ int64_t mlastDequeuedBufferMediaUs;
+
+ void prepare_l(const sp<NuCachedSource2> &cachedSource,
+ const sp<WVMExtractor> &wvmExtractor,
+ int64_t durationUs,
+ int64_t bitrate,
+ bool isStreaming);
+ void cancelPollBuffering_l();
+ void notifyBufferingUpdate_l(int32_t percentage);
+ void startBufferingIfNecessary_l();
+ void stopBufferingIfNecessary_l();
+ void sendCacheStats_l();
+ void ensureCacheIsFetching_l();
+ int64_t getLastReadPosition_l();
+ void onPollBuffering_l();
+ void schedulePollBuffering_l();
+ };
+
+ Vector<sp<IMediaSource> > mSources;
Track mAudioTrack;
int64_t mAudioTimeUs;
int64_t mAudioLastDequeueTimeUs;
@@ -146,16 +226,15 @@
bool mStarted;
bool mStopRead;
int64_t mBitrate;
- int32_t mPollBufferingGeneration;
+ sp<BufferingMonitor> mBufferingMonitor;
uint32_t mPendingReadBufferTypes;
- bool mBuffering;
- bool mPrepareBuffering;
- int32_t mPrevBufferPercentage;
+ sp<ABuffer> mGlobalTimedText;
mutable Mutex mReadBufferLock;
mutable Mutex mDisconnectLock;
sp<ALooper> mLooper;
+ sp<ALooper> mBufferingMonitorLooper;
void resetDataSource();
@@ -187,6 +266,10 @@
uint32_t what, media_track_type type,
int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
+ void sendGlobalTextData(
+ uint32_t what,
+ int32_t curGen, sp<AMessage> msg);
+
void sendTextData(
uint32_t what, media_track_type type,
int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
@@ -206,16 +289,6 @@
void queueDiscontinuityIfNeeded(
bool seeking, bool formatChange, media_track_type trackType, Track *track);
- void schedulePollBuffering();
- void cancelPollBuffering();
- void restartPollBuffering();
- void onPollBuffering();
- void notifyBufferingUpdate(int32_t percentage);
- void startBufferingIfNecessary();
- void stopBufferingIfNecessary();
- void sendCacheStats();
- void ensureCacheIsFetching();
-
DISALLOW_EVIL_CONSTRUCTORS(GenericSource);
};
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 126625a..3fffdc1a 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -101,15 +101,20 @@
}
sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
- if (mLiveSession == NULL) {
- return NULL;
+ sp<AMessage> format;
+ status_t err = -EWOULDBLOCK;
+ if (mLiveSession != NULL) {
+ err = mLiveSession->getStreamFormat(
+ audio ? LiveSession::STREAMTYPE_AUDIO
+ : LiveSession::STREAMTYPE_VIDEO,
+ &format);
}
- sp<AMessage> format;
- status_t err = mLiveSession->getStreamFormat(
- audio ? LiveSession::STREAMTYPE_AUDIO
- : LiveSession::STREAMTYPE_VIDEO,
- &format);
+ if (err == -EWOULDBLOCK) {
+ format = new AMessage();
+ format->setInt32("err", err);
+ return format;
+ }
if (err != OK) {
return NULL;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 26532d7..d0e7aa9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -188,9 +188,11 @@
mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
mVideoFpsHint(-1.f),
mStarted(false),
+ mResetting(false),
mSourceStarted(false),
mPaused(false),
- mPausedByClient(false),
+ mPausedByClient(true),
+ mPendingBufferingFlag(PENDING_BUFFERING_FLAG_NONE),
mPausedForBuffering(false) {
clearFlushComplete();
}
@@ -421,8 +423,15 @@
void NuPlayer::writeTrackInfo(
Parcel* reply, const sp<AMessage> format) const {
+ if (format == NULL) {
+ ALOGE("NULL format");
+ return;
+ }
int32_t trackType;
- CHECK(format->findInt32("type", &trackType));
+ if (!format->findInt32("type", &trackType)) {
+ ALOGE("no track type");
+ return;
+ }
AString mime;
if (!format->findString("mime", &mime)) {
@@ -435,12 +444,16 @@
} else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
mime = "video/";
} else {
- TRESPASS();
+ ALOGE("unknown track type: %d", trackType);
+ return;
}
}
AString lang;
- CHECK(format->findString("language", &lang));
+ if (!format->findString("language", &lang)) {
+ ALOGE("no language");
+ return;
+ }
reply->writeInt32(2); // write something non-zero
reply->writeInt32(trackType);
@@ -703,6 +716,10 @@
onStart();
}
mPausedByClient = false;
+ if (mPendingBufferingFlag != PENDING_BUFFERING_FLAG_NONE) {
+ notifyListener(MEDIA_INFO, mPendingBufferingFlag, 0);
+ mPendingBufferingFlag = PENDING_BUFFERING_FLAG_NONE;
+ }
break;
}
@@ -719,6 +736,7 @@
if (err == OK) {
if (rate.mSpeed == 0.f) {
onPause();
+ mPausedByClient = true;
// save all other settings (using non-paused speed)
// so we can restore them on start
AudioPlaybackRate newRate = rate;
@@ -726,6 +744,7 @@
mPlaybackSettings = newRate;
} else { /* rate.mSpeed != 0.f */
onResume();
+ mPausedByClient = false;
mPlaybackSettings = rate;
}
}
@@ -833,16 +852,21 @@
bool mHadAnySourcesBefore =
(mAudioDecoder != NULL) || (mVideoDecoder != NULL);
+ bool rescan = false;
// initialize video before audio because successful initialization of
// video may change deep buffer mode of audio.
if (mSurface != NULL) {
- instantiateDecoder(false, &mVideoDecoder);
+ if (instantiateDecoder(false, &mVideoDecoder) == -EWOULDBLOCK) {
+ rescan = true;
+ }
}
// Don't try to re-open audio sink if there's an existing decoder.
if (mAudioSink != NULL && mAudioDecoder == NULL) {
- instantiateDecoder(true, &mAudioDecoder);
+ if (instantiateDecoder(true, &mAudioDecoder) == -EWOULDBLOCK) {
+ rescan = true;
+ }
}
if (!mHadAnySourcesBefore
@@ -869,8 +893,7 @@
break;
}
- if ((mAudioDecoder == NULL && mAudioSink != NULL)
- || (mVideoDecoder == NULL && mSurface != NULL)) {
+ if (rescan) {
msg->post(100000ll);
mScanSourcesPending = true;
}
@@ -1098,6 +1121,7 @@
int32_t reason;
CHECK(msg->findInt32("reason", &reason));
ALOGV("Tear down audio with reason %d.", reason);
+ mAudioDecoder->pause();
mAudioDecoder.clear();
++mAudioDecoderGeneration;
bool needsToCreateAudioDecoder = true;
@@ -1145,6 +1169,8 @@
{
ALOGV("kWhatReset");
+ mResetting = true;
+
mDeferredActions.push_back(
new FlushDecoderAction(
FLUSH_CMD_SHUTDOWN /* audio */,
@@ -1184,6 +1210,8 @@
break;
}
+ mPendingBufferingFlag = PENDING_BUFFERING_FLAG_NONE;
+
mDeferredActions.push_back(
new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
FLUSH_CMD_FLUSH /* video */));
@@ -1227,7 +1255,8 @@
}
void NuPlayer::onResume() {
- if (!mPaused) {
+ if (!mPaused || mResetting) {
+ ALOGD_IF(mResetting, "resetting, onResume discarded");
return;
}
mPaused = false;
@@ -1301,6 +1330,7 @@
}
sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
+ ALOGV_IF(audioMeta == NULL, "no metadata for audio source"); // video only stream
audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
if (mAudioSink != NULL) {
streamType = mAudioSink->getAudioStreamType();
@@ -1503,7 +1533,12 @@
sp<AMessage> format = mSource->getFormat(audio);
if (format == NULL) {
- return -EWOULDBLOCK;
+ return UNKNOWN_ERROR;
+ } else {
+ status_t err;
+ if (format->findInt32("err", &err) && err) {
+ return err;
+ }
}
format->setInt32("priority", 0 /* realtime */);
@@ -1538,10 +1573,14 @@
determineAudioModeChange();
if (mOffloadAudio) {
+ mSource->setOffloadAudio(true /* offload */);
+
const bool hasVideo = (mSource->getFormat(false /*audio */) != NULL);
format->setInt32("has-video", hasVideo);
*decoder = new DecoderPassThrough(notify, mSource, mRenderer);
} else {
+ mSource->setOffloadAudio(false /* offload */);
+
*decoder = new Decoder(notify, mSource, mPID, mRenderer);
}
} else {
@@ -1873,6 +1912,7 @@
}
mPreviousSeekTimeUs = seekTimeUs;
mSource->seekTo(seekTimeUs);
+ mPendingBufferingFlag = PENDING_BUFFERING_FLAG_NONE;
++mTimedTextGeneration;
// everything's flushed, continue playback.
@@ -1930,6 +1970,7 @@
}
mStarted = false;
+ mResetting = false;
mSourceStarted = false;
}
@@ -2116,7 +2157,12 @@
case Source::kWhatBufferingStart:
{
- notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0);
+ if (mPausedByClient) {
+ mPendingBufferingFlag = PENDING_BUFFERING_FLAG_START;
+ } else {
+ notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0);
+ mPendingBufferingFlag = PENDING_BUFFERING_FLAG_NONE;
+ }
break;
}
@@ -2139,6 +2185,7 @@
case Source::kWhatBufferingEnd:
{
notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_END, 0);
+ mPendingBufferingFlag = PENDING_BUFFERING_FLAG_NONE;
break;
}
@@ -2190,7 +2237,7 @@
int posMs;
int64_t timeUs, posUs;
driver->getCurrentPosition(&posMs);
- posUs = posMs * 1000;
+ posUs = (int64_t) posMs * 1000ll;
CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
if (posUs < timeUs) {
@@ -2296,7 +2343,7 @@
const void *data;
size_t size = 0;
int64_t timeUs;
- int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
+ int32_t flag = TextDescriptions::IN_BAND_TEXT_3GPP;
AString mime;
CHECK(buffer->meta()->findString("mime", &mime));
@@ -2308,7 +2355,12 @@
Parcel parcel;
if (size > 0) {
CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
+ int32_t global = 0;
+ if (buffer->meta()->findInt32("global", &global) && global) {
+ flag |= TextDescriptions::GLOBAL_DESCRIPTIONS;
+ } else {
+ flag |= TextDescriptions::LOCAL_DESCRIPTIONS;
+ }
TextDescriptions::getParcelOfDescriptions(
(const uint8_t *)data, size, flag, timeUs / 1000, &parcel);
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index c9f0bbd..cefbb19 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -182,6 +182,12 @@
FLUSH_CMD_SHUTDOWN,
};
+ enum PendingBufferingFlag {
+ PENDING_BUFFERING_FLAG_NONE = MEDIA_INFO_UNKNOWN,
+ PENDING_BUFFERING_FLAG_START = MEDIA_INFO_BUFFERING_START,
+ PENDING_BUFFERING_FLAG_END = MEDIA_INFO_BUFFERING_END,
+ };
+
// Status of flush responses from the decoder and renderer.
bool mFlushComplete[2][2];
@@ -197,6 +203,7 @@
AVSyncSettings mSyncSettings;
float mVideoFpsHint;
bool mStarted;
+ bool mResetting;
bool mSourceStarted;
// Actual pause state, either as requested by client or due to buffering.
@@ -207,6 +214,9 @@
// still become true, when we pause internally due to buffering.
bool mPausedByClient;
+ // Pending buffering flag which is not sent to client due to being paused.
+ PendingBufferingFlag mPendingBufferingFlag;
+
// Pause state as requested by source (internally) due to buffering
bool mPausedForBuffering;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
index ac3c6b6..13716cf 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
@@ -30,6 +30,9 @@
namespace android {
+// In CEA-708B, the maximum bandwidth of CC is set to 9600bps.
+static const size_t kMaxBandwithSizeBytes = 9600 / 8;
+
struct CCData {
CCData(uint8_t type, uint8_t data1, uint8_t data2)
: mType(type), mData1(data1), mData2(data2) {
@@ -116,15 +119,19 @@
NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> ¬ify)
: mNotify(notify),
- mCurrentChannel(0),
- mSelectedTrack(-1) {
- for (size_t i = 0; i < sizeof(mTrackIndices)/sizeof(mTrackIndices[0]); ++i) {
- mTrackIndices[i] = -1;
- }
+ mSelectedTrack(-1),
+ mDTVCCPacket(new ABuffer(kMaxBandwithSizeBytes)) {
+ mDTVCCPacket->setRange(0, 0);
+
+ // In CEA-608, streams from packets which have the value 0 of cc_type contain CC1 and CC2, and
+ // streams from packets which have the value 1 of cc_type contain CC3 and CC4.
+ // The following array indicates the current transmitting channels for each value of cc_type.
+ mLine21Channels[0] = 0; // CC1
+ mLine21Channels[1] = 2; // CC3
}
size_t NuPlayer::CCDecoder::getTrackCount() const {
- return mFoundChannels.size();
+ return mTracks.size();
}
sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const {
@@ -134,13 +141,31 @@
sp<AMessage> format = new AMessage();
+ CCTrack track = mTracks[index];
+
format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
format->setString("language", "und");
- format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
- //CC1, field 0 channel 0
- bool isDefaultAuto = (mFoundChannels[index] == 0);
+
+ switch (track.mTrackType) {
+ case kTrackTypeCEA608:
+ format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
+ break;
+ case kTrackTypeCEA708:
+ format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_708);
+ break;
+ default:
+ ALOGE("Unknown track type: %d", track.mTrackType);
+ return NULL;
+ }
+
+ // For CEA-608 CC1, field 0 channel 0
+ bool isDefaultAuto = track.mTrackType == kTrackTypeCEA608
+ && track.mTrackChannel == 0;
+ // For CEA-708, Primary Caption Service.
+ bool isDefaultOnly = track.mTrackType == kTrackTypeCEA708
+ && track.mTrackChannel == 1;
format->setInt32("auto", isDefaultAuto);
- format->setInt32("default", isDefaultAuto);
+ format->setInt32("default", isDefaultAuto || isDefaultOnly);
format->setInt32("forced", 0);
return format;
@@ -167,24 +192,20 @@
mSelectedTrack = -1;
}
+ // Clear the previous track payloads
+ mCCMap.clear();
+
return OK;
}
bool NuPlayer::CCDecoder::isSelected() const {
- return mSelectedTrack >= 0 && mSelectedTrack < (int32_t) getTrackCount();
+ return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)getTrackCount();
}
bool NuPlayer::CCDecoder::isTrackValid(size_t index) const {
return index < getTrackCount();
}
-int32_t NuPlayer::CCDecoder::getTrackIndex(size_t channel) const {
- if (channel < sizeof(mTrackIndices)/sizeof(mTrackIndices[0])) {
- return mTrackIndices[channel];
- }
- return -1;
-}
-
// returns true if a new CC track is found
bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
sp<ABuffer> sei;
@@ -197,7 +218,7 @@
bool trackAdded = false;
- const NALPosition *nal = (NALPosition *) sei->data();
+ const NALPosition *nal = (NALPosition *)sei->data();
for (size_t i = 0; i < sei->size() / sizeof(NALPosition); ++i, ++nal) {
trackAdded |= parseSEINalUnit(
@@ -208,9 +229,8 @@
}
// returns true if a new CC track is found
-bool NuPlayer::CCDecoder::parseSEINalUnit(
- int64_t timeUs, const uint8_t *nalStart, size_t nalSize) {
- unsigned nalType = nalStart[0] & 0x1f;
+bool NuPlayer::CCDecoder::parseSEINalUnit(int64_t timeUs, const uint8_t *data, size_t size) {
+ unsigned nalType = data[0] & 0x1f;
// the buffer should only have SEI in it
if (nalType != 6) {
@@ -218,7 +238,8 @@
}
bool trackAdded = false;
- NALBitReader br(nalStart + 1, nalSize - 1);
+ NALBitReader br(data + 1, size - 1);
+
// sei_message()
while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
uint32_t payload_type = 0;
@@ -256,53 +277,7 @@
}
if (isCC && payload_size > 2) {
- // MPEG_cc_data()
- // ATSC A/53 Part 4: 6.2.3.1
- br.skipBits(1); //process_em_data_flag
- bool process_cc_data_flag = br.getBits(1);
- br.skipBits(1); //additional_data_flag
- size_t cc_count = br.getBits(5);
- br.skipBits(8); // em_data;
- payload_size -= 2;
-
- if (process_cc_data_flag) {
- AString out;
-
- sp<ABuffer> ccBuf = new ABuffer(cc_count * sizeof(CCData));
- ccBuf->setRange(0, 0);
-
- for (size_t i = 0; i < cc_count && payload_size >= 3; i++) {
- uint8_t marker = br.getBits(5);
- CHECK_EQ(marker, 0x1f);
-
- bool cc_valid = br.getBits(1);
- uint8_t cc_type = br.getBits(2);
- // remove odd parity bit
- uint8_t cc_data_1 = br.getBits(8) & 0x7f;
- uint8_t cc_data_2 = br.getBits(8) & 0x7f;
-
- payload_size -= 3;
-
- if (cc_valid
- && (cc_type == 0 || cc_type == 1)) {
- CCData cc(cc_type, cc_data_1, cc_data_2);
- if (!isNullPad(&cc)) {
- size_t channel;
- if (cc.getChannel(&channel) && getTrackIndex(channel) < 0) {
- mTrackIndices[channel] = mFoundChannels.size();
- mFoundChannels.push_back(channel);
- trackAdded = true;
- }
- memcpy(ccBuf->data() + ccBuf->size(),
- (void *)&cc, sizeof(cc));
- ccBuf->setRange(0, ccBuf->size() + sizeof(CCData));
- }
- }
- }
-
- mCCMap.add(timeUs, ccBuf);
- break;
- }
+ trackAdded |= parseMPEGCCData(timeUs, br.data(), br.numBitsLeft() / 8);
} else {
ALOGV("Malformed SEI payload type 4");
}
@@ -317,31 +292,202 @@
return trackAdded;
}
-sp<ABuffer> NuPlayer::CCDecoder::filterCCBuf(
- const sp<ABuffer> &ccBuf, size_t index) {
- sp<ABuffer> filteredCCBuf = new ABuffer(ccBuf->size());
- filteredCCBuf->setRange(0, 0);
+// returns true if a new CC track is found
+bool NuPlayer::CCDecoder::extractFromMPEGUserData(const sp<ABuffer> &accessUnit) {
+ sp<ABuffer> mpegUserData;
+ if (!accessUnit->meta()->findBuffer("mpegUserData", &mpegUserData)
+ || mpegUserData == NULL) {
+ return false;
+ }
- size_t cc_count = ccBuf->size() / sizeof(CCData);
- const CCData* cc_data = (const CCData*)ccBuf->data();
+ int64_t timeUs;
+ CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+
+ bool trackAdded = false;
+
+ const size_t *userData = (size_t *)mpegUserData->data();
+
+ for (size_t i = 0; i < mpegUserData->size() / sizeof(size_t); ++i) {
+ trackAdded |= parseMPEGUserDataUnit(
+ timeUs, accessUnit->data() + userData[i], accessUnit->size() - userData[i]);
+ }
+
+ return trackAdded;
+}
+
+// returns true if a new CC track is found
+bool NuPlayer::CCDecoder::parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size) {
+ ABitReader br(data + 4, 5);
+
+ uint32_t user_identifier = br.getBits(32);
+ uint8_t user_data_type = br.getBits(8);
+
+ if (user_identifier == 'GA94' && user_data_type == 0x3) {
+ return parseMPEGCCData(timeUs, data + 9, size - 9);
+ }
+
+ return false;
+}
+
+// returns true if a new CC track is found
+bool NuPlayer::CCDecoder::parseMPEGCCData(int64_t timeUs, const uint8_t *data, size_t size) {
+ bool trackAdded = false;
+
+ // MPEG_cc_data()
+ // ATSC A/53 Part 4: 6.2.3.1
+ ABitReader br(data, size);
+
+ if (br.numBitsLeft() <= 16) {
+ return false;
+ }
+
+ br.skipBits(1);
+ bool process_cc_data_flag = br.getBits(1);
+ br.skipBits(1);
+ size_t cc_count = br.getBits(5);
+ br.skipBits(8);
+
+ if (!process_cc_data_flag || 3 * 8 * cc_count >= br.numBitsLeft()) {
+ return false;
+ }
+
+ sp<ABuffer> line21CCBuf = NULL;
+
for (size_t i = 0; i < cc_count; ++i) {
- size_t channel;
- if (cc_data[i].getChannel(&channel)) {
- mCurrentChannel = channel;
- }
- if (mCurrentChannel == mFoundChannels[index]) {
- memcpy(filteredCCBuf->data() + filteredCCBuf->size(),
- (void *)&cc_data[i], sizeof(CCData));
- filteredCCBuf->setRange(0, filteredCCBuf->size() + sizeof(CCData));
+ br.skipBits(5);
+ bool cc_valid = br.getBits(1);
+ uint8_t cc_type = br.getBits(2);
+
+ if (cc_valid) {
+ if (cc_type == 3) {
+ if (mDTVCCPacket->size() > 0) {
+ trackAdded |= parseDTVCCPacket(
+ timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
+ mDTVCCPacket->setRange(0, 0);
+ }
+ memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
+ mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
+ br.skipBits(16);
+ } else if (mDTVCCPacket->size() > 0 && cc_type == 2) {
+ memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
+ mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
+ br.skipBits(16);
+ } else if (cc_type == 0 || cc_type == 1) {
+ uint8_t cc_data_1 = br.getBits(8) & 0x7f;
+ uint8_t cc_data_2 = br.getBits(8) & 0x7f;
+
+ CCData cc(cc_type, cc_data_1, cc_data_2);
+
+ if (isNullPad(&cc)) {
+ continue;
+ }
+
+ size_t channel;
+ if (cc.getChannel(&channel)) {
+ mLine21Channels[cc_type] = channel;
+
+ // create a new track if it does not exist.
+ getTrackIndex(kTrackTypeCEA608, channel, &trackAdded);
+ }
+
+ if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
+ && mTracks[mSelectedTrack].mTrackChannel == mLine21Channels[cc_type]) {
+ if (line21CCBuf == NULL) {
+ line21CCBuf = new ABuffer((cc_count - i) * sizeof(CCData));
+ line21CCBuf->setRange(0, 0);
+ }
+ memcpy(line21CCBuf->data() + line21CCBuf->size(), &cc, sizeof(cc));
+ line21CCBuf->setRange(0, line21CCBuf->size() + sizeof(CCData));
+ }
+ } else {
+ br.skipBits(16);
+ }
+ } else {
+ if ((cc_type == 3 || cc_type == 2) && mDTVCCPacket->size() > 0) {
+ trackAdded |= parseDTVCCPacket(timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
+ mDTVCCPacket->setRange(0, 0);
+ }
+ br.skipBits(16);
}
}
- return filteredCCBuf;
+ if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
+ && line21CCBuf != NULL && line21CCBuf->size() > 0) {
+ mCCMap.add(timeUs, line21CCBuf);
+ }
+
+ return trackAdded;
+}
+
+// returns true if a new CC track is found
+bool NuPlayer::CCDecoder::parseDTVCCPacket(int64_t timeUs, const uint8_t *data, size_t size) {
+ // CEA-708B 5 DTVCC Packet Layer.
+ ABitReader br(data, size);
+ br.skipBits(2);
+
+ size_t packet_size = br.getBits(6);
+ if (packet_size == 0) packet_size = 64;
+ packet_size *= 2;
+
+ if (size != packet_size) {
+ return false;
+ }
+
+ bool trackAdded = false;
+
+ while (br.numBitsLeft() >= 16) {
+ // CEA-708B Figure 5 and 6.
+ uint8_t service_number = br.getBits(3);
+ size_t block_size = br.getBits(5);
+
+ if (service_number == 64) {
+ br.skipBits(2);
+ service_number = br.getBits(6);
+
+ if (service_number < 64) {
+ return trackAdded;
+ }
+ }
+
+ if (br.numBitsLeft() < block_size * 8) {
+ return trackAdded;
+ }
+
+ if (block_size > 0) {
+ size_t trackIndex = getTrackIndex(kTrackTypeCEA708, service_number, &trackAdded);
+ if (mSelectedTrack == (ssize_t)trackIndex) {
+ sp<ABuffer> ccPacket = new ABuffer(block_size);
+ memcpy(ccPacket->data(), br.data(), block_size);
+ mCCMap.add(timeUs, ccPacket);
+ }
+ }
+ br.skipBits(block_size * 8);
+ }
+
+ return trackAdded;
+}
+
+// return the track index for a given type and channel.
+// if the track does not exist, creates a new one.
+size_t NuPlayer::CCDecoder::getTrackIndex(
+ int32_t trackType, size_t channel, bool *trackAdded) {
+ CCTrack track(trackType, channel);
+ ssize_t index = mTrackIndices.indexOfKey(track);
+
+ if (index < 0) {
+ // A new track is added.
+ index = mTracks.size();
+ mTrackIndices.add(track, index);
+ mTracks.add(track);
+ *trackAdded = true;
+ return index;
+ }
+
+ return mTrackIndices.valueAt(index);
}
void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
- if (extractFromSEI(accessUnit)) {
- ALOGI("Found CEA-608 track");
+ if (extractFromMPEGUserData(accessUnit) || extractFromSEI(accessUnit)) {
sp<AMessage> msg = mNotify->dup();
msg->setInt32("what", kWhatTrackAdded);
msg->post();
@@ -350,8 +496,7 @@
}
void NuPlayer::CCDecoder::display(int64_t timeUs) {
- if (!isTrackValid(mSelectedTrack)) {
- ALOGE("Could not find current track(index=%d)", mSelectedTrack);
+ if (!isSelected()) {
return;
}
@@ -361,7 +506,26 @@
return;
}
- sp<ABuffer> ccBuf = filterCCBuf(mCCMap.valueAt(index), mSelectedTrack);
+ sp<ABuffer> ccBuf;
+
+ if (index == 0) {
+ ccBuf = mCCMap.valueAt(index);
+ } else {
+ size_t size = 0;
+
+ for (ssize_t i = 0; i <= index; ++i) {
+ size += mCCMap.valueAt(i)->size();
+ }
+
+ ccBuf = new ABuffer(size);
+ ccBuf->setRange(0, 0);
+
+ for (ssize_t i = 0; i <= index; ++i) {
+ sp<ABuffer> buf = mCCMap.valueAt(i);
+ memcpy(ccBuf->data() + ccBuf->size(), buf->data(), buf->size());
+ ccBuf->setRange(0, ccBuf->size() + buf->size());
+ }
+ }
if (ccBuf->size() > 0) {
#if 0
@@ -384,6 +548,25 @@
void NuPlayer::CCDecoder::flush() {
mCCMap.clear();
+ mDTVCCPacket->setRange(0, 0);
+}
+
+int32_t NuPlayer::CCDecoder::CCTrack::compare(const NuPlayer::CCDecoder::CCTrack& rhs) const {
+ int32_t cmp = mTrackType - rhs.mTrackType;
+ if (cmp != 0) return cmp;
+ return mTrackChannel - rhs.mTrackChannel;
+}
+
+bool NuPlayer::CCDecoder::CCTrack::operator<(const NuPlayer::CCDecoder::CCTrack& rhs) const {
+ return compare(rhs) < 0;
+}
+
+bool NuPlayer::CCDecoder::CCTrack::operator==(const NuPlayer::CCDecoder::CCTrack& rhs) const {
+ return compare(rhs) == 0;
+}
+
+bool NuPlayer::CCDecoder::CCTrack::operator!=(const NuPlayer::CCDecoder::CCTrack& rhs) const {
+ return compare(rhs) != 0;
}
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
index 77fb0fe..a297334 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
@@ -28,6 +28,11 @@
kWhatTrackAdded,
};
+ enum {
+ kTrackTypeCEA608,
+ kTrackTypeCEA708,
+ };
+
CCDecoder(const sp<AMessage> ¬ify);
size_t getTrackCount() const;
@@ -39,18 +44,50 @@
void flush();
private:
+ // CC track identifier.
+ struct CCTrack {
+ CCTrack() : mTrackType(0), mTrackChannel(0) { }
+
+ CCTrack(const int32_t trackType, const size_t trackChannel)
+ : mTrackType(trackType), mTrackChannel(trackChannel) { }
+
+ int32_t mTrackType;
+ size_t mTrackChannel;
+
+ // The ordering of CCTracks is to build a map of track to index.
+ // It is necessary to find the index of the matched CCTrack when CC data comes.
+ int compare(const NuPlayer::CCDecoder::CCTrack& rhs) const;
+ inline bool operator<(const NuPlayer::CCDecoder::CCTrack& rhs) const;
+ inline bool operator==(const NuPlayer::CCDecoder::CCTrack& rhs) const;
+ inline bool operator!=(const NuPlayer::CCDecoder::CCTrack& rhs) const;
+ };
+
sp<AMessage> mNotify;
KeyedVector<int64_t, sp<ABuffer> > mCCMap;
- size_t mCurrentChannel;
- int32_t mSelectedTrack;
- int32_t mTrackIndices[4];
- Vector<size_t> mFoundChannels;
+ ssize_t mSelectedTrack;
+ KeyedVector<CCTrack, size_t> mTrackIndices;
+ Vector<CCTrack> mTracks;
+
+ // CEA-608 closed caption
+ size_t mLine21Channels[2]; // The current channels of NTSC_CC_FIELD_{1, 2}
+
+ // CEA-708 closed caption
+ sp<ABuffer> mDTVCCPacket;
bool isTrackValid(size_t index) const;
- int32_t getTrackIndex(size_t channel) const;
+ size_t getTrackIndex(int32_t trackType, size_t channel, bool *trackAdded);
+
+ // Extract from H.264 SEIs
bool extractFromSEI(const sp<ABuffer> &accessUnit);
- bool parseSEINalUnit(int64_t timeUs, const uint8_t *nalStart, size_t nalSize);
- sp<ABuffer> filterCCBuf(const sp<ABuffer> &ccBuf, size_t index);
+ bool parseSEINalUnit(int64_t timeUs, const uint8_t *data, size_t size);
+
+ // Extract from MPEG user data
+ bool extractFromMPEGUserData(const sp<ABuffer> &accessUnit);
+ bool parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size);
+
+ // Extract CC tracks from MPEG_cc_data
+ bool parseMPEGCCData(int64_t timeUs, const uint8_t *data, size_t size);
+ bool parseDTVCCPacket(int64_t timeUs, const uint8_t *data, size_t size);
DISALLOW_EVIL_CONSTRUCTORS(CCDecoder);
};
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index c005f3f..4678956 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -69,7 +69,6 @@
mIsSecure(false),
mFormatChangePending(false),
mTimeChangePending(false),
- mPaused(true),
mResumePending(false),
mComponentName("decoder") {
mCodecLooper = new ALooper;
@@ -526,7 +525,10 @@
ALOGI("[%s] resubmitting CSD", mComponentName.c_str());
msg->setBuffer("buffer", buffer);
mCSDsToSubmit.removeAt(0);
- CHECK(onInputBufferFetched(msg));
+ if (!onInputBufferFetched(msg)) {
+ handleError(UNKNOWN_ERROR);
+ return false;
+ }
return true;
}
@@ -863,7 +865,11 @@
// copy into codec buffer
if (buffer != codecBuffer) {
- CHECK_LE(buffer->size(), codecBuffer->capacity());
+ if (buffer->size() > codecBuffer->capacity()) {
+ handleError(ERROR_BUFFER_TOO_SMALL);
+ mDequeuedInputBuffers.push_back(bufferIx);
+ return false;
+ }
codecBuffer->setRange(0, buffer->size());
memcpy(codecBuffer->data(), buffer->data(), buffer->size());
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index eeb4af4..ae08b4b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -91,7 +91,6 @@
bool mFormatChangePending;
bool mTimeChangePending;
- bool mPaused;
bool mResumePending;
AString mComponentName;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
index 7e76842..04bb61c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
@@ -31,6 +31,7 @@
NuPlayer::DecoderBase::DecoderBase(const sp<AMessage> ¬ify)
: mNotify(notify),
mBufferGeneration(0),
+ mPaused(false),
mStats(new AMessage),
mRequestInputBuffersPending(false) {
// Every decoder has its own looper because MediaCodec operations
@@ -83,6 +84,13 @@
msg->post();
}
+void NuPlayer::DecoderBase::pause() {
+ sp<AMessage> msg = new AMessage(kWhatPause, this);
+
+ sp<AMessage> response;
+ PostAndAwaitResponse(msg, &response);
+}
+
status_t NuPlayer::DecoderBase::getInputBuffers(Vector<sp<ABuffer> > *buffers) const {
sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, this);
msg->setPointer("buffers", buffers);
@@ -146,6 +154,17 @@
break;
}
+ case kWhatPause:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ mPaused = true;
+
+ (new AMessage)->postReply(replyID);
+ break;
+ }
+
case kWhatGetInputBuffers:
{
sp<AReplyToken> replyID;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index b0dc01d..a334ec5 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -36,6 +36,9 @@
void init();
void setParameters(const sp<AMessage> ¶ms);
+ // Synchronous call to ensure decoder will not request or send out data.
+ void pause();
+
void setRenderer(const sp<Renderer> &renderer);
virtual status_t setVideoSurface(const sp<Surface> &) { return INVALID_OPERATION; }
@@ -78,6 +81,7 @@
sp<AMessage> mNotify;
int32_t mBufferGeneration;
+ bool mPaused;
sp<AMessage> mStats;
private:
@@ -85,6 +89,7 @@
kWhatConfigure = 'conf',
kWhatSetParameters = 'setP',
kWhatSetRenderer = 'setR',
+ kWhatPause = 'paus',
kWhatGetInputBuffers = 'gInB',
kWhatRequestInputBuffers = 'reqB',
kWhatFlush = 'flus',
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index 30146c4..f224635 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -47,7 +47,6 @@
mSource(source),
mRenderer(renderer),
mSkipRenderingUntilMediaTimeUs(-1ll),
- mPaused(false),
mReachedEOS(true),
mPendingAudioErr(OK),
mPendingBuffersToDrain(0),
@@ -224,6 +223,11 @@
status_t err = dequeueAccessUnit(&accessUnit);
if (err == -EWOULDBLOCK) {
+ // Flush out the aggregate buffer to try to avoid underrun.
+ accessUnit = aggregateBuffer(NULL /* accessUnit */);
+ if (accessUnit != NULL) {
+ break;
+ }
return err;
} else if (err != OK) {
if (err == INFO_DISCONTINUITY) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
index db33e87..5850efa 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
@@ -52,7 +52,6 @@
sp<Source> mSource;
sp<Renderer> mRenderer;
int64_t mSkipRenderingUntilMediaTimeUs;
- bool mPaused;
bool mReachedEOS;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index f288c36..332fef6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -334,8 +334,8 @@
// down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
// current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
// getCurrentPosition here.
- int msec;
- getCurrentPosition(&msec);
+ int unused;
+ getCurrentPosition(&unused);
Mutex::Autolock autoLock(mLock);
@@ -364,11 +364,12 @@
status_t NuPlayerDriver::setPlaybackSettings(const AudioPlaybackRate &rate) {
status_t err = mPlayer->setPlaybackSettings(rate);
if (err == OK) {
+ // try to update position
+ int unused;
+ getCurrentPosition(&unused);
Mutex::Autolock autoLock(mLock);
if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
mState = STATE_PAUSED;
- // try to update position
- (void)mPlayer->getCurrentPosition(&mPositionUs);
notifyListener_l(MEDIA_PAUSED);
} else if (rate.mSpeed != 0.f && mState == STATE_PAUSED) {
mState = STATE_RUNNING;
@@ -390,7 +391,7 @@
}
status_t NuPlayerDriver::seekTo(int msec) {
- ALOGD("seekTo(%p) %d ms", this, msec);
+ ALOGD("seekTo(%p) %d ms at state %d", this, msec, mState);
Mutex::Autolock autoLock(mLock);
int64_t seekTimeUs = msec * 1000ll;
@@ -423,7 +424,7 @@
int64_t tempUs = 0;
{
Mutex::Autolock autoLock(mLock);
- if (mSeekInProgress || mState == STATE_PAUSED) {
+ if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) {
tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
*msec = (int)divRound(tempUs, (int64_t)(1000));
return OK;
@@ -458,7 +459,7 @@
}
status_t NuPlayerDriver::reset() {
- ALOGD("reset(%p)", this);
+ ALOGD("reset(%p) at state %d", this, mState);
Mutex::Autolock autoLock(mLock);
switch (mState) {
@@ -725,7 +726,8 @@
void NuPlayerDriver::notifyListener_l(
int msg, int ext1, int ext2, const Parcel *in) {
- ALOGD("notifyListener_l(%p), (%d, %d, %d)", this, msg, ext1, ext2);
+ ALOGD("notifyListener_l(%p), (%d, %d, %d), loop setting(%d, %d)",
+ this, msg, ext1, ext2, mAutoLoop, mLooping);
switch (msg) {
case MEDIA_PLAYBACK_COMPLETE:
{
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 4d25294..0e6a6e6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -69,6 +69,11 @@
// is closed to allow the audio DSP to power down.
static const int64_t kOffloadPauseMaxUs = 10000000ll;
+// Maximum allowed delay from AudioSink, 1.5 seconds.
+static const int64_t kMaxAllowedAudioSinkDelayUs = 1500000ll;
+
+static const int64_t kMinimumAudioClockUpdatePeriodUs = 20 /* msec */ * 1000;
+
// static
const NuPlayer::Renderer::PcmInfo NuPlayer::Renderer::AUDIO_PCMINFO_INITIALIZER = {
AUDIO_CHANNEL_NONE,
@@ -86,6 +91,7 @@
const sp<AMessage> ¬ify,
uint32_t flags)
: mAudioSink(sink),
+ mUseVirtualAudioSink(false),
mNotify(notify),
mFlags(flags),
mNumFramesWritten(0),
@@ -95,6 +101,7 @@
mVideoQueueGeneration(0),
mAudioDrainGeneration(0),
mVideoDrainGeneration(0),
+ mAudioEOSGeneration(0),
mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
mAudioFirstAnchorTimeMediaUs(-1),
mAnchorTimeMediaUs(-1),
@@ -112,6 +119,8 @@
mVideoRenderingStartGeneration(0),
mAudioRenderingStartGeneration(0),
mRenderingDataDelivered(false),
+ mNextAudioClockUpdateTimeUs(-1),
+ mLastAudioMediaTimeUs(-1),
mAudioOffloadPauseTimeoutGeneration(0),
mAudioTornDown(false),
mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
@@ -311,8 +320,33 @@
msg->post();
}
-// Called on any threads.
+// Called on any threads without mLock acquired.
status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) {
+ status_t result = mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
+ if (result == OK) {
+ return result;
+ }
+
+ // MediaClock has not started yet. Try to start it if possible.
+ {
+ Mutex::Autolock autoLock(mLock);
+ if (mAudioFirstAnchorTimeMediaUs == -1) {
+ return result;
+ }
+
+ AudioTimestamp ts;
+ status_t res = mAudioSink->getTimestamp(ts);
+ if (res != OK) {
+ return result;
+ }
+
+ // AudioSink has rendered some frames.
+ int64_t nowUs = ALooper::GetNowUs();
+ int64_t nowMediaUs = mAudioSink->getPlayedOutDurationUs(nowUs)
+ + mAudioFirstAnchorTimeMediaUs;
+ mMediaClock->updateAnchor(nowMediaUs, nowUs, -1);
+ }
+
return mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
}
@@ -500,6 +534,19 @@
break;
}
+ case kWhatEOS:
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("audioEOSGeneration", &generation));
+ if (generation != mAudioEOSGeneration) {
+ break;
+ }
+ status_t finalResult;
+ CHECK(msg->findInt32("finalResult", &finalResult));
+ notifyEOS(true /* audio */, finalResult);
+ break;
+ }
+
case kWhatConfigPlayback:
{
sp<AReplyToken> replyID;
@@ -755,7 +802,7 @@
if (mAudioFirstAnchorTimeMediaUs >= 0) {
int64_t nowUs = ALooper::GetNowUs();
int64_t nowMediaUs =
- mAudioFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs);
+ mAudioFirstAnchorTimeMediaUs + mAudioSink->getPlayedOutDurationUs(nowUs);
// we don't know how much data we are queueing for offloaded tracks.
mMediaClock->updateAnchor(nowMediaUs, nowUs, INT64_MAX);
}
@@ -864,6 +911,7 @@
postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
}
notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
+ mLastAudioMediaTimeUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
mAudioQueue.erase(mAudioQueue.begin());
entry = NULL;
@@ -973,7 +1021,16 @@
// Calculate duration of pending samples if played at normal rate (i.e., 1.0).
int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
int64_t writtenAudioDurationUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
- return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs);
+ if (mUseVirtualAudioSink) {
+ int64_t nowUs = ALooper::GetNowUs();
+ int64_t mediaUs;
+ if (mMediaClock->getMediaTime(nowUs, &mediaUs) != OK) {
+ return 0ll;
+ } else {
+ return writtenAudioDurationUs - (mediaUs - mAudioFirstAnchorTimeMediaUs);
+ }
+ }
+ return writtenAudioDurationUs - mAudioSink->getPlayedOutDurationUs(nowUs);
}
int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
@@ -994,9 +1051,39 @@
return;
}
setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
+
+ // mNextAudioClockUpdateTimeUs is -1 if we're waiting for audio sink to start
+ if (mNextAudioClockUpdateTimeUs == -1) {
+ AudioTimestamp ts;
+ if (mAudioSink->getTimestamp(ts) == OK && ts.mPosition > 0) {
+ mNextAudioClockUpdateTimeUs = 0; // start our clock updates
+ }
+ }
int64_t nowUs = ALooper::GetNowUs();
- int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
- mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
+ if (mNextAudioClockUpdateTimeUs >= 0) {
+ if (nowUs >= mNextAudioClockUpdateTimeUs) {
+ int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
+ mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
+ mUseVirtualAudioSink = false;
+ mNextAudioClockUpdateTimeUs = nowUs + kMinimumAudioClockUpdatePeriodUs;
+ }
+ } else {
+ int64_t unused;
+ if ((mMediaClock->getMediaTime(nowUs, &unused) != OK)
+ && (getDurationUsIfPlayedAtSampleRate(mNumFramesWritten)
+ > kMaxAllowedAudioSinkDelayUs)) {
+ // Enough data has been sent to AudioSink, but AudioSink has not rendered
+ // any data yet. Something is wrong with AudioSink, e.g., the device is not
+ // connected to audio out.
+ // Switch to system clock. This essentially creates a virtual AudioSink with
+ // initial latenty of getDurationUsIfPlayedAtSampleRate(mNumFramesWritten).
+ // This virtual AudioSink renders audio data starting from the very first sample
+ // and it's paced by system clock.
+ ALOGW("AudioSink stuck. ARE YOU CONNECTED TO AUDIO OUT? Switching to system clock.");
+ mMediaClock->updateAnchor(mAudioFirstAnchorTimeMediaUs, nowUs, mediaTimeUs);
+ mUseVirtualAudioSink = true;
+ }
+ }
mAnchorNumFramesWritten = mNumFramesWritten;
mAnchorTimeMediaUs = mediaTimeUs;
}
@@ -1025,6 +1112,7 @@
return;
}
+ bool needRepostDrainVideoQueue = false;
int64_t delayUs;
int64_t nowUs = ALooper::GetNowUs();
int64_t realTimeUs;
@@ -1042,8 +1130,17 @@
mMediaClock->updateAnchor(mediaTimeUs, nowUs, mediaTimeUs);
mAnchorTimeMediaUs = mediaTimeUs;
realTimeUs = nowUs;
- } else {
+ } else if (!mVideoSampleReceived) {
+ // Always render the first video frame.
+ realTimeUs = nowUs;
+ } else if (mAudioFirstAnchorTimeMediaUs < 0
+ || mMediaClock->getRealTimeFor(mediaTimeUs, &realTimeUs) == OK) {
realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
+ } else if (mediaTimeUs - mAudioFirstAnchorTimeMediaUs >= 0) {
+ needRepostDrainVideoQueue = true;
+ realTimeUs = nowUs;
+ } else {
+ realTimeUs = nowUs;
}
}
if (!mHasAudio) {
@@ -1056,15 +1153,25 @@
// received after this buffer, repost in 10 msec. Otherwise repost
// in 500 msec.
delayUs = realTimeUs - nowUs;
+ int64_t postDelayUs = -1;
if (delayUs > 500000) {
- int64_t postDelayUs = 500000;
+ postDelayUs = 500000;
if (mHasAudio && (mLastAudioBufferDrained - entry.mBufferOrdinal) <= 0) {
postDelayUs = 10000;
}
+ } else if (needRepostDrainVideoQueue) {
+ // CHECK(mPlaybackRate > 0);
+ // CHECK(mAudioFirstAnchorTimeMediaUs >= 0);
+ // CHECK(mediaTimeUs - mAudioFirstAnchorTimeMediaUs >= 0);
+ postDelayUs = mediaTimeUs - mAudioFirstAnchorTimeMediaUs;
+ postDelayUs /= mPlaybackRate;
+ }
+
+ if (postDelayUs >= 0) {
msg->setWhat(kWhatPostDrainVideoQueue);
msg->post(postDelayUs);
mVideoScheduler->restart();
- ALOGI("possible video time jump of %dms, retrying in %dms",
+ ALOGI("possible video time jump of %dms or uninitialized media clock, retrying in %dms",
(int)(delayUs / 1000), (int)(postDelayUs / 1000));
mDrainVideoQueuePending = true;
return;
@@ -1102,24 +1209,20 @@
return;
}
- int64_t nowUs = -1;
+ int64_t nowUs = ALooper::GetNowUs();
int64_t realTimeUs;
+ int64_t mediaTimeUs = -1;
if (mFlags & FLAG_REAL_TIME) {
CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
} else {
- int64_t mediaTimeUs;
CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
- nowUs = ALooper::GetNowUs();
realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
}
bool tooLate = false;
if (!mPaused) {
- if (nowUs == -1) {
- nowUs = ALooper::GetNowUs();
- }
setVideoLateByUs(nowUs - realTimeUs);
tooLate = (mVideoLateByUs > 40000);
@@ -1132,6 +1235,14 @@
ALOGV("rendering video at media time %.2f secs",
(mFlags & FLAG_REAL_TIME ? realTimeUs :
mediaUs) / 1E6);
+
+ if (!(mFlags & FLAG_REAL_TIME)
+ && mLastAudioMediaTimeUs != -1
+ && mediaTimeUs > mLastAudioMediaTimeUs) {
+ // If audio ends before video, video continues to drive media clock.
+ // Also smooth out videos >= 10fps.
+ mMediaClock->updateMaxTimeMedia(mediaTimeUs + 100000);
+ }
}
} else {
setVideoLateByUs(0);
@@ -1143,6 +1254,12 @@
}
}
+ // Always render the first video frame while keeping stats on A/V sync.
+ if (!mVideoSampleReceived) {
+ realTimeUs = nowUs;
+ tooLate = false;
+ }
+
entry->mNotifyConsumed->setInt64("timestampNs", realTimeUs * 1000ll);
entry->mNotifyConsumed->setInt32("render", !tooLate);
entry->mNotifyConsumed->post();
@@ -1168,6 +1285,13 @@
}
void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
+ if (audio && delayUs > 0) {
+ sp<AMessage> msg = new AMessage(kWhatEOS, this);
+ msg->setInt32("audioEOSGeneration", mAudioEOSGeneration);
+ msg->setInt32("finalResult", finalResult);
+ msg->post(delayUs);
+ return;
+ }
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kWhatEOS);
notify->setInt32("audio", static_cast<int32_t>(audio));
@@ -1318,6 +1442,7 @@
if (audio) {
notifyComplete = mNotifyCompleteAudio;
mNotifyCompleteAudio = false;
+ mLastAudioMediaTimeUs = -1;
} else {
notifyComplete = mNotifyCompleteVideo;
mNotifyCompleteVideo = false;
@@ -1342,6 +1467,7 @@
flushQueue(&mAudioQueue);
++mAudioDrainGeneration;
+ ++mAudioEOSGeneration;
prepareForMediaRenderingStart_l();
// the frame count will be reset after flush.
@@ -1375,6 +1501,7 @@
}
mNumFramesWritten = 0;
}
+ mNextAudioClockUpdateTimeUs = -1;
} else {
flushQueue(&mVideoQueue);
@@ -1484,10 +1611,9 @@
mDrainAudioQueuePending = false;
mDrainVideoQueuePending = false;
- if (mHasAudio) {
- mAudioSink->pause();
- startAudioOffloadPauseTimeout();
- }
+ // Note: audio data may not have been decoded, and the AudioSink may not be opened.
+ mAudioSink->pause();
+ startAudioOffloadPauseTimeout();
ALOGV("now paused audio queue has %zu entries, video has %zu entries",
mAudioQueue.size(), mVideoQueue.size());
@@ -1498,8 +1624,9 @@
return;
}
- if (mHasAudio) {
- cancelAudioOffloadPauseTimeout();
+ // Note: audio data may not have been decoded, and the AudioSink may not be opened.
+ cancelAudioOffloadPauseTimeout();
+ if (mAudioSink->ready()) {
status_t err = mAudioSink->start();
if (err != OK) {
ALOGE("cannot start AudioSink err %d", err);
@@ -1553,70 +1680,6 @@
return mSyncQueues;
}
-// TODO: Remove unnecessary calls to getPlayedOutAudioDurationUs()
-// as it acquires locks and may query the audio driver.
-//
-// Some calls could conceivably retrieve extrapolated data instead of
-// accessing getTimestamp() or getPosition() every time a data buffer with
-// a media time is received.
-//
-// Calculate duration of played samples if played at normal rate (i.e., 1.0).
-int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) {
- uint32_t numFramesPlayed;
- int64_t numFramesPlayedAt;
- AudioTimestamp ts;
- static const int64_t kStaleTimestamp100ms = 100000;
-
- status_t res = mAudioSink->getTimestamp(ts);
- if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
- numFramesPlayed = ts.mPosition;
- numFramesPlayedAt =
- ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
- const int64_t timestampAge = nowUs - numFramesPlayedAt;
- if (timestampAge > kStaleTimestamp100ms) {
- // This is an audio FIXME.
- // getTimestamp returns a timestamp which may come from audio mixing threads.
- // After pausing, the MixerThread may go idle, thus the mTime estimate may
- // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms,
- // the max latency should be about 25ms with an average around 12ms (to be verified).
- // For safety we use 100ms.
- ALOGV("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)",
- (long long)nowUs, (long long)numFramesPlayedAt);
- numFramesPlayedAt = nowUs - kStaleTimestamp100ms;
- }
- //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAt);
- } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
- numFramesPlayed = 0;
- numFramesPlayedAt = nowUs;
- //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
- // numFramesPlayed, (long long)numFramesPlayedAt);
- } else { // case 3: transitory at new track or audio fast tracks.
- res = mAudioSink->getPosition(&numFramesPlayed);
- CHECK_EQ(res, (status_t)OK);
- numFramesPlayedAt = nowUs;
- numFramesPlayedAt += 1000LL * mAudioSink->latency() / 2; /* XXX */
- //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAt);
- }
-
- //CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
- int64_t durationUs = getDurationUsIfPlayedAtSampleRate(numFramesPlayed)
- + nowUs - numFramesPlayedAt;
- if (durationUs < 0) {
- // Occurs when numFramesPlayed position is very small and the following:
- // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
- // numFramesPlayedAt is greater than nowUs by time more than numFramesPlayed.
- // (2) In case 3, using getPosition and adding mAudioSink->latency() to
- // numFramesPlayedAt, by a time amount greater than numFramesPlayed.
- //
- // Both of these are transitory conditions.
- ALOGV("getPlayedOutAudioDurationUs: negative duration %lld set to zero", (long long)durationUs);
- durationUs = 0;
- }
- ALOGV("getPlayedOutAudioDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
- (long long)durationUs, (long long)nowUs, numFramesPlayed, (long long)numFramesPlayedAt);
- return durationUs;
-}
-
void NuPlayer::Renderer::onAudioTearDown(AudioTearDownReason reason) {
if (mAudioTornDown) {
return;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 9479c31..c3ce511 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -134,6 +134,7 @@
static const int64_t kMinPositionUpdateDelayUs;
sp<MediaPlayerBase::AudioSink> mAudioSink;
+ bool mUseVirtualAudioSink;
sp<AMessage> mNotify;
Mutex mLock;
uint32_t mFlags;
@@ -148,6 +149,7 @@
int32_t mVideoQueueGeneration;
int32_t mAudioDrainGeneration;
int32_t mVideoDrainGeneration;
+ int32_t mAudioEOSGeneration;
sp<MediaClock> mMediaClock;
float mPlaybackRate; // audio track rate
@@ -178,7 +180,9 @@
int32_t mAudioRenderingStartGeneration;
bool mRenderingDataDelivered;
- int64_t mLastPositionUpdateUs;
+ int64_t mNextAudioClockUpdateTimeUs;
+ // the media timestamp of last audio sample right before EOS.
+ int64_t mLastAudioMediaTimeUs;
int32_t mAudioOffloadPauseTimeoutGeneration;
bool mAudioTornDown;
@@ -212,7 +216,6 @@
bool onDrainAudioQueue();
void drainAudioQueueUntilLastEOS();
int64_t getPendingAudioPlayoutDurationUs(int64_t nowUs);
- int64_t getPlayedOutAudioDurationUs(int64_t nowUs);
void postDrainAudioQueue_l(int64_t delayUs = 0);
void clearAnchorTime_l();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 11a6a9f..fba4540 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -122,6 +122,8 @@
return true;
}
+ virtual void setOffloadAudio(bool /* offload */) {}
+
protected:
virtual ~Source() {}
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index af0351e..ec33478 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -76,6 +76,11 @@
}
void NuPlayer::RTSPSource::prepareAsync() {
+ if (mIsSDP && mHTTPService == NULL) {
+ notifyPrepared(BAD_VALUE);
+ return;
+ }
+
if (mLooper == NULL) {
mLooper = new ALooper;
mLooper->setName("rtsp");
@@ -380,10 +385,8 @@
case MyHandler::kWhatSeekDone:
{
mState = CONNECTED;
- if (mSeekReplyID != NULL) {
- // Unblock seekTo here in case we attempted to seek in a live stream
- finishSeek(OK);
- }
+ // Unblock seekTo here in case we attempted to seek in a live stream
+ finishSeek(OK);
break;
}
@@ -404,12 +407,13 @@
status_t err = OK;
msg->findInt32("err", &err);
- finishSeek(err);
if (err == OK) {
int64_t timeUs;
CHECK(msg->findInt64("time", &timeUs));
mHandler->continueSeekAfterPause(timeUs);
+ } else {
+ finishSeek(err);
}
break;
}
@@ -744,7 +748,9 @@
}
void NuPlayer::RTSPSource::finishSeek(status_t err) {
- CHECK(mSeekReplyID != NULL);
+ if (mSeekReplyID == NULL) {
+ return;
+ }
sp<AMessage> seekReply = new AMessage;
seekReply->setInt32("err", err);
seekReply->postReply(mSeekReplyID);
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index 0246b59..d4c88de 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -32,6 +32,8 @@
namespace android {
+const int32_t kNumListenerQueuePackets = 80;
+
NuPlayer::StreamingSource::StreamingSource(
const sp<AMessage> ¬ify,
const sp<IStreamSource> &source)
@@ -84,7 +86,7 @@
}
void NuPlayer::StreamingSource::onReadBuffer() {
- for (int32_t i = 0; i < 50; ++i) {
+ for (int32_t i = 0; i < kNumListenerQueuePackets; ++i) {
char buffer[188];
sp<AMessage> extra;
ssize_t n = mStreamListener->read(buffer, sizeof(buffer), &extra);
diff --git a/media/libnbaio/Android.mk b/media/libnbaio/Android.mk
index 1353f28..16c5040 100644
--- a/media/libnbaio/Android.mk
+++ b/media/libnbaio/Android.mk
@@ -28,7 +28,6 @@
LOCAL_SHARED_LIBRARIES := \
libaudioutils \
libbinder \
- libcommon_time_client \
libcutils \
libutils \
liblog
diff --git a/media/libnbaio/AudioBufferProviderSource.cpp b/media/libnbaio/AudioBufferProviderSource.cpp
index 551f516..cba8b59 100644
--- a/media/libnbaio/AudioBufferProviderSource.cpp
+++ b/media/libnbaio/AudioBufferProviderSource.cpp
@@ -46,16 +46,14 @@
return mBuffer.raw != NULL ? mBuffer.frameCount - mConsumed : 0;
}
-ssize_t AudioBufferProviderSource::read(void *buffer,
- size_t count,
- int64_t readPTS)
+ssize_t AudioBufferProviderSource::read(void *buffer, size_t count)
{
if (CC_UNLIKELY(!mNegotiated)) {
return NEGOTIATE;
}
if (CC_UNLIKELY(mBuffer.raw == NULL)) {
mBuffer.frameCount = count;
- status_t status = mProvider->getNextBuffer(&mBuffer, readPTS);
+ status_t status = mProvider->getNextBuffer(&mBuffer);
if (status != OK) {
return status == NOT_ENOUGH_DATA ? (ssize_t) WOULD_BLOCK : (ssize_t) status;
}
@@ -81,8 +79,7 @@
return count;
}
-ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *user,
- int64_t readPTS, size_t block)
+ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *user, size_t block)
{
if (CC_UNLIKELY(!mNegotiated)) {
return NEGOTIATE;
@@ -102,7 +99,7 @@
// 1 <= count <= block
if (CC_UNLIKELY(mBuffer.raw == NULL)) {
mBuffer.frameCount = count;
- status_t status = mProvider->getNextBuffer(&mBuffer, readPTS);
+ status_t status = mProvider->getNextBuffer(&mBuffer);
if (CC_LIKELY(status == OK)) {
ALOG_ASSERT(mBuffer.raw != NULL && mBuffer.frameCount <= count);
// mConsumed is 0 either from constructor or after releaseBuffer()
@@ -120,8 +117,8 @@
count = available;
}
if (CC_LIKELY(count > 0)) {
- char* readTgt = (char *) mBuffer.raw + (mConsumed * mFrameSize);
- ssize_t ret = via(user, readTgt, count, readPTS);
+ ssize_t ret = via(user, (char *) mBuffer.raw + (mConsumed * mFrameSize), count);
+
if (CC_UNLIKELY(ret <= 0)) {
if (CC_LIKELY(accumulator > 0)) {
return accumulator;
diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp
index 6aab48a..286e0eb 100644
--- a/media/libnbaio/AudioStreamInSource.cpp
+++ b/media/libnbaio/AudioStreamInSource.cpp
@@ -64,7 +64,7 @@
return mFramesOverrun;
}
-ssize_t AudioStreamInSource::read(void *buffer, size_t count, int64_t readPTS __unused)
+ssize_t AudioStreamInSource::read(void *buffer, size_t count)
{
if (CC_UNLIKELY(!Format_isValid(mFormat))) {
return NEGOTIATE;
diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp
index 0d5f935..3f4e0bb 100644
--- a/media/libnbaio/AudioStreamOutSink.cpp
+++ b/media/libnbaio/AudioStreamOutSink.cpp
@@ -66,18 +66,6 @@
return ret;
}
-status_t AudioStreamOutSink::getNextWriteTimestamp(int64_t *timestamp) {
- ALOG_ASSERT(timestamp != NULL);
-
- if (NULL == mStream)
- return INVALID_OPERATION;
-
- if (NULL == mStream->get_next_write_timestamp)
- return INVALID_OPERATION;
-
- return mStream->get_next_write_timestamp(mStream, timestamp);
-}
-
status_t AudioStreamOutSink::getTimestamp(AudioTimestamp& timestamp)
{
if (mStream->get_presentation_position == NULL) {
diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp
index 129e9ef..aef9834 100644
--- a/media/libnbaio/MonoPipe.cpp
+++ b/media/libnbaio/MonoPipe.cpp
@@ -19,10 +19,8 @@
#define LOG_TAG "MonoPipe"
//#define LOG_NDEBUG 0
-#include <common_time/cc_helper.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
-#include <utils/LinearTransform.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <media/AudioBufferProvider.h>
@@ -32,26 +30,8 @@
namespace android {
-static uint64_t cacheN; // output of CCHelper::getLocalFreq()
-static bool cacheValid; // whether cacheN is valid
-static pthread_once_t cacheOnceControl = PTHREAD_ONCE_INIT;
-
-static void cacheOnceInit()
-{
- CCHelper tmpHelper;
- status_t res;
- if (OK != (res = tmpHelper.getLocalFreq(&cacheN))) {
- ALOGE("Failed to fetch local time frequency when constructing a"
- " MonoPipe (res = %d). getNextWriteTimestamp calls will be"
- " non-functional", res);
- return;
- }
- cacheValid = true;
-}
-
MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) :
NBAIO_Sink(format),
- mUpdateSeq(0),
mReqFrames(reqFrames),
mMaxFrames(roundup(reqFrames)),
mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
@@ -66,36 +46,6 @@
mTimestampMutator(&mTimestampShared),
mTimestampObserver(&mTimestampShared)
{
- uint64_t N, D;
-
- mNextRdPTS = AudioBufferProvider::kInvalidPTS;
-
- mSamplesToLocalTime.a_zero = 0;
- mSamplesToLocalTime.b_zero = 0;
- mSamplesToLocalTime.a_to_b_numer = 0;
- mSamplesToLocalTime.a_to_b_denom = 0;
-
- D = Format_sampleRate(format);
-
- (void) pthread_once(&cacheOnceControl, cacheOnceInit);
- if (!cacheValid) {
- // log has already been done
- return;
- }
- N = cacheN;
-
- LinearTransform::reduce(&N, &D);
- static const uint64_t kSignedHiBitsMask = ~(0x7FFFFFFFull);
- static const uint64_t kUnsignedHiBitsMask = ~(0xFFFFFFFFull);
- if ((N & kSignedHiBitsMask) || (D & kUnsignedHiBitsMask)) {
- ALOGE("Cannot reduce sample rate to local clock frequency ratio to fit"
- " in a 32/32 bit rational. (max reduction is 0x%016" PRIx64 "/0x%016" PRIx64
- "). getNextWriteTimestamp calls will be non-functional", N, D);
- return;
- }
-
- mSamplesToLocalTime.a_to_b_numer = static_cast<int32_t>(N);
- mSamplesToLocalTime.a_to_b_denom = static_cast<uint32_t>(D);
}
MonoPipe::~MonoPipe()
@@ -223,104 +173,6 @@
mSetpoint = setpoint;
}
-status_t MonoPipe::getNextWriteTimestamp(int64_t *timestamp)
-{
- int32_t front;
-
- ALOG_ASSERT(NULL != timestamp);
-
- if (0 == mSamplesToLocalTime.a_to_b_denom)
- return UNKNOWN_ERROR;
-
- observeFrontAndNRPTS(&front, timestamp);
-
- if (AudioBufferProvider::kInvalidPTS != *timestamp) {
- // If we have a valid read-pointer and next read timestamp pair, then
- // use the current value of the write pointer to figure out how many
- // frames are in the buffer, and offset the timestamp by that amt. Then
- // next time we write to the MonoPipe, the data will hit the speakers at
- // the next read timestamp plus the current amount of data in the
- // MonoPipe.
- size_t pendingFrames = (mRear - front) & (mMaxFrames - 1);
- *timestamp = offsetTimestampByAudioFrames(*timestamp, pendingFrames);
- }
-
- return OK;
-}
-
-void MonoPipe::updateFrontAndNRPTS(int32_t newFront, int64_t newNextRdPTS)
-{
- // Set the MSB of the update sequence number to indicate that there is a
- // multi-variable update in progress. Use an atomic store with an "acquire"
- // barrier to make sure that the next operations cannot be re-ordered and
- // take place before the change to mUpdateSeq is commited..
- int32_t tmp = mUpdateSeq | 0x80000000;
- android_atomic_acquire_store(tmp, &mUpdateSeq);
-
- // Update mFront and mNextRdPTS
- mFront = newFront;
- mNextRdPTS = newNextRdPTS;
-
- // We are finished with the update. Compute the next sequnce number (which
- // should be the old sequence number, plus one, and with the MSB cleared)
- // and then store it in mUpdateSeq using an atomic store with a "release"
- // barrier so our update operations cannot be re-ordered past the update of
- // the sequence number.
- tmp = (tmp + 1) & 0x7FFFFFFF;
- android_atomic_release_store(tmp, &mUpdateSeq);
-}
-
-void MonoPipe::observeFrontAndNRPTS(int32_t *outFront, int64_t *outNextRdPTS)
-{
- // Perform an atomic observation of mFront and mNextRdPTS. Basically,
- // atomically observe the sequence number, then observer the variables, then
- // atomically observe the sequence number again. If the two observations of
- // the sequence number match, and the update-in-progress bit was not set,
- // then we know we have a successful atomic observation. Otherwise, we loop
- // around and try again.
- //
- // Note, it is very important that the observer be a lower priority thread
- // than the updater. If the updater is lower than the observer, or they are
- // the same priority and running with SCHED_FIFO (implying that quantum
- // based premption is disabled) then we run the risk of deadlock.
- int32_t seqOne, seqTwo;
-
- do {
- seqOne = android_atomic_acquire_load(&mUpdateSeq);
- *outFront = mFront;
- *outNextRdPTS = mNextRdPTS;
- seqTwo = android_atomic_release_load(&mUpdateSeq);
- } while ((seqOne != seqTwo) || (seqOne & 0x80000000));
-}
-
-int64_t MonoPipe::offsetTimestampByAudioFrames(int64_t ts, size_t audFrames)
-{
- if (0 == mSamplesToLocalTime.a_to_b_denom)
- return AudioBufferProvider::kInvalidPTS;
-
- if (ts == AudioBufferProvider::kInvalidPTS)
- return AudioBufferProvider::kInvalidPTS;
-
- int64_t frame_lt_duration;
- if (!mSamplesToLocalTime.doForwardTransform(audFrames,
- &frame_lt_duration)) {
- // This should never fail, but if there is a bug which is causing it
- // to fail, this message would probably end up flooding the logs
- // because the conversion would probably fail forever. Log the
- // error, but then zero out the ratio in the linear transform so
- // that we don't try to do any conversions from now on. This
- // MonoPipe's getNextWriteTimestamp is now broken for good.
- ALOGE("Overflow when attempting to convert %zu audio frames to"
- " duration in local time. getNextWriteTimestamp will fail from"
- " now on.", audFrames);
- mSamplesToLocalTime.a_to_b_numer = 0;
- mSamplesToLocalTime.a_to_b_denom = 0;
- return AudioBufferProvider::kInvalidPTS;
- }
-
- return ts + frame_lt_duration;
-}
-
void MonoPipe::shutdown(bool newState)
{
mIsShutdown = newState;
diff --git a/media/libnbaio/MonoPipeReader.cpp b/media/libnbaio/MonoPipeReader.cpp
index e4d3ed8..7e09544 100644
--- a/media/libnbaio/MonoPipeReader.cpp
+++ b/media/libnbaio/MonoPipeReader.cpp
@@ -43,25 +43,11 @@
return ret;
}
-ssize_t MonoPipeReader::read(void *buffer, size_t count, int64_t readPTS)
+ssize_t MonoPipeReader::read(void *buffer, size_t count)
{
- // Compute the "next read PTS" and cache it. Callers of read pass a read
- // PTS indicating the local time for which they are requesting data along
- // with a count (which is the number of audio frames they are going to
- // ultimately pass to the next stage of the pipeline). Offsetting readPTS
- // by the duration of count will give us the readPTS which will be passed to
- // us next time, assuming they system continues to operate in steady state
- // with no discontinuities. We stash this value so it can be used by the
- // MonoPipe writer to imlement getNextWriteTimestamp.
- int64_t nextReadPTS;
- nextReadPTS = mPipe->offsetTimestampByAudioFrames(readPTS, count);
-
// count == 0 is unlikely and not worth checking for explicitly; will be handled automatically
ssize_t red = availableToRead();
if (CC_UNLIKELY(red <= 0)) {
- // Uh-oh, looks like we are underflowing. Update the next read PTS and
- // get out.
- mPipe->updateFrontAndNRPTS(mPipe->mFront, nextReadPTS);
return red;
}
if (CC_LIKELY((size_t) red > count)) {
@@ -80,7 +66,7 @@
memcpy((char *) buffer + (part1 * mFrameSize), mPipe->mBuffer, part2 * mFrameSize);
}
}
- mPipe->updateFrontAndNRPTS(red + mPipe->mFront, nextReadPTS);
+ android_atomic_release_store(red + mPipe->mFront, &mPipe->mFront);
mFramesRead += red;
}
return red;
diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp
index d641e74..1cb4410 100644
--- a/media/libnbaio/NBAIO.cpp
+++ b/media/libnbaio/NBAIO.cpp
@@ -97,8 +97,7 @@
}
// This is a default implementation; it is expected that subclasses will optimize this.
-ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user,
- int64_t readPTS, size_t block)
+ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, size_t block)
{
if (!mNegotiated) {
return (ssize_t) NEGOTIATE;
@@ -117,11 +116,11 @@
if (count > block) {
count = block;
}
- ssize_t ret = read(buffer, count, readPTS);
+ ssize_t ret = read(buffer, count);
if (ret > 0) {
ALOG_ASSERT((size_t) ret <= count);
size_t maxRet = ret;
- ret = via(user, buffer, maxRet, readPTS);
+ ret = via(user, buffer, maxRet);
if (ret > 0) {
ALOG_ASSERT((size_t) ret <= maxRet);
accumulator += ret;
diff --git a/media/libnbaio/PipeReader.cpp b/media/libnbaio/PipeReader.cpp
index c8e4953..b096903 100644
--- a/media/libnbaio/PipeReader.cpp
+++ b/media/libnbaio/PipeReader.cpp
@@ -59,7 +59,7 @@
return avail;
}
-ssize_t PipeReader::read(void *buffer, size_t count, int64_t readPTS __unused)
+ssize_t PipeReader::read(void *buffer, size_t count)
{
ssize_t avail = availableToRead();
if (CC_UNLIKELY(avail <= 0)) {
diff --git a/media/libnbaio/SourceAudioBufferProvider.cpp b/media/libnbaio/SourceAudioBufferProvider.cpp
index e21ef48..dc01c0e 100644
--- a/media/libnbaio/SourceAudioBufferProvider.cpp
+++ b/media/libnbaio/SourceAudioBufferProvider.cpp
@@ -45,7 +45,7 @@
free(mAllocated);
}
-status_t SourceAudioBufferProvider::getNextBuffer(Buffer *buffer, int64_t pts)
+status_t SourceAudioBufferProvider::getNextBuffer(Buffer *buffer)
{
ALOG_ASSERT(buffer != NULL && buffer->frameCount > 0 && mGetCount == 0);
// any leftover data available?
@@ -61,20 +61,30 @@
// do we need to reallocate?
if (buffer->frameCount > mSize) {
free(mAllocated);
- mAllocated = malloc(buffer->frameCount * mFrameSize);
+ // Android convention is to _not_ check the return value of malloc and friends.
+ // But in this case the calloc() can also fail due to integer overflow,
+ // so we check and recover.
+ mAllocated = calloc(buffer->frameCount, mFrameSize);
+ if (mAllocated == NULL) {
+ mSize = 0;
+ goto fail;
+ }
mSize = buffer->frameCount;
}
- // read from source
- ssize_t actual = mSource->read(mAllocated, buffer->frameCount, pts);
- if (actual > 0) {
- ALOG_ASSERT((size_t) actual <= buffer->frameCount);
- mOffset = 0;
- mRemaining = actual;
- buffer->raw = mAllocated;
- buffer->frameCount = actual;
- mGetCount = actual;
- return OK;
+ {
+ // read from source
+ ssize_t actual = mSource->read(mAllocated, buffer->frameCount);
+ if (actual > 0) {
+ ALOG_ASSERT((size_t) actual <= buffer->frameCount);
+ mOffset = 0;
+ mRemaining = actual;
+ buffer->raw = mAllocated;
+ buffer->frameCount = actual;
+ mGetCount = actual;
+ return OK;
+ }
}
+fail:
buffer->raw = NULL;
buffer->frameCount = 0;
mGetCount = 0;
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 45e8a30..19efc53 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -211,7 +211,7 @@
return mInitCheck == OK ? 1 : 0;
}
-sp<MediaSource> AACExtractor::getTrack(size_t index) {
+sp<IMediaSource> AACExtractor::getTrack(size_t index) {
if (mInitCheck != OK || index != 0) {
return NULL;
}
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 9d90dbd..8b1e1c3 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -67,7 +67,7 @@
}
-status_t AACWriter::addSource(const sp<MediaSource> &source) {
+status_t AACWriter::addSource(const sp<IMediaSource> &source) {
if (mInitCheck != OK) {
return mInitCheck;
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 8d9bd21..ee573f0 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -41,7 +41,6 @@
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/PersistentSurface.h>
#include <media/stagefright/SurfaceUtils.h>
#include <media/hardware/HardwareAPI.h>
@@ -56,6 +55,10 @@
namespace android {
+enum {
+ kMaxIndicesToCheck = 32, // used when enumerating supported formats and profiles
+};
+
// OMX errors are directly mapped into status_t range if
// there is no corresponding MediaError status code.
// Use the statusFromOMXError(int32_t omxError) function.
@@ -808,6 +811,10 @@
def.nBufferCountActual, bufSize, allottedSize, def.nBufferSize, asString(type),
portIndex == kPortIndexInput ? "input" : "output");
+ if (bufSize == 0 || def.nBufferCountActual > SIZE_MAX / bufSize) {
+ ALOGE("b/22885421");
+ return NO_MEMORY;
+ }
size_t totalSize = def.nBufferCountActual * bufSize;
mDealer[portIndex] = new MemoryDealer(totalSize, "ACodec");
@@ -821,22 +828,32 @@
info.mStatus = BufferInfo::OWNED_BY_US;
info.mFenceFd = -1;
info.mRenderInfo = NULL;
+ info.mNativeHandle = NULL;
uint32_t requiresAllocateBufferBit =
(portIndex == kPortIndexInput)
- ? OMXCodec::kRequiresAllocateBufferOnInputPorts
- : OMXCodec::kRequiresAllocateBufferOnOutputPorts;
+ ? kRequiresAllocateBufferOnInputPorts
+ : kRequiresAllocateBufferOnOutputPorts;
- if ((portIndex == kPortIndexInput && (mFlags & kFlagIsSecure))
- || (portIndex == kPortIndexOutput && usingMetadataOnEncoderOutput())) {
+ if (portIndex == kPortIndexInput && (mFlags & kFlagIsSecure)) {
mem.clear();
- void *ptr;
- err = mOMX->allocateBuffer(
+ void *ptr = NULL;
+ native_handle_t *native_handle = NULL;
+ err = mOMX->allocateSecureBuffer(
mNode, portIndex, bufSize, &info.mBufferID,
- &ptr);
+ &ptr, &native_handle);
- info.mData = new ABuffer(ptr, bufSize);
+ // TRICKY: this representation is unorthodox, but ACodec requires
+ // an ABuffer with a proper size to validate range offsets and lengths.
+ // Since mData is never referenced for secure input, it is used to store
+ // either the pointer to the secure buffer, or the opaque handle as on
+ // some devices ptr is actually an opaque handle, not a pointer.
+
+ // TRICKY2: use native handle as the base of the ABuffer if received one,
+ // because Widevine source only receives these base addresses.
+ info.mData = new ABuffer(ptr != NULL ? ptr : (void *)native_handle, bufSize);
+ info.mNativeHandle = NativeHandle::create(native_handle, true /* ownsHandle */);
} else if (mQuirks & requiresAllocateBufferBit) {
err = mOMX->allocateBufferWithBackup(
mNode, portIndex, mem, &info.mBufferID, allottedSize);
@@ -849,6 +866,7 @@
if (type == kMetadataBufferTypeANWBuffer) {
((VideoNativeMetadata *)mem->pointer())->nFenceFd = -1;
}
+ info.mMemRef = mem;
}
mBuffers[portIndex].push(info);
@@ -869,8 +887,7 @@
for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
const BufferInfo &info = mBuffers[portIndex][i];
-
- desc->addBuffer(info.mBufferID, info.mData);
+ desc->addBuffer(info.mBufferID, info.mData, info.mNativeHandle, info.mMemRef);
}
notify->setObject("portDesc", desc);
@@ -1130,7 +1147,7 @@
// we use useBuffer for metadata regardless of quirks
err = mOMX->useBuffer(
mNode, kPortIndexOutput, mem, &info.mBufferID, mem->size());
-
+ info.mMemRef = mem;
mBuffers[kPortIndexOutput].push(info);
ALOGV("[%s] allocated meta buffer with ID %u (pointer = %p)",
@@ -1327,7 +1344,8 @@
}
bool stale = false;
- for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) {
+ for (size_t i = mBuffers[kPortIndexOutput].size(); i > 0;) {
+ i--;
BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i);
if (info->mGraphicBuffer != NULL &&
@@ -1370,7 +1388,8 @@
// get oldest undequeued buffer
BufferInfo *oldest = NULL;
- for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) {
+ for (size_t i = mBuffers[kPortIndexOutput].size(); i > 0;) {
+ i--;
BufferInfo *info =
&mBuffers[kPortIndexOutput].editItemAt(i);
if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW &&
@@ -1523,6 +1542,21 @@
status_t ACodec::setComponentRole(
bool isEncoder, const char *mime) {
+ const char *role = getComponentRole(isEncoder, mime);
+ if (role == NULL) {
+ return BAD_VALUE;
+ }
+ status_t err = setComponentRole(mOMX, mNode, role);
+ if (err != OK) {
+ ALOGW("[%s] Failed to set standard component role '%s'.",
+ mComponentName.c_str(), role);
+ }
+ return err;
+}
+
+//static
+const char *ACodec::getComponentRole(
+ bool isEncoder, const char *mime) {
struct MimeToRole {
const char *mime;
const char *decoderRole;
@@ -1564,6 +1598,8 @@
"video_decoder.vp9", "video_encoder.vp9" },
{ MEDIA_MIMETYPE_AUDIO_RAW,
"audio_decoder.raw", "audio_encoder.raw" },
+ { MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
+ "video_decoder.dolby-vision", "video_encoder.dolby-vision" },
{ MEDIA_MIMETYPE_AUDIO_FLAC,
"audio_decoder.flac", "audio_encoder.flac" },
{ MEDIA_MIMETYPE_AUDIO_MSGSM,
@@ -1587,35 +1623,27 @@
}
if (i == kNumMimeToRole) {
- return ERROR_UNSUPPORTED;
+ return NULL;
}
- const char *role =
- isEncoder ? kMimeToRole[i].encoderRole
+ return isEncoder ? kMimeToRole[i].encoderRole
: kMimeToRole[i].decoderRole;
+}
- if (role != NULL) {
- OMX_PARAM_COMPONENTROLETYPE roleParams;
- InitOMXParams(&roleParams);
+//static
+status_t ACodec::setComponentRole(
+ const sp<IOMX> &omx, IOMX::node_id node, const char *role) {
+ OMX_PARAM_COMPONENTROLETYPE roleParams;
+ InitOMXParams(&roleParams);
- strncpy((char *)roleParams.cRole,
- role, OMX_MAX_STRINGNAME_SIZE - 1);
+ strncpy((char *)roleParams.cRole,
+ role, OMX_MAX_STRINGNAME_SIZE - 1);
- roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+ roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
- status_t err = mOMX->setParameter(
- mNode, OMX_IndexParamStandardComponentRole,
- &roleParams, sizeof(roleParams));
-
- if (err != OK) {
- ALOGW("[%s] Failed to set standard component role '%s'.",
- mComponentName.c_str(), role);
-
- return err;
- }
- }
-
- return OK;
+ return omx->setParameter(
+ node, OMX_IndexParamStandardComponentRole,
+ &roleParams, sizeof(roleParams));
}
status_t ACodec::configureCodec(
@@ -1757,6 +1785,14 @@
mFlags |= kFlagIsGrallocUsageProtected;
mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown;
}
+
+ if (mFlags & kFlagIsSecure) {
+ // use native_handles for secure input buffers
+ err = mOMX->enableNativeBuffers(
+ mNode, kPortIndexInput, OMX_FALSE /* graphic */, OMX_TRUE);
+ ALOGI_IF(err != OK, "falling back to non-native_handles");
+ err = OK; // ignore error for now
+ }
}
if (haveNativeWindow) {
sp<ANativeWindow> nativeWindow =
@@ -1968,7 +2004,8 @@
inputFormat->setInt32("adaptive-playback", false);
}
if (err == OK) {
- err = mOMX->enableGraphicBuffers(mNode, kPortIndexOutput, OMX_FALSE);
+ err = mOMX->enableNativeBuffers(
+ mNode, kPortIndexOutput, OMX_TRUE /* graphic */, OMX_FALSE);
}
if (mFlags & kFlagIsGrallocUsageProtected) {
// fallback is not supported for protected playback
@@ -2224,6 +2261,102 @@
return OK;
}
+status_t ACodec::getIntraRefreshPeriod(uint32_t *intraRefreshPeriod) {
+ OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE params;
+ InitOMXParams(¶ms);
+ params.nPortIndex = kPortIndexOutput;
+ status_t err = mOMX->getConfig(
+ mNode, (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh, ¶ms, sizeof(params));
+ if (err == OK) {
+ *intraRefreshPeriod = params.nRefreshPeriod;
+ return OK;
+ }
+
+ // Fallback to query through standard OMX index.
+ OMX_VIDEO_PARAM_INTRAREFRESHTYPE refreshParams;
+ InitOMXParams(&refreshParams);
+ refreshParams.nPortIndex = kPortIndexOutput;
+ refreshParams.eRefreshMode = OMX_VIDEO_IntraRefreshCyclic;
+ err = mOMX->getParameter(
+ mNode, OMX_IndexParamVideoIntraRefresh, &refreshParams, sizeof(refreshParams));
+ if (err != OK || refreshParams.nCirMBs == 0) {
+ *intraRefreshPeriod = 0;
+ return OK;
+ }
+
+ // Calculate period based on width and height
+ uint32_t width, height;
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+ def.nPortIndex = kPortIndexOutput;
+ err = mOMX->getParameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ if (err != OK) {
+ *intraRefreshPeriod = 0;
+ return err;
+ }
+ width = video_def->nFrameWidth;
+ height = video_def->nFrameHeight;
+ // Use H.264/AVC MacroBlock size 16x16
+ *intraRefreshPeriod = divUp((divUp(width, 16u) * divUp(height, 16u)), refreshParams.nCirMBs);
+
+ return OK;
+}
+
+status_t ACodec::setIntraRefreshPeriod(uint32_t intraRefreshPeriod, bool inConfigure) {
+ OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE params;
+ InitOMXParams(¶ms);
+ params.nPortIndex = kPortIndexOutput;
+ params.nRefreshPeriod = intraRefreshPeriod;
+ status_t err = mOMX->setConfig(
+ mNode, (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh, ¶ms, sizeof(params));
+ if (err == OK) {
+ return OK;
+ }
+
+ // Only in configure state, a component could invoke setParameter.
+ if (!inConfigure) {
+ return INVALID_OPERATION;
+ } else {
+ ALOGI("[%s] try falling back to Cyclic", mComponentName.c_str());
+ }
+
+ OMX_VIDEO_PARAM_INTRAREFRESHTYPE refreshParams;
+ InitOMXParams(&refreshParams);
+ refreshParams.nPortIndex = kPortIndexOutput;
+ refreshParams.eRefreshMode = OMX_VIDEO_IntraRefreshCyclic;
+
+ if (intraRefreshPeriod == 0) {
+ // 0 means disable intra refresh.
+ refreshParams.nCirMBs = 0;
+ } else {
+ // Calculate macroblocks that need to be intra coded base on width and height
+ uint32_t width, height;
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+ def.nPortIndex = kPortIndexOutput;
+ err = mOMX->getParameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ if (err != OK) {
+ return err;
+ }
+ width = video_def->nFrameWidth;
+ height = video_def->nFrameHeight;
+ // Use H.264/AVC MacroBlock size 16x16
+ refreshParams.nCirMBs = divUp((divUp(width, 16u) * divUp(height, 16u)), intraRefreshPeriod);
+ }
+
+ err = mOMX->setParameter(mNode, OMX_IndexParamVideoIntraRefresh,
+ &refreshParams, sizeof(refreshParams));
+ if (err != OK) {
+ return err;
+ }
+
+ return OK;
+}
+
status_t ACodec::setMinBufferSize(OMX_U32 portIndex, size_t size) {
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
@@ -2270,9 +2403,8 @@
InitOMXParams(&format);
format.nPortIndex = portIndex;
- for (OMX_U32 index = 0;; ++index) {
+ for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
format.nIndex = index;
-
status_t err = mOMX->getParameter(
mNode, OMX_IndexParamAudioPortFormat,
&format, sizeof(format));
@@ -2284,6 +2416,13 @@
if (format.eEncoding == desiredFormat) {
break;
}
+
+ if (index == kMaxIndicesToCheck) {
+ ALOGW("[%s] stopping checking formats after %u: %s(%x)",
+ mComponentName.c_str(), index,
+ asString(format.eEncoding), format.eEncoding);
+ return ERROR_UNSUPPORTED;
+ }
}
return mOMX->setParameter(
@@ -2703,8 +2842,7 @@
format.nIndex = 0;
bool found = false;
- OMX_U32 index = 0;
- for (;;) {
+ for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
format.nIndex = index;
status_t err = mOMX->getParameter(
mNode, OMX_IndexParamVideoPortFormat,
@@ -2749,7 +2887,12 @@
break;
}
- ++index;
+ if (index == kMaxIndicesToCheck) {
+ ALOGW("[%s] stopping checking formats after %u: %s(%x)/%s(%x)",
+ mComponentName.c_str(), index,
+ asString(format.eCompressionFormat), format.eCompressionFormat,
+ asString(format.eColorFormat), format.eColorFormat);
+ }
}
if (!found) {
@@ -2839,6 +2982,7 @@
{ MEDIA_MIMETYPE_VIDEO_MPEG2, OMX_VIDEO_CodingMPEG2 },
{ MEDIA_MIMETYPE_VIDEO_VP8, OMX_VIDEO_CodingVP8 },
{ MEDIA_MIMETYPE_VIDEO_VP9, OMX_VIDEO_CodingVP9 },
+ { MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, OMX_VIDEO_CodingDolbyVision },
};
static status_t GetVideoCodingTypeFromMime(
@@ -3074,6 +3218,17 @@
return err;
}
+ int32_t intraRefreshPeriod = 0;
+ if (msg->findInt32("intra-refresh-period", &intraRefreshPeriod)
+ && intraRefreshPeriod >= 0) {
+ err = setIntraRefreshPeriod((uint32_t)intraRefreshPeriod, true);
+ if (err != OK) {
+ ALOGI("[%s] failed setIntraRefreshPeriod. Failure is fine since this key is optional",
+ mComponentName.c_str());
+ err = OK;
+ }
+ }
+
switch (compressionFormat) {
case OMX_VIDEO_CodingMPEG4:
err = setupMPEG4EncoderParameters(msg);
@@ -3524,8 +3679,8 @@
hevcType.eProfile = static_cast<OMX_VIDEO_HEVCPROFILETYPE>(profile);
hevcType.eLevel = static_cast<OMX_VIDEO_HEVCLEVELTYPE>(level);
}
-
- // TODO: Need OMX structure definition for setting iFrameInterval
+ // TODO: finer control?
+ hevcType.nKeyFrameInterval = setPFramesSpacing(iFrameInterval, frameRate);
err = mOMX->setParameter(
mNode, (OMX_INDEXTYPE)OMX_IndexParamVideoHevc, &hevcType, sizeof(hevcType));
@@ -3622,7 +3777,8 @@
InitOMXParams(¶ms);
params.nPortIndex = kPortIndexOutput;
- for (params.nProfileIndex = 0;; ++params.nProfileIndex) {
+ for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
+ params.nProfileIndex = index;
status_t err = mOMX->getParameter(
mNode,
OMX_IndexParamVideoProfileLevelQuerySupported,
@@ -3639,7 +3795,14 @@
if (profile == supportedProfile && level <= supportedLevel) {
return OK;
}
+
+ if (index == kMaxIndicesToCheck) {
+ ALOGW("[%s] stopping checking profiles after %u: %x/%x",
+ mComponentName.c_str(), index,
+ params.eProfile, params.eLevel);
+ }
}
+ return ERROR_UNSUPPORTED;
}
status_t ACodec::configureBitrate(
@@ -3736,10 +3899,10 @@
status_t ACodec::initNativeWindow() {
if (mNativeWindow != NULL) {
- return mOMX->enableGraphicBuffers(mNode, kPortIndexOutput, OMX_TRUE);
+ return mOMX->enableNativeBuffers(mNode, kPortIndexOutput, OMX_TRUE /* graphic */, OMX_TRUE);
}
- mOMX->enableGraphicBuffers(mNode, kPortIndexOutput, OMX_FALSE);
+ mOMX->enableNativeBuffers(mNode, kPortIndexOutput, OMX_TRUE /* graphic */, OMX_FALSE);
return OK;
}
@@ -3838,7 +4001,7 @@
fmt != OMX_COLOR_FormatYUV420PackedPlanar &&
fmt != OMX_COLOR_FormatYUV420SemiPlanar &&
fmt != OMX_COLOR_FormatYUV420PackedSemiPlanar &&
- fmt != HAL_PIXEL_FORMAT_YV12) {
+ fmt != (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_YV12) {
ALOGW("do not know color format 0x%x = %d", fmt, fmt);
return false;
}
@@ -3850,8 +4013,11 @@
params.nSliceHeight = params.nFrameHeight;
}
- // we need stride and slice-height to be non-zero
- if (params.nStride == 0 || params.nSliceHeight == 0) {
+ // we need stride and slice-height to be non-zero and sensible. These values were chosen to
+ // prevent integer overflows further down the line, and do not indicate support for
+ // 32kx32k video.
+ if (params.nStride == 0 || params.nSliceHeight == 0
+ || params.nStride > 32768 || params.nSliceHeight > 32768) {
ALOGW("cannot describe color format 0x%x = %d with stride=%u and sliceHeight=%u",
fmt, fmt, params.nStride, params.nSliceHeight);
return false;
@@ -4148,6 +4314,11 @@
} else {
notify->setString("mime", mime.c_str());
}
+ uint32_t intraRefreshPeriod = 0;
+ if (mIsEncoder && getIntraRefreshPeriod(&intraRefreshPeriod) == OK
+ && intraRefreshPeriod > 0) {
+ notify->setInt32("intra-refresh-period", intraRefreshPeriod);
+ }
break;
}
}
@@ -4436,16 +4607,13 @@
(mEncoderDelay || mEncoderPadding)) {
int32_t channelCount;
CHECK(notify->findInt32("channel-count", &channelCount));
- size_t frameSize = channelCount * sizeof(int16_t);
if (mSkipCutBuffer != NULL) {
size_t prevbufsize = mSkipCutBuffer->size();
if (prevbufsize != 0) {
ALOGW("Replacing SkipCutBuffer holding %zu bytes", prevbufsize);
}
}
- mSkipCutBuffer = new SkipCutBuffer(
- mEncoderDelay * frameSize,
- mEncoderPadding * frameSize);
+ mSkipCutBuffer = new SkipCutBuffer(mEncoderDelay, mEncoderPadding, channelCount);
}
notify->post();
@@ -4498,9 +4666,12 @@
}
void ACodec::PortDescription::addBuffer(
- IOMX::buffer_id id, const sp<ABuffer> &buffer) {
+ IOMX::buffer_id id, const sp<ABuffer> &buffer,
+ const sp<NativeHandle> &handle, const sp<RefBase> &memRef) {
mBufferIDs.push_back(id);
mBuffers.push_back(buffer);
+ mHandles.push_back(handle);
+ mMemRefs.push_back(memRef);
}
size_t ACodec::PortDescription::countBuffers() {
@@ -4515,6 +4686,14 @@
return mBuffers.itemAt(index);
}
+sp<NativeHandle> ACodec::PortDescription::handleAt(size_t index) const {
+ return mHandles.itemAt(index);
+}
+
+sp<RefBase> ACodec::PortDescription::memRefAt(size_t index) const {
+ return mMemRefs.itemAt(index);
+}
+
////////////////////////////////////////////////////////////////////////////////
ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
@@ -5362,7 +5541,7 @@
ALOGV("Now uninitialized");
if (mDeathNotifier != NULL) {
- IInterface::asBinder(mCodec->mOMX)->unlinkToDeath(mDeathNotifier);
+ mCodec->mNodeBinder->unlinkToDeath(mDeathNotifier);
mDeathNotifier.clear();
}
@@ -5459,14 +5638,7 @@
sp<AMessage> notify = new AMessage(kWhatOMXDied, mCodec);
- mDeathNotifier = new DeathNotifier(notify);
- if (IInterface::asBinder(omx)->linkToDeath(mDeathNotifier) != OK) {
- // This was a local binder, if it dies so do we, we won't care
- // about any notifications in the afterlife.
- mDeathNotifier.clear();
- }
-
- Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs;
+ Vector<AString> matchingCodecs;
AString mime;
@@ -5474,13 +5646,9 @@
uint32_t quirks = 0;
int32_t encoder = false;
if (msg->findString("componentName", &componentName)) {
- ssize_t index = matchingCodecs.add();
- OMXCodec::CodecNameAndQuirks *entry = &matchingCodecs.editItemAt(index);
- entry->mName = String8(componentName.c_str());
-
- if (!OMXCodec::findCodecQuirks(
- componentName.c_str(), &entry->mQuirks)) {
- entry->mQuirks = 0;
+ sp<IMediaCodecList> list = MediaCodecList::getInstance();
+ if (list != NULL && list->findCodecByName(componentName.c_str()) >= 0) {
+ matchingCodecs.add(componentName);
}
} else {
CHECK(msg->findString("mime", &mime));
@@ -5489,11 +5657,10 @@
encoder = false;
}
- OMXCodec::findMatchingCodecs(
+ MediaCodecList::findMatchingCodecs(
mime.c_str(),
encoder, // createEncoder
- NULL, // matchComponentName
- 0, // flags
+ 0, // flags
&matchingCodecs);
}
@@ -5503,13 +5670,13 @@
status_t err = NAME_NOT_FOUND;
for (size_t matchIndex = 0; matchIndex < matchingCodecs.size();
++matchIndex) {
- componentName = matchingCodecs.itemAt(matchIndex).mName.string();
- quirks = matchingCodecs.itemAt(matchIndex).mQuirks;
+ componentName = matchingCodecs[matchIndex];
+ quirks = MediaCodecList::getQuirksFor(componentName.c_str());
pid_t tid = gettid();
int prevPriority = androidGetThreadPriority(tid);
androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
- err = omx->allocateNode(componentName.c_str(), observer, &node);
+ err = omx->allocateNode(componentName.c_str(), observer, &mCodec->mNodeBinder, &node);
androidSetThreadPriority(tid, prevPriority);
if (err == OK) {
@@ -5533,6 +5700,14 @@
return false;
}
+ mDeathNotifier = new DeathNotifier(notify);
+ if (mCodec->mNodeBinder == NULL ||
+ mCodec->mNodeBinder->linkToDeath(mDeathNotifier) != OK) {
+ // This was a local binder, if it dies so do we, we won't care
+ // about any notifications in the afterlife.
+ mDeathNotifier.clear();
+ }
+
notify = new AMessage(kWhatOMXMessageList, mCodec);
observer->setNotificationMessage(notify);
@@ -5892,6 +6067,15 @@
mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
+ mCodec->mOMX->sendCommand(
+ mCodec->mNode, OMX_CommandStateSet, OMX_StateLoaded);
+ if (mCodec->allYourBuffersAreBelongToUs(kPortIndexInput)) {
+ mCodec->freeBuffersOnPort(kPortIndexInput);
+ }
+ if (mCodec->allYourBuffersAreBelongToUs(kPortIndexOutput)) {
+ mCodec->freeBuffersOnPort(kPortIndexOutput);
+ }
+
mCodec->changeState(mCodec->mLoadedState);
}
}
@@ -6345,6 +6529,17 @@
}
}
+ int32_t intraRefreshPeriod = 0;
+ if (params->findInt32("intra-refresh-period", &intraRefreshPeriod)
+ && intraRefreshPeriod > 0) {
+ status_t err = setIntraRefreshPeriod(intraRefreshPeriod, false);
+ if (err != OK) {
+ ALOGI("[%s] failed setIntraRefreshPeriod. Failure is fine since this key is optional",
+ mComponentName.c_str());
+ err = OK;
+ }
+ }
+
return OK;
}
@@ -6381,7 +6576,8 @@
mCodec->freeOutputBuffersNotOwnedByComponent();
mCodec->changeState(mCodec->mOutputPortSettingsChangedState);
- } else if (data2 == OMX_IndexConfigCommonOutputCrop) {
+ } else if (data2 == OMX_IndexConfigCommonOutputCrop
+ || data2 == OMX_IndexConfigAndroidIntraRefresh) {
mCodec->mSentFormat = false;
if (mCodec->mTunneled) {
@@ -6864,4 +7060,230 @@
}
}
+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());
+ if (role == NULL) {
+ return BAD_VALUE;
+ }
+
+ OMXClient client;
+ status_t err = client.connect();
+ if (err != OK) {
+ return err;
+ }
+
+ sp<IOMX> omx = client.interface();
+ sp<CodecObserver> observer = new CodecObserver;
+ IOMX::node_id node = 0;
+
+ err = omx->allocateNode(name.c_str(), observer, NULL, &node);
+ if (err != OK) {
+ client.disconnect();
+ return err;
+ }
+
+ err = setComponentRole(omx, node, role);
+ if (err != OK) {
+ omx->freeNode(node);
+ client.disconnect();
+ return err;
+ }
+
+ sp<MediaCodecInfo::CapabilitiesBuilder> builder = new MediaCodecInfo::CapabilitiesBuilder();
+ bool isVideo = mime.startsWithIgnoreCase("video/");
+
+ if (isVideo) {
+ OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
+ InitOMXParams(¶m);
+ param.nPortIndex = isEncoder ? kPortIndexOutput : kPortIndexInput;
+
+ for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
+ param.nProfileIndex = index;
+ status_t err = omx->getParameter(
+ node, OMX_IndexParamVideoProfileLevelQuerySupported,
+ ¶m, sizeof(param));
+ if (err != OK) {
+ break;
+ }
+ builder->addProfileLevel(param.eProfile, param.eLevel);
+
+ if (index == kMaxIndicesToCheck) {
+ ALOGW("[%s] stopping checking profiles after %u: %x/%x",
+ name.c_str(), index,
+ param.eProfile, param.eLevel);
+ }
+ }
+
+ // Color format query
+ // return colors in the order reported by the OMX component
+ // prefix "flexible" standard ones with the flexible equivalent
+ 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 = omx->getParameter(
+ node, OMX_IndexParamVideoPortFormat,
+ &portFormat, sizeof(portFormat));
+ if (err != OK) {
+ break;
+ }
+
+ OMX_U32 flexibleEquivalent;
+ if (isFlexibleColorFormat(
+ omx, node, 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);
+ }
+ }
+ supportedColors.push(portFormat.eColorFormat);
+ builder->addColorFormat(portFormat.eColorFormat);
+
+ if (index == kMaxIndicesToCheck) {
+ ALOGW("[%s] stopping checking formats after %u: %s(%x)",
+ name.c_str(), index,
+ asString(portFormat.eColorFormat), portFormat.eColorFormat);
+ }
+ }
+ } else if (mime.equalsIgnoreCase(MEDIA_MIMETYPE_AUDIO_AAC)) {
+ // More audio codecs if they have profiles.
+ OMX_AUDIO_PARAM_ANDROID_PROFILETYPE param;
+ InitOMXParams(¶m);
+ param.nPortIndex = isEncoder ? kPortIndexOutput : kPortIndexInput;
+ for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
+ param.nProfileIndex = index;
+ status_t err = omx->getParameter(
+ node, (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported,
+ ¶m, sizeof(param));
+ if (err != OK) {
+ break;
+ }
+ // For audio, level is ignored.
+ builder->addProfileLevel(param.eProfile, 0 /* level */);
+
+ if (index == kMaxIndicesToCheck) {
+ ALOGW("[%s] stopping checking profiles after %u: %x",
+ name.c_str(), index,
+ param.eProfile);
+ }
+ }
+
+ // 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());
+ }
+ }
+
+ if (isVideo && !isEncoder) {
+ native_handle_t *sidebandHandle = NULL;
+ if (omx->configureVideoTunnelMode(
+ node, kPortIndexOutput, OMX_TRUE, 0, &sidebandHandle) == OK) {
+ // tunneled playback includes adaptive playback
+ builder->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback
+ | MediaCodecInfo::Capabilities::kFlagSupportsTunneledPlayback);
+ } else if (omx->storeMetaDataInBuffers(
+ node, kPortIndexOutput, OMX_TRUE) == OK ||
+ omx->prepareForAdaptivePlayback(
+ node, kPortIndexOutput, OMX_TRUE,
+ 1280 /* width */, 720 /* height */) == OK) {
+ builder->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback);
+ }
+ }
+
+ if (isVideo && isEncoder) {
+ OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE params;
+ InitOMXParams(¶ms);
+ params.nPortIndex = kPortIndexOutput;
+ // TODO: should we verify if fallback is supported?
+ if (omx->getConfig(
+ node, (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh,
+ ¶ms, sizeof(params)) == OK) {
+ builder->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsIntraRefresh);
+ }
+ }
+
+ *caps = builder;
+ omx->freeNode(node);
+ client.disconnect();
+ return OK;
+}
+
+// These are supposed be equivalent to the logic in
+// "audio_channel_out_mask_from_count".
+//static
+status_t ACodec::getOMXChannelMapping(size_t numChannels, OMX_AUDIO_CHANNELTYPE map[]) {
+ switch (numChannels) {
+ case 1:
+ map[0] = OMX_AUDIO_ChannelCF;
+ break;
+ case 2:
+ map[0] = OMX_AUDIO_ChannelLF;
+ map[1] = OMX_AUDIO_ChannelRF;
+ break;
+ case 3:
+ map[0] = OMX_AUDIO_ChannelLF;
+ map[1] = OMX_AUDIO_ChannelRF;
+ map[2] = OMX_AUDIO_ChannelCF;
+ break;
+ case 4:
+ map[0] = OMX_AUDIO_ChannelLF;
+ map[1] = OMX_AUDIO_ChannelRF;
+ map[2] = OMX_AUDIO_ChannelLR;
+ map[3] = OMX_AUDIO_ChannelRR;
+ break;
+ case 5:
+ map[0] = OMX_AUDIO_ChannelLF;
+ map[1] = OMX_AUDIO_ChannelRF;
+ map[2] = OMX_AUDIO_ChannelCF;
+ map[3] = OMX_AUDIO_ChannelLR;
+ map[4] = OMX_AUDIO_ChannelRR;
+ break;
+ case 6:
+ map[0] = OMX_AUDIO_ChannelLF;
+ map[1] = OMX_AUDIO_ChannelRF;
+ map[2] = OMX_AUDIO_ChannelCF;
+ map[3] = OMX_AUDIO_ChannelLFE;
+ map[4] = OMX_AUDIO_ChannelLR;
+ map[5] = OMX_AUDIO_ChannelRR;
+ break;
+ case 7:
+ map[0] = OMX_AUDIO_ChannelLF;
+ map[1] = OMX_AUDIO_ChannelRF;
+ map[2] = OMX_AUDIO_ChannelCF;
+ map[3] = OMX_AUDIO_ChannelLFE;
+ map[4] = OMX_AUDIO_ChannelLR;
+ map[5] = OMX_AUDIO_ChannelRR;
+ map[6] = OMX_AUDIO_ChannelCS;
+ break;
+ case 8:
+ map[0] = OMX_AUDIO_ChannelLF;
+ map[1] = OMX_AUDIO_ChannelRF;
+ map[2] = OMX_AUDIO_ChannelCF;
+ map[3] = OMX_AUDIO_ChannelLFE;
+ map[4] = OMX_AUDIO_ChannelLR;
+ map[5] = OMX_AUDIO_ChannelRR;
+ map[6] = OMX_AUDIO_ChannelLS;
+ map[7] = OMX_AUDIO_ChannelRS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return OK;
+}
+
} // namespace android
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index a6fb3d8..1458802 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -180,7 +180,7 @@
return mInitCheck == OK ? 1 : 0;
}
-sp<MediaSource> AMRExtractor::getTrack(size_t index) {
+sp<IMediaSource> AMRExtractor::getTrack(size_t index) {
if (mInitCheck != OK || index != 0) {
return NULL;
}
@@ -309,7 +309,13 @@
buffer->release();
buffer = NULL;
- return ERROR_IO;
+ if (n < 0) {
+ return ERROR_IO;
+ } else {
+ // only partial frame is available, treat it as EOS.
+ mOffset += n;
+ return ERROR_END_OF_STREAM;
+ }
}
buffer->set_range(0, frameSize);
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index f53d7f0..961b57f 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -54,7 +54,7 @@
return mInitCheck;
}
-status_t AMRWriter::addSource(const sp<MediaSource> &source) {
+status_t AMRWriter::addSource(const sp<IMediaSource> &source) {
if (mInitCheck != OK) {
return mInitCheck;
}
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 2529aa7..68e02e7 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -1,7 +1,6 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-include frameworks/av/media/libstagefright/codecs/common/Config.mk
LOCAL_SRC_FILES:= \
ACodec.cpp \
@@ -11,11 +10,9 @@
AMRWriter.cpp \
AudioPlayer.cpp \
AudioSource.cpp \
- AwesomePlayer.cpp \
CallbackDataSource.cpp \
CameraSource.cpp \
CameraSourceTimeLapse.cpp \
- ClockEstimator.cpp \
CodecBase.cpp \
DataSource.cpp \
DataURISource.cpp \
@@ -25,14 +22,13 @@
FLACExtractor.cpp \
FrameRenderTracker.cpp \
HTTPBase.cpp \
+ HevcUtils.cpp \
JPEGSource.cpp \
MP3Extractor.cpp \
MPEG2TSWriter.cpp \
MPEG4Extractor.cpp \
MPEG4Writer.cpp \
MediaAdapter.cpp \
- MediaBuffer.cpp \
- MediaBufferGroup.cpp \
MediaClock.cpp \
MediaCodec.cpp \
MediaCodecList.cpp \
@@ -45,23 +41,20 @@
http/MediaHTTP.cpp \
MediaMuxer.cpp \
MediaSource.cpp \
- MetaData.cpp \
NuCachedSource2.cpp \
NuMediaExtractor.cpp \
OMXClient.cpp \
- OMXCodec.cpp \
OggExtractor.cpp \
ProcessInfo.cpp \
SampleIterator.cpp \
SampleTable.cpp \
+ SimpleDecodingSource.cpp \
SkipCutBuffer.cpp \
StagefrightMediaScanner.cpp \
StagefrightMetadataRetriever.cpp \
SurfaceMediaSource.cpp \
SurfaceUtils.cpp \
ThrottledSource.cpp \
- TimeSource.cpp \
- TimedEventQueue.cpp \
Utils.cpp \
VBRISeeker.cpp \
VideoFrameScheduler.cpp \
@@ -135,6 +128,7 @@
endif
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_MODULE:= libstagefright
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index dd9d393..cb42847 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -33,14 +33,11 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
-#include "include/AwesomePlayer.h"
-
namespace android {
AudioPlayer::AudioPlayer(
const sp<MediaPlayerBase::AudioSink> &audioSink,
- uint32_t flags,
- AwesomePlayer *observer)
+ uint32_t flags)
: mInputBuffer(NULL),
mSampleRate(0),
mLatencyUs(0),
@@ -58,8 +55,6 @@
mFirstBufferResult(OK),
mFirstBuffer(NULL),
mAudioSink(audioSink),
- mObserver(observer),
- mPinnedTimeUs(-1ll),
mPlaying(false),
mStartPosUs(0),
mCreateFlags(flags) {
@@ -71,7 +66,7 @@
}
}
-void AudioPlayer::setSource(const sp<MediaSource> &source) {
+void AudioPlayer::setSource(const sp<IMediaSource> &source) {
CHECK(mSource == NULL);
mSource = source;
}
@@ -256,7 +251,6 @@
mStarted = true;
mPlaying = true;
- mPinnedTimeUs = -1ll;
return OK;
}
@@ -279,8 +273,6 @@
} else {
mAudioTrack->pause();
}
-
- mPinnedTimeUs = ALooper::GetNowUs();
}
mPlaying = false;
@@ -358,7 +350,7 @@
// When offloading, the OMX component is not used so this hack
// is not needed
if (!useOffload()) {
- wp<MediaSource> tmp = mSource;
+ wp<IMediaSource> tmp = mSource;
mSource.clear();
while (tmp.promote() != NULL) {
usleep(1000);
@@ -386,11 +378,6 @@
static_cast<AudioPlayer *>(user)->AudioCallback(event, info);
}
-bool AudioPlayer::isSeeking() {
- Mutex::Autolock autoLock(mLock);
- return mSeeking;
-}
-
bool AudioPlayer::reachedEOS(status_t *finalStatus) {
*finalStatus = OK;
@@ -399,15 +386,6 @@
return mReachedEOS;
}
-void AudioPlayer::notifyAudioEOS() {
- ALOGV("AudioPlayer@0x%p notifyAudioEOS", this);
-
- if (mObserver != NULL) {
- mObserver->postAudioEOS(0);
- ALOGV("Notified observer of EOS!");
- }
-}
-
status_t AudioPlayer::setPlaybackRate(const AudioPlaybackRate &rate) {
if (mAudioSink.get() != NULL) {
return mAudioSink->setPlaybackRate(rate);
@@ -443,12 +421,10 @@
case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
ALOGV("AudioSinkCallback: stream end");
me->mReachedEOS = true;
- me->notifyAudioEOS();
break;
case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN:
ALOGV("AudioSinkCallback: Tear down event");
- me->mObserver->postAudioTearDown();
break;
}
@@ -467,31 +443,10 @@
case AudioTrack::EVENT_STREAM_END:
mReachedEOS = true;
- notifyAudioEOS();
break;
}
}
-uint32_t AudioPlayer::getNumFramesPendingPlayout() const {
- uint32_t numFramesPlayedOut;
- status_t err;
-
- if (mAudioSink != NULL) {
- err = mAudioSink->getPosition(&numFramesPlayedOut);
- } else {
- err = mAudioTrack->getPosition(&numFramesPlayedOut);
- }
-
- if (err != OK || mNumFramesPlayed < numFramesPlayedOut) {
- return 0;
- }
-
- // mNumFramesPlayed is the number of frames submitted
- // to the audio sink for playback, but not all of them
- // may have played out by now.
- return mNumFramesPlayed - numFramesPlayedOut;
-}
-
size_t AudioPlayer::fillBuffer(void *data, size_t size) {
if (mNumFramesPlayed == 0) {
ALOGV("AudioCallback");
@@ -501,10 +456,6 @@
return 0;
}
- bool postSeekComplete = false;
- bool postEOS = false;
- int64_t postEOSDelayUs = 0;
-
size_t size_done = 0;
size_t size_remaining = size;
while (size_remaining > 0) {
@@ -532,9 +483,6 @@
}
mSeeking = false;
- if (mObserver) {
- postSeekComplete = true;
- }
}
}
@@ -567,42 +515,6 @@
mAudioTrack->stop();
}
} else {
- if (mObserver) {
- // We don't want to post EOS right away but only
- // after all frames have actually been played out.
-
- // These are the number of frames submitted to the
- // AudioTrack that you haven't heard yet.
- uint32_t numFramesPendingPlayout =
- getNumFramesPendingPlayout();
-
- // These are the number of frames we're going to
- // submit to the AudioTrack by returning from this
- // callback.
- uint32_t numAdditionalFrames = size_done / mFrameSize;
-
- numFramesPendingPlayout += numAdditionalFrames;
-
- int64_t timeToCompletionUs =
- (1000000ll * numFramesPendingPlayout) / mSampleRate;
-
- ALOGV("total number of frames played: %" PRId64 " (%lld us)",
- (mNumFramesPlayed + numAdditionalFrames),
- 1000000ll * (mNumFramesPlayed + numAdditionalFrames)
- / mSampleRate);
-
- ALOGV("%d frames left to play, %" PRId64 " us (%.2f secs)",
- numFramesPendingPlayout,
- timeToCompletionUs, timeToCompletionUs / 1E6);
-
- postEOS = true;
- if (mAudioSink->needsTrailingPadding()) {
- postEOSDelayUs = timeToCompletionUs + mLatencyUs;
- } else {
- postEOSDelayUs = 0;
- }
- }
-
mReachedEOS = true;
}
}
@@ -626,12 +538,6 @@
// might not be able to get the exact seek time requested.
if (refreshSeekTime) {
if (useOffload()) {
- if (postSeekComplete) {
- ALOGV("fillBuffer is going to post SEEK_COMPLETE");
- mObserver->postAudioSeekComplete();
- postSeekComplete = false;
- }
-
mStartPosUs = mPositionTimeMediaUs;
ALOGV("adjust seek time to: %.2f", mStartPosUs/ 1E6);
}
@@ -690,58 +596,11 @@
Mutex::Autolock autoLock(mLock);
mNumFramesPlayed += size_done / mFrameSize;
mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
-
- if (mReachedEOS) {
- mPinnedTimeUs = mNumFramesPlayedSysTimeUs;
- } else {
- mPinnedTimeUs = -1ll;
- }
- }
-
- if (postEOS) {
- mObserver->postAudioEOS(postEOSDelayUs);
- }
-
- if (postSeekComplete) {
- mObserver->postAudioSeekComplete();
}
return size_done;
}
-int64_t AudioPlayer::getRealTimeUs() {
- Mutex::Autolock autoLock(mLock);
- if (useOffload()) {
- if (mSeeking) {
- return mSeekTimeUs;
- }
- mPositionTimeRealUs = getOutputPlayPositionUs_l();
- return mPositionTimeRealUs;
- }
-
- return getRealTimeUsLocked();
-}
-
-int64_t AudioPlayer::getRealTimeUsLocked() const {
- CHECK(mStarted);
- CHECK_NE(mSampleRate, 0);
- int64_t result = -mLatencyUs + (mNumFramesPlayed * 1000000) / mSampleRate;
-
- // Compensate for large audio buffers, updates of mNumFramesPlayed
- // are less frequent, therefore to get a "smoother" notion of time we
- // compensate using system time.
- int64_t diffUs;
- if (mPinnedTimeUs >= 0ll) {
- diffUs = mPinnedTimeUs;
- } else {
- diffUs = ALooper::GetNowUs();
- }
-
- diffUs -= mNumFramesPlayedSysTimeUs;
-
- return result + diffUs;
-}
-
int64_t AudioPlayer::getOutputPlayPositionUs_l()
{
uint32_t playedSamples = 0;
@@ -770,54 +629,6 @@
return renderedDuration;
}
-int64_t AudioPlayer::getMediaTimeUs() {
- Mutex::Autolock autoLock(mLock);
-
- if (useOffload()) {
- if (mSeeking) {
- return mSeekTimeUs;
- }
- if (mReachedEOS) {
- int64_t durationUs;
- mSource->getFormat()->findInt64(kKeyDuration, &durationUs);
- return durationUs;
- }
- mPositionTimeRealUs = getOutputPlayPositionUs_l();
- ALOGV("getMediaTimeUs getOutputPlayPositionUs_l() mPositionTimeRealUs %" PRId64,
- mPositionTimeRealUs);
- return mPositionTimeRealUs;
- }
-
-
- if (mPositionTimeMediaUs < 0 || mPositionTimeRealUs < 0) {
- // mSeekTimeUs is either seek time while seeking or 0 if playback did not start.
- return mSeekTimeUs;
- }
-
- int64_t realTimeOffset = getRealTimeUsLocked() - mPositionTimeRealUs;
- if (realTimeOffset < 0) {
- realTimeOffset = 0;
- }
-
- return mPositionTimeMediaUs + realTimeOffset;
-}
-
-bool AudioPlayer::getMediaTimeMapping(
- int64_t *realtime_us, int64_t *mediatime_us) {
- Mutex::Autolock autoLock(mLock);
-
- if (useOffload()) {
- mPositionTimeRealUs = getOutputPlayPositionUs_l();
- *realtime_us = mPositionTimeRealUs;
- *mediatime_us = mPositionTimeRealUs;
- } else {
- *realtime_us = mPositionTimeRealUs;
- *mediatime_us = mPositionTimeMediaUs;
- }
-
- return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1;
-}
-
status_t AudioPlayer::seekTo(int64_t time_us) {
Mutex::Autolock autoLock(mLock);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
deleted file mode 100644
index 3cd0b0e..0000000
--- a/media/libstagefright/AwesomePlayer.cpp
+++ /dev/null
@@ -1,3047 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef DEBUG_HDCP
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "AwesomePlayer"
-#define ATRACE_TAG ATRACE_TAG_VIDEO
-
-#include <inttypes.h>
-
-#include <utils/Log.h>
-#include <utils/Trace.h>
-
-#include <dlfcn.h>
-
-#include "include/AwesomePlayer.h"
-#include "include/DRMExtractor.h"
-#include "include/SoftwareRenderer.h"
-#include "include/NuCachedSource2.h"
-#include "include/ThrottledSource.h"
-#include "include/MPEG2TSExtractor.h"
-#include "include/WVMExtractor.h"
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <media/IMediaHTTPConnection.h>
-#include <media/IMediaHTTPService.h>
-#include <media/IMediaPlayerService.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/timedtext/TimedTextDriver.h>
-#include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/ClockEstimator.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaHTTP.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/Utils.h>
-
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/Surface.h>
-
-#include <media/stagefright/foundation/AMessage.h>
-
-#include <cutils/properties.h>
-
-#define USE_SURFACE_ALLOC 1
-#define FRAME_DROP_FREQ 0
-
-namespace android {
-
-static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
-static int64_t kHighWaterMarkUs = 5000000ll; // 5secs
-static const size_t kLowWaterMarkBytes = 40000;
-static const size_t kHighWaterMarkBytes = 200000;
-
-// maximum time in paused state when offloading audio decompression. When elapsed, the AudioPlayer
-// is destroyed to allow the audio DSP to power down.
-static int64_t kOffloadPauseMaxUs = 10000000ll;
-
-
-struct AwesomeEvent : public TimedEventQueue::Event {
- AwesomeEvent(
- AwesomePlayer *player,
- void (AwesomePlayer::*method)())
- : mPlayer(player),
- mMethod(method) {
- }
-
-protected:
- virtual ~AwesomeEvent() {}
-
- virtual void fire(TimedEventQueue * /* queue */, int64_t /* now_us */) {
- (mPlayer->*mMethod)();
- }
-
-private:
- AwesomePlayer *mPlayer;
- void (AwesomePlayer::*mMethod)();
-
- AwesomeEvent(const AwesomeEvent &);
- AwesomeEvent &operator=(const AwesomeEvent &);
-};
-
-struct AwesomeLocalRenderer : public AwesomeRenderer {
- AwesomeLocalRenderer(
- const sp<ANativeWindow> &nativeWindow, const sp<AMessage> &format)
- : mFormat(format),
- mTarget(new SoftwareRenderer(nativeWindow)) {
- }
-
- virtual void render(MediaBuffer *buffer) {
- int64_t timeUs;
- CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
-
- render((const uint8_t *)buffer->data() + buffer->range_offset(),
- buffer->range_length(), timeUs, timeUs * 1000);
- }
-
- void render(const void *data, size_t size, int64_t mediaTimeUs, nsecs_t renderTimeNs) {
- (void)mTarget->render(data, size, mediaTimeUs, renderTimeNs, NULL, mFormat);
- }
-
-protected:
- virtual ~AwesomeLocalRenderer() {
- delete mTarget;
- mTarget = NULL;
- }
-
-private:
- sp<AMessage> mFormat;
- SoftwareRenderer *mTarget;
-
- AwesomeLocalRenderer(const AwesomeLocalRenderer &);
- AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
-};
-
-struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
- AwesomeNativeWindowRenderer(
- const sp<ANativeWindow> &nativeWindow,
- int32_t rotationDegrees)
- : mNativeWindow(nativeWindow) {
- applyRotation(rotationDegrees);
- }
-
- virtual void render(MediaBuffer *buffer) {
- ATRACE_CALL();
- int64_t timeUs;
- CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
- native_window_set_buffers_timestamp(mNativeWindow.get(), timeUs * 1000);
- status_t err = mNativeWindow->queueBuffer(
- mNativeWindow.get(), buffer->graphicBuffer().get(), -1);
- if (err != 0) {
- ALOGE("queueBuffer failed with error %s (%d)", strerror(-err),
- -err);
- return;
- }
-
- sp<MetaData> metaData = buffer->meta_data();
- metaData->setInt32(kKeyRendered, 1);
- }
-
-protected:
- virtual ~AwesomeNativeWindowRenderer() {}
-
-private:
- sp<ANativeWindow> mNativeWindow;
-
- void applyRotation(int32_t rotationDegrees) {
- uint32_t transform;
- switch (rotationDegrees) {
- case 0: transform = 0; break;
- case 90: transform = HAL_TRANSFORM_ROT_90; break;
- case 180: transform = HAL_TRANSFORM_ROT_180; break;
- case 270: transform = HAL_TRANSFORM_ROT_270; break;
- default: transform = 0; break;
- }
-
- if (transform) {
- CHECK_EQ(0, native_window_set_buffers_transform(
- mNativeWindow.get(), transform));
- }
- }
-
- AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
- AwesomeNativeWindowRenderer &operator=(
- const AwesomeNativeWindowRenderer &);
-};
-
-// To collect the decoder usage
-void addBatteryData(uint32_t params) {
- sp<IBinder> binder =
- defaultServiceManager()->getService(String16("media.player"));
- sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
- CHECK(service.get() != NULL);
-
- service->addBatteryData(params);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-AwesomePlayer::AwesomePlayer()
- : mQueueStarted(false),
- mUIDValid(false),
- mTimeSource(NULL),
- mVideoRenderingStarted(false),
- mVideoRendererIsPreview(false),
- mMediaRenderingStartGeneration(0),
- mStartGeneration(0),
- mAudioPlayer(NULL),
- mDisplayWidth(0),
- mDisplayHeight(0),
- mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
- mFlags(0),
- mExtractorFlags(0),
- mVideoBuffer(NULL),
- mDecryptHandle(NULL),
- mLastVideoTimeUs(-1),
- mTextDriver(NULL),
- mOffloadAudio(false),
- mAudioTearDown(false) {
- CHECK_EQ(mClient.connect(), (status_t)OK);
-
- DataSource::RegisterDefaultSniffers();
-
- mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
- mVideoEventPending = false;
- mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
- mStreamDoneEventPending = false;
- mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
- mBufferingEventPending = false;
- mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate);
- mVideoLagEventPending = false;
-
- mCheckAudioStatusEvent = new AwesomeEvent(
- this, &AwesomePlayer::onCheckAudioStatus);
-
- mAudioStatusEventPending = false;
-
- mAudioTearDownEvent = new AwesomeEvent(this,
- &AwesomePlayer::onAudioTearDownEvent);
- mAudioTearDownEventPending = false;
-
- mClockEstimator = new WindowedLinearFitEstimator();
-
- mPlaybackSettings = AUDIO_PLAYBACK_RATE_DEFAULT;
-
- reset();
-}
-
-AwesomePlayer::~AwesomePlayer() {
- if (mQueueStarted) {
- mQueue.stop();
- }
-
- reset();
-
- mClient.disconnect();
-}
-
-void AwesomePlayer::cancelPlayerEvents(bool keepNotifications) {
- mQueue.cancelEvent(mVideoEvent->eventID());
- mVideoEventPending = false;
- mQueue.cancelEvent(mVideoLagEvent->eventID());
- mVideoLagEventPending = false;
-
- if (mOffloadAudio) {
- mQueue.cancelEvent(mAudioTearDownEvent->eventID());
- mAudioTearDownEventPending = false;
- }
-
- if (!keepNotifications) {
- mQueue.cancelEvent(mStreamDoneEvent->eventID());
- mStreamDoneEventPending = false;
- mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
- mAudioStatusEventPending = false;
-
- mQueue.cancelEvent(mBufferingEvent->eventID());
- mBufferingEventPending = false;
- mAudioTearDown = false;
- }
-}
-
-void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
- Mutex::Autolock autoLock(mLock);
- mListener = listener;
-}
-
-void AwesomePlayer::setUID(uid_t uid) {
- ALOGV("AwesomePlayer running on behalf of uid %d", uid);
-
- mUID = uid;
- mUIDValid = true;
-}
-
-status_t AwesomePlayer::setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers) {
- Mutex::Autolock autoLock(mLock);
- return setDataSource_l(httpService, uri, headers);
-}
-
-status_t AwesomePlayer::setDataSource_l(
- const sp<IMediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers) {
- reset_l();
-
- mHTTPService = httpService;
- mUri = uri;
-
- if (headers) {
- mUriHeaders = *headers;
-
- ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
- if (index >= 0) {
- // Browser is in "incognito" mode, suppress logging URLs.
-
- // This isn't something that should be passed to the server.
- mUriHeaders.removeItemsAt(index);
-
- modifyFlags(INCOGNITO, SET);
- }
- }
-
- ALOGI("setDataSource_l(%s)", uriDebugString(mUri, mFlags & INCOGNITO).c_str());
-
- // The actual work will be done during preparation in the call to
- // ::finishSetDataSource_l to avoid blocking the calling thread in
- // setDataSource for any significant time.
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mFd = -1;
- mStats.mURI = mUri;
- }
-
- return OK;
-}
-
-status_t AwesomePlayer::setDataSource(
- int fd, int64_t offset, int64_t length) {
- Mutex::Autolock autoLock(mLock);
-
- reset_l();
-
- sp<DataSource> dataSource = new FileSource(fd, offset, length);
-
- status_t err = dataSource->initCheck();
-
- if (err != OK) {
- return err;
- }
-
- mFileSource = dataSource;
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mFd = fd;
- mStats.mURI = String8();
- }
-
- return setDataSource_l(dataSource);
-}
-
-status_t AwesomePlayer::setDataSource(const sp<IStreamSource> &source __unused) {
- return INVALID_OPERATION;
-}
-
-status_t AwesomePlayer::setDataSource_l(
- const sp<DataSource> &dataSource) {
- sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
-
- if (extractor == NULL) {
- return UNKNOWN_ERROR;
- }
-
- if (extractor->getDrmFlag()) {
- checkDrmStatus(dataSource);
- }
-
- return setDataSource_l(extractor);
-}
-
-void AwesomePlayer::checkDrmStatus(const sp<DataSource>& dataSource) {
- dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
- if (mDecryptHandle != NULL) {
- CHECK(mDrmManagerClient);
- if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
- }
- }
-}
-
-status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
- // Attempt to approximate overall stream bitrate by summing all
- // tracks' individual bitrates, if not all of them advertise bitrate,
- // we have to fail.
-
- int64_t totalBitRate = 0;
-
- mExtractor = extractor;
- for (size_t i = 0; i < extractor->countTracks(); ++i) {
- sp<MetaData> meta = extractor->getTrackMetaData(i);
-
- int32_t bitrate;
- if (!meta->findInt32(kKeyBitRate, &bitrate)) {
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
- ALOGV("track of type '%s' does not publish bitrate", mime);
-
- totalBitRate = -1;
- break;
- }
-
- totalBitRate += bitrate;
- }
- sp<MetaData> fileMeta = mExtractor->getMetaData();
- if (fileMeta != NULL) {
- int64_t duration;
- if (fileMeta->findInt64(kKeyDuration, &duration)) {
- mDurationUs = duration;
- }
- }
-
- mBitrate = totalBitRate;
-
- ALOGV("mBitrate = %lld bits/sec", (long long)mBitrate);
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mBitrate = mBitrate;
- mStats.mTracks.clear();
- mStats.mAudioTrackIndex = -1;
- mStats.mVideoTrackIndex = -1;
- }
-
- bool haveAudio = false;
- bool haveVideo = false;
- for (size_t i = 0; i < extractor->countTracks(); ++i) {
- sp<MetaData> meta = extractor->getTrackMetaData(i);
-
- const char *_mime;
- CHECK(meta->findCString(kKeyMIMEType, &_mime));
-
- String8 mime = String8(_mime);
-
- if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) {
- setVideoSource(extractor->getTrack(i));
- haveVideo = true;
-
- // Set the presentation/display size
- int32_t displayWidth, displayHeight;
- bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);
- if (success) {
- success = meta->findInt32(kKeyDisplayHeight, &displayHeight);
- }
- if (success) {
- mDisplayWidth = displayWidth;
- mDisplayHeight = displayHeight;
- }
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mVideoTrackIndex = mStats.mTracks.size();
- mStats.mTracks.push();
- TrackStat *stat =
- &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);
- stat->mMIME = mime.string();
- }
- } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) {
- setAudioSource(extractor->getTrack(i));
- haveAudio = true;
- mActiveAudioTrackIndex = i;
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mAudioTrackIndex = mStats.mTracks.size();
- mStats.mTracks.push();
- TrackStat *stat =
- &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);
- stat->mMIME = mime.string();
- }
-
- if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_AUDIO_VORBIS)) {
- // Only do this for vorbis audio, none of the other audio
- // formats even support this ringtone specific hack and
- // retrieving the metadata on some extractors may turn out
- // to be very expensive.
- sp<MetaData> fileMeta = extractor->getMetaData();
- int32_t loop;
- if (fileMeta != NULL
- && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
- modifyFlags(AUTO_LOOPING, SET);
- }
- }
- } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
- addTextSource_l(i, extractor->getTrack(i));
- }
- }
-
- if (!haveAudio && !haveVideo) {
- if (mWVMExtractor != NULL) {
- return mWVMExtractor->getError();
- } else {
- return UNKNOWN_ERROR;
- }
- }
-
- mExtractorFlags = extractor->flags();
-
- return OK;
-}
-
-void AwesomePlayer::reset() {
- Mutex::Autolock autoLock(mLock);
- reset_l();
-}
-
-void AwesomePlayer::reset_l() {
- mVideoRenderingStarted = false;
- mActiveAudioTrackIndex = -1;
- mDisplayWidth = 0;
- mDisplayHeight = 0;
-
- notifyListener_l(MEDIA_STOPPED);
-
- if (mDecryptHandle != NULL) {
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::STOP, 0);
- mDecryptHandle = NULL;
- mDrmManagerClient = NULL;
- }
-
- if (mFlags & PLAYING) {
- uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
- if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
- params |= IMediaPlayerService::kBatteryDataTrackAudio;
- }
- if (mVideoSource != NULL) {
- params |= IMediaPlayerService::kBatteryDataTrackVideo;
- }
- addBatteryData(params);
- }
-
- if (mFlags & PREPARING) {
- modifyFlags(PREPARE_CANCELLED, SET);
- if (mConnectingDataSource != NULL) {
- ALOGI("interrupting the connection process");
- mConnectingDataSource->disconnect();
- }
-
- if (mFlags & PREPARING_CONNECTED) {
- // We are basically done preparing, we're just buffering
- // enough data to start playback, we can safely interrupt that.
- finishAsyncPrepare_l();
- }
- }
-
- while (mFlags & PREPARING) {
- mPreparedCondition.wait(mLock);
- }
-
- cancelPlayerEvents();
-
- mWVMExtractor.clear();
- mCachedSource.clear();
- mAudioTrack.clear();
- mVideoTrack.clear();
- mExtractor.clear();
-
- // Shutdown audio first, so that the response to the reset request
- // appears to happen instantaneously as far as the user is concerned
- // If we did this later, audio would continue playing while we
- // shutdown the video-related resources and the player appear to
- // not be as responsive to a reset request.
- if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED))
- && mAudioSource != NULL) {
- // If we had an audio player, it would have effectively
- // taken possession of the audio source and stopped it when
- // _it_ is stopped. Otherwise this is still our responsibility.
- mAudioSource->stop();
- }
- mAudioSource.clear();
- mOmxSource.clear();
-
- mTimeSource = NULL;
-
- delete mAudioPlayer;
- mAudioPlayer = NULL;
-
- if (mTextDriver != NULL) {
- delete mTextDriver;
- mTextDriver = NULL;
- }
-
- mVideoRenderer.clear();
-
- if (mVideoSource != NULL) {
- shutdownVideoDecoder_l();
- }
-
- mDurationUs = -1;
- modifyFlags(0, ASSIGN);
- mExtractorFlags = 0;
- mTimeSourceDeltaUs = 0;
- mVideoTimeUs = 0;
-
- mSeeking = NO_SEEK;
- mSeekNotificationSent = true;
- mSeekTimeUs = 0;
-
- mHTTPService.clear();
- mUri.setTo("");
- mUriHeaders.clear();
-
- mFileSource.clear();
-
- mBitrate = -1;
- mLastVideoTimeUs = -1;
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mFd = -1;
- mStats.mURI = String8();
- mStats.mBitrate = -1;
- mStats.mAudioTrackIndex = -1;
- mStats.mVideoTrackIndex = -1;
- mStats.mNumVideoFramesDecoded = 0;
- mStats.mNumVideoFramesDropped = 0;
- mStats.mVideoWidth = -1;
- mStats.mVideoHeight = -1;
- mStats.mFlags = 0;
- mStats.mTracks.clear();
- }
-
- mWatchForAudioSeekComplete = false;
- mWatchForAudioEOS = false;
-
- mMediaRenderingStartGeneration = 0;
- mStartGeneration = 0;
-}
-
-void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
- if ((mListener != NULL) && !mAudioTearDown) {
- sp<MediaPlayerBase> listener = mListener.promote();
-
- if (listener != NULL) {
- listener->sendEvent(msg, ext1, ext2);
- }
- }
-}
-
-bool AwesomePlayer::getBitrate(int64_t *bitrate) {
- off64_t size;
- if (mDurationUs > 0 && mCachedSource != NULL
- && mCachedSource->getSize(&size) == OK) {
- *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
- return true;
- }
-
- if (mBitrate >= 0) {
- *bitrate = mBitrate;
- return true;
- }
-
- *bitrate = 0;
-
- return false;
-}
-
-// Returns true iff cached duration is available/applicable.
-bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
- int64_t bitrate;
-
- if (mCachedSource != NULL && getBitrate(&bitrate) && (bitrate > 0)) {
- status_t finalStatus;
- size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
- *durationUs = cachedDataRemaining * 8000000ll / bitrate;
- *eos = (finalStatus != OK);
- return true;
- } else if (mWVMExtractor != NULL) {
- status_t finalStatus;
- *durationUs = mWVMExtractor->getCachedDurationUs(&finalStatus);
- *eos = (finalStatus != OK);
- return true;
- }
-
- return false;
-}
-
-void AwesomePlayer::ensureCacheIsFetching_l() {
- if (mCachedSource != NULL) {
- mCachedSource->resumeFetchingIfNecessary();
- }
-}
-
-void AwesomePlayer::onVideoLagUpdate() {
- Mutex::Autolock autoLock(mLock);
- if (!mVideoLagEventPending) {
- return;
- }
- mVideoLagEventPending = false;
-
- int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs();
- int64_t videoLateByUs = audioTimeUs - mVideoTimeUs;
-
- if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) {
- ALOGV("video late by %lld ms.", videoLateByUs / 1000ll);
-
- notifyListener_l(
- MEDIA_INFO,
- MEDIA_INFO_VIDEO_TRACK_LAGGING,
- videoLateByUs / 1000ll);
- }
-
- postVideoLagEvent_l();
-}
-
-void AwesomePlayer::onBufferingUpdate() {
- Mutex::Autolock autoLock(mLock);
- if (!mBufferingEventPending) {
- return;
- }
- mBufferingEventPending = false;
-
- if (mCachedSource != NULL) {
- status_t finalStatus;
- size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
- bool eos = (finalStatus != OK);
-
- if (eos) {
- if (finalStatus == ERROR_END_OF_STREAM) {
- notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
- }
- if (mFlags & PREPARING) {
- ALOGV("cache has reached EOS, prepare is done.");
- finishAsyncPrepare_l();
- }
- } else {
- bool eos2;
- int64_t cachedDurationUs;
- if (getCachedDuration_l(&cachedDurationUs, &eos2) && mDurationUs > 0) {
- int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
- if (percentage > 100) {
- percentage = 100;
- }
-
- notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
- } else {
- // We don't know the bitrate/duration of the stream, use absolute size
- // limits to maintain the cache.
-
- if ((mFlags & PLAYING) && !eos
- && (cachedDataRemaining < kLowWaterMarkBytes)) {
- ALOGI("cache is running low (< %zu) , pausing.",
- kLowWaterMarkBytes);
- modifyFlags(CACHE_UNDERRUN, SET);
- pause_l();
- ensureCacheIsFetching_l();
- sendCacheStats();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
- } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
- if (mFlags & CACHE_UNDERRUN) {
- ALOGI("cache has filled up (> %zu), resuming.",
- kHighWaterMarkBytes);
- modifyFlags(CACHE_UNDERRUN, CLEAR);
- play_l();
- } else if (mFlags & PREPARING) {
- ALOGV("cache has filled up (> %zu), prepare is done",
- kHighWaterMarkBytes);
- finishAsyncPrepare_l();
- }
- }
- }
- }
- } else if (mWVMExtractor != NULL) {
- status_t finalStatus;
-
- int64_t cachedDurationUs
- = mWVMExtractor->getCachedDurationUs(&finalStatus);
-
- bool eos = (finalStatus != OK);
-
- if (eos) {
- if (finalStatus == ERROR_END_OF_STREAM) {
- notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
- }
- if (mFlags & PREPARING) {
- ALOGV("cache has reached EOS, prepare is done.");
- finishAsyncPrepare_l();
- }
- } else {
- int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
- if (percentage > 100) {
- percentage = 100;
- }
-
- notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
- }
- }
-
- int64_t cachedDurationUs;
- bool eos;
- if (getCachedDuration_l(&cachedDurationUs, &eos)) {
- ALOGV("cachedDurationUs = %.2f secs, eos=%d",
- cachedDurationUs / 1E6, eos);
-
- if ((mFlags & PLAYING) && !eos
- && (cachedDurationUs < kLowWaterMarkUs)) {
- modifyFlags(CACHE_UNDERRUN, SET);
- ALOGI("cache is running low (%.2f secs) , pausing.",
- cachedDurationUs / 1E6);
- pause_l();
- ensureCacheIsFetching_l();
- sendCacheStats();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
- } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
- if (mFlags & CACHE_UNDERRUN) {
- modifyFlags(CACHE_UNDERRUN, CLEAR);
- ALOGI("cache has filled up (%.2f secs), resuming.",
- cachedDurationUs / 1E6);
- play_l();
- } else if (mFlags & PREPARING) {
- ALOGV("cache has filled up (%.2f secs), prepare is done",
- cachedDurationUs / 1E6);
- finishAsyncPrepare_l();
- }
- }
- }
-
- if (mFlags & (PLAYING | PREPARING | CACHE_UNDERRUN)) {
- postBufferingEvent_l();
- }
-}
-
-void AwesomePlayer::sendCacheStats() {
- sp<MediaPlayerBase> listener = mListener.promote();
- if (listener != NULL) {
- int32_t kbps = 0;
- status_t err = UNKNOWN_ERROR;
- if (mCachedSource != NULL) {
- err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
- } else if (mWVMExtractor != NULL) {
- err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
- }
- if (err == OK) {
- listener->sendEvent(
- MEDIA_INFO, MEDIA_INFO_NETWORK_BANDWIDTH, kbps);
- }
- }
-}
-
-void AwesomePlayer::onStreamDone() {
- // Posted whenever any stream finishes playing.
- ATRACE_CALL();
-
- Mutex::Autolock autoLock(mLock);
- if (!mStreamDoneEventPending) {
- return;
- }
- mStreamDoneEventPending = false;
-
- if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
- ALOGV("MEDIA_ERROR %d", mStreamDoneStatus);
-
- notifyListener_l(
- MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
-
- pause_l(true /* at eos */);
-
- modifyFlags(AT_EOS, SET);
- return;
- }
-
- const bool allDone =
- (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
- && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
-
- if (!allDone) {
- return;
- }
-
- if (mFlags & AUTO_LOOPING) {
- audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
- if (mAudioSink != NULL) {
- streamType = mAudioSink->getAudioStreamType();
- }
- if (streamType == AUDIO_STREAM_NOTIFICATION) {
- ALOGW("disabling auto-loop for notification");
- modifyFlags(AUTO_LOOPING, CLEAR);
- }
- }
- if ((mFlags & LOOPING)
- || (mFlags & AUTO_LOOPING)) {
-
- seekTo_l(0);
-
- if (mVideoSource != NULL) {
- postVideoEvent_l();
- }
- } else {
- ALOGV("MEDIA_PLAYBACK_COMPLETE");
- notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
-
- pause_l(true /* at eos */);
-
- // If audio hasn't completed MEDIA_SEEK_COMPLETE yet,
- // notify MEDIA_SEEK_COMPLETE to observer immediately for state persistence.
- if (mWatchForAudioSeekComplete) {
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- mWatchForAudioSeekComplete = false;
- }
-
- modifyFlags(AT_EOS, SET);
- }
-}
-
-status_t AwesomePlayer::play() {
- ATRACE_CALL();
-
- Mutex::Autolock autoLock(mLock);
-
- modifyFlags(CACHE_UNDERRUN, CLEAR);
-
- return play_l();
-}
-
-status_t AwesomePlayer::play_l() {
- modifyFlags(SEEK_PREVIEW, CLEAR);
-
- if (mFlags & PLAYING) {
- return OK;
- }
-
- mMediaRenderingStartGeneration = ++mStartGeneration;
-
- if (!(mFlags & PREPARED)) {
- status_t err = prepare_l();
-
- if (err != OK) {
- return err;
- }
- }
-
- modifyFlags(PLAYING, SET);
- modifyFlags(FIRST_FRAME, SET);
-
- if (mDecryptHandle != NULL) {
- int64_t position;
- getPosition(&position);
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::START, position / 1000);
- }
-
- if (mAudioSource != NULL) {
- if (mAudioPlayer == NULL) {
- createAudioPlayer_l();
- }
-
- CHECK(!(mFlags & AUDIO_RUNNING));
-
- if (mVideoSource == NULL) {
-
- // We don't want to post an error notification at this point,
- // the error returned from MediaPlayer::start() will suffice.
-
- status_t err = startAudioPlayer_l(
- false /* sendErrorNotification */);
-
- if ((err != OK) && mOffloadAudio) {
- ALOGI("play_l() cannot create offload output, fallback to sw decode");
- int64_t curTimeUs;
- getPosition(&curTimeUs);
-
- delete mAudioPlayer;
- mAudioPlayer = NULL;
- // if the player was started it will take care of stopping the source when destroyed
- if (!(mFlags & AUDIOPLAYER_STARTED)) {
- mAudioSource->stop();
- }
- modifyFlags((AUDIO_RUNNING | AUDIOPLAYER_STARTED), CLEAR);
- mOffloadAudio = false;
- mAudioSource = mOmxSource;
- if (mAudioSource != NULL) {
- err = mAudioSource->start();
-
- if (err != OK) {
- mAudioSource.clear();
- } else {
- mSeekNotificationSent = true;
- if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
- seekTo_l(curTimeUs);
- }
- createAudioPlayer_l();
- err = startAudioPlayer_l(false);
- }
- }
- }
-
- if (err != OK) {
- delete mAudioPlayer;
- mAudioPlayer = NULL;
-
- modifyFlags((PLAYING | FIRST_FRAME), CLEAR);
-
- if (mDecryptHandle != NULL) {
- mDrmManagerClient->setPlaybackStatus(
- mDecryptHandle, Playback::STOP, 0);
- }
-
- return err;
- }
- }
-
- if (mAudioPlayer != NULL) {
- mAudioPlayer->setPlaybackRate(mPlaybackSettings);
- }
- }
-
- if (mTimeSource == NULL && mAudioPlayer == NULL) {
- mTimeSource = &mSystemTimeSource;
- }
-
- if (mVideoSource != NULL) {
- // Kick off video playback
- postVideoEvent_l();
-
- if (mAudioSource != NULL && mVideoSource != NULL) {
- postVideoLagEvent_l();
- }
- }
-
- if (mFlags & AT_EOS) {
- // Legacy behaviour, if a stream finishes playing and then
- // is started again, we play from the start...
- seekTo_l(0);
- }
-
- uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted
- | IMediaPlayerService::kBatteryDataTrackDecoder;
- if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
- params |= IMediaPlayerService::kBatteryDataTrackAudio;
- }
- if (mVideoSource != NULL) {
- params |= IMediaPlayerService::kBatteryDataTrackVideo;
- }
- addBatteryData(params);
-
- if (isStreamingHTTP()) {
- postBufferingEvent_l();
- }
-
- return OK;
-}
-
-void AwesomePlayer::createAudioPlayer_l()
-{
- uint32_t flags = 0;
- int64_t cachedDurationUs;
- bool eos;
-
- if (mOffloadAudio) {
- flags |= AudioPlayer::USE_OFFLOAD;
- } else if (mVideoSource == NULL
- && (mDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US ||
- (getCachedDuration_l(&cachedDurationUs, &eos) &&
- cachedDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US))) {
- flags |= AudioPlayer::ALLOW_DEEP_BUFFERING;
- }
- if (isStreamingHTTP()) {
- flags |= AudioPlayer::IS_STREAMING;
- }
- if (mVideoSource != NULL) {
- flags |= AudioPlayer::HAS_VIDEO;
- }
-
- mAudioPlayer = new AudioPlayer(mAudioSink, flags, this);
- mAudioPlayer->setSource(mAudioSource);
-
- mTimeSource = mAudioPlayer;
-
- // If there was a seek request before we ever started,
- // honor the request now.
- // Make sure to do this before starting the audio player
- // to avoid a race condition.
- seekAudioIfNecessary_l();
-}
-
-void AwesomePlayer::notifyIfMediaStarted_l() {
- if (mMediaRenderingStartGeneration == mStartGeneration) {
- mMediaRenderingStartGeneration = -1;
- notifyListener_l(MEDIA_STARTED);
- }
-}
-
-status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) {
- CHECK(!(mFlags & AUDIO_RUNNING));
- status_t err = OK;
-
- if (mAudioSource == NULL || mAudioPlayer == NULL) {
- return OK;
- }
-
- if (mOffloadAudio) {
- mQueue.cancelEvent(mAudioTearDownEvent->eventID());
- mAudioTearDownEventPending = false;
- }
-
- if (!(mFlags & AUDIOPLAYER_STARTED)) {
- bool wasSeeking = mAudioPlayer->isSeeking();
-
- // We've already started the MediaSource in order to enable
- // the prefetcher to read its data.
- err = mAudioPlayer->start(
- true /* sourceAlreadyStarted */);
-
- if (err != OK) {
- if (sendErrorNotification) {
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
- }
-
- return err;
- }
-
- modifyFlags(AUDIOPLAYER_STARTED, SET);
-
- if (wasSeeking) {
- CHECK(!mAudioPlayer->isSeeking());
-
- // We will have finished the seek while starting the audio player.
- postAudioSeekComplete();
- } else {
- notifyIfMediaStarted_l();
- }
- } else {
- err = mAudioPlayer->resume();
- }
-
- if (err == OK) {
- err = mAudioPlayer->setPlaybackRate(mPlaybackSettings);
- }
-
- if (err == OK) {
- modifyFlags(AUDIO_RUNNING, SET);
-
- mWatchForAudioEOS = true;
- }
-
- return err;
-}
-
-void AwesomePlayer::notifyVideoSize_l() {
- ATRACE_CALL();
- sp<MetaData> meta = mVideoSource->getFormat();
-
- int32_t cropLeft, cropTop, cropRight, cropBottom;
- if (!meta->findRect(
- kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
- int32_t width, height;
- CHECK(meta->findInt32(kKeyWidth, &width));
- CHECK(meta->findInt32(kKeyHeight, &height));
-
- cropLeft = cropTop = 0;
- cropRight = width - 1;
- cropBottom = height - 1;
-
- ALOGV("got dimensions only %d x %d", width, height);
- } else {
- ALOGV("got crop rect %d, %d, %d, %d",
- cropLeft, cropTop, cropRight, cropBottom);
- }
-
- int32_t displayWidth;
- if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
- ALOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth);
- mDisplayWidth = displayWidth;
- }
- int32_t displayHeight;
- if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
- ALOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight);
- mDisplayHeight = displayHeight;
- }
-
- int32_t usableWidth = cropRight - cropLeft + 1;
- int32_t usableHeight = cropBottom - cropTop + 1;
- if (mDisplayWidth != 0) {
- usableWidth = mDisplayWidth;
- }
- if (mDisplayHeight != 0) {
- usableHeight = mDisplayHeight;
- }
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mVideoWidth = usableWidth;
- mStats.mVideoHeight = usableHeight;
- }
-
- int32_t rotationDegrees;
- if (!mVideoTrack->getFormat()->findInt32(
- kKeyRotation, &rotationDegrees)) {
- rotationDegrees = 0;
- }
-
- if (rotationDegrees == 90 || rotationDegrees == 270) {
- notifyListener_l(
- MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth);
- } else {
- notifyListener_l(
- MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight);
- }
-}
-
-void AwesomePlayer::initRenderer_l() {
- ATRACE_CALL();
-
- if (mNativeWindow == NULL) {
- return;
- }
-
- sp<MetaData> meta = mVideoSource->getFormat();
-
- int32_t format;
- const char *component;
- int32_t decodedWidth, decodedHeight;
- CHECK(meta->findInt32(kKeyColorFormat, &format));
- CHECK(meta->findCString(kKeyDecoderComponent, &component));
- CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
- CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
-
- int32_t rotationDegrees;
- if (!mVideoTrack->getFormat()->findInt32(
- kKeyRotation, &rotationDegrees)) {
- rotationDegrees = 0;
- }
-
- mVideoRenderer.clear();
-
- // Must ensure that mVideoRenderer's destructor is actually executed
- // before creating a new one.
- IPCThreadState::self()->flushCommands();
-
- // Even if set scaling mode fails, we will continue anyway
- setVideoScalingMode_l(mVideoScalingMode);
- if (USE_SURFACE_ALLOC
- && !strncmp(component, "OMX.", 4)
- && strncmp(component, "OMX.google.", 11)) {
- // Hardware decoders avoid the CPU color conversion by decoding
- // directly to ANativeBuffers, so we must use a renderer that
- // just pushes those buffers to the ANativeWindow.
- mVideoRenderer =
- new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees);
- } else {
- // Other decoders are instantiated locally and as a consequence
- // allocate their buffers in local address space. This renderer
- // then performs a color conversion and copy to get the data
- // into the ANativeBuffer.
- sp<AMessage> format;
- convertMetaDataToMessage(meta, &format);
- mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, format);
- }
-}
-
-status_t AwesomePlayer::pause() {
- ATRACE_CALL();
-
- Mutex::Autolock autoLock(mLock);
-
- modifyFlags(CACHE_UNDERRUN, CLEAR);
-
- return pause_l();
-}
-
-status_t AwesomePlayer::pause_l(bool at_eos) {
- if (!(mFlags & PLAYING)) {
- if (mAudioTearDown && mAudioTearDownWasPlaying) {
- ALOGV("pause_l() during teardown and finishSetDataSource_l() mFlags %x" , mFlags);
- mAudioTearDownWasPlaying = false;
- notifyListener_l(MEDIA_PAUSED);
- mMediaRenderingStartGeneration = ++mStartGeneration;
- }
- return OK;
- }
-
- notifyListener_l(MEDIA_PAUSED);
- mMediaRenderingStartGeneration = ++mStartGeneration;
-
- cancelPlayerEvents(true /* keepNotifications */);
-
- if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
- // If we played the audio stream to completion we
- // want to make sure that all samples remaining in the audio
- // track's queue are played out.
- mAudioPlayer->pause(at_eos /* playPendingSamples */);
- // send us a reminder to tear down the AudioPlayer if paused for too long.
- if (mOffloadAudio) {
- postAudioTearDownEvent(kOffloadPauseMaxUs);
- }
- modifyFlags(AUDIO_RUNNING, CLEAR);
- }
-
- if (mFlags & TEXTPLAYER_INITIALIZED) {
- mTextDriver->pause();
- modifyFlags(TEXT_RUNNING, CLEAR);
- }
-
- modifyFlags(PLAYING, CLEAR);
-
- if (mDecryptHandle != NULL) {
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::PAUSE, 0);
- }
-
- uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
- if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
- params |= IMediaPlayerService::kBatteryDataTrackAudio;
- }
- if (mVideoSource != NULL) {
- params |= IMediaPlayerService::kBatteryDataTrackVideo;
- }
-
- addBatteryData(params);
-
- return OK;
-}
-
-bool AwesomePlayer::isPlaying() const {
- return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
-}
-
-status_t AwesomePlayer::setSurfaceTexture(const sp<IGraphicBufferProducer> &bufferProducer) {
- Mutex::Autolock autoLock(mLock);
-
- status_t err;
- if (bufferProducer != NULL) {
- err = setNativeWindow_l(new Surface(bufferProducer));
- } else {
- err = setNativeWindow_l(NULL);
- }
-
- return err;
-}
-
-void AwesomePlayer::shutdownVideoDecoder_l() {
- if (mVideoBuffer) {
- mVideoBuffer->release();
- mVideoBuffer = NULL;
- }
-
- mVideoSource->stop();
-
- // The following hack is necessary to ensure that the OMX
- // component is completely released by the time we may try
- // to instantiate it again.
- wp<MediaSource> tmp = mVideoSource;
- mVideoSource.clear();
- while (tmp.promote() != NULL) {
- usleep(1000);
- }
- IPCThreadState::self()->flushCommands();
- ALOGV("video decoder shutdown completed");
-}
-
-status_t AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) {
- mNativeWindow = native;
-
- if (mVideoSource == NULL) {
- return OK;
- }
-
- ALOGV("attempting to reconfigure to use new surface");
-
- bool wasPlaying = (mFlags & PLAYING) != 0;
-
- pause_l();
- mVideoRenderer.clear();
-
- shutdownVideoDecoder_l();
-
- status_t err = initVideoDecoder();
-
- if (err != OK) {
- ALOGE("failed to reinstantiate video decoder after surface change.");
- return err;
- }
-
- if (mLastVideoTimeUs >= 0) {
- mSeeking = SEEK;
- mSeekTimeUs = mLastVideoTimeUs;
- modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
- }
-
- if (wasPlaying) {
- play_l();
- }
-
- return OK;
-}
-
-void AwesomePlayer::setAudioSink(
- const sp<MediaPlayerBase::AudioSink> &audioSink) {
- Mutex::Autolock autoLock(mLock);
-
- mAudioSink = audioSink;
-}
-
-status_t AwesomePlayer::setLooping(bool shouldLoop) {
- Mutex::Autolock autoLock(mLock);
-
- modifyFlags(LOOPING, CLEAR);
-
- if (shouldLoop) {
- modifyFlags(LOOPING, SET);
- }
-
- return OK;
-}
-
-status_t AwesomePlayer::getDuration(int64_t *durationUs) {
- Mutex::Autolock autoLock(mMiscStateLock);
-
- if (mDurationUs < 0) {
- return UNKNOWN_ERROR;
- }
-
- *durationUs = mDurationUs;
-
- return OK;
-}
-
-status_t AwesomePlayer::getPosition(int64_t *positionUs) {
- if (mSeeking != NO_SEEK) {
- *positionUs = mSeekTimeUs;
- } else if (mVideoSource != NULL
- && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
- Mutex::Autolock autoLock(mMiscStateLock);
- *positionUs = mVideoTimeUs;
- } else if (mAudioPlayer != NULL) {
- *positionUs = mAudioPlayer->getMediaTimeUs();
- } else {
- *positionUs = 0;
- }
- return OK;
-}
-
-status_t AwesomePlayer::seekTo(int64_t timeUs) {
- ATRACE_CALL();
-
- if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
- Mutex::Autolock autoLock(mLock);
- return seekTo_l(timeUs);
- }
-
- return OK;
-}
-
-status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
- if (mFlags & CACHE_UNDERRUN) {
- modifyFlags(CACHE_UNDERRUN, CLEAR);
- play_l();
- }
-
- if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) {
- // Video playback completed before, there's no pending
- // video event right now. In order for this new seek
- // to be honored, we need to post one.
-
- postVideoEvent_l();
- }
-
- mSeeking = SEEK;
- mSeekNotificationSent = false;
- mSeekTimeUs = timeUs;
- modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
-
- if (mFlags & PLAYING) {
- notifyListener_l(MEDIA_PAUSED);
- mMediaRenderingStartGeneration = ++mStartGeneration;
- }
-
- seekAudioIfNecessary_l();
-
- if (mFlags & TEXTPLAYER_INITIALIZED) {
- mTextDriver->seekToAsync(mSeekTimeUs);
- }
-
- if (!(mFlags & PLAYING)) {
- ALOGV("seeking while paused, sending SEEK_COMPLETE notification"
- " immediately.");
-
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- mSeekNotificationSent = true;
-
- if ((mFlags & PREPARED) && mVideoSource != NULL) {
- modifyFlags(SEEK_PREVIEW, SET);
- postVideoEvent_l();
- }
- }
-
- return OK;
-}
-
-void AwesomePlayer::seekAudioIfNecessary_l() {
- if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) {
- mAudioPlayer->seekTo(mSeekTimeUs);
-
- mWatchForAudioSeekComplete = true;
- mWatchForAudioEOS = true;
-
- if (mDecryptHandle != NULL) {
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::PAUSE, 0);
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::START, mSeekTimeUs / 1000);
- }
- }
-}
-
-void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
- CHECK(source != NULL);
-
- mAudioTrack = source;
-}
-
-void AwesomePlayer::addTextSource_l(size_t trackIndex, const sp<MediaSource>& source) {
- CHECK(source != NULL);
-
- if (mTextDriver == NULL) {
- mTextDriver = new TimedTextDriver(mListener, mHTTPService);
- }
-
- mTextDriver->addInBandTextSource(trackIndex, source);
-}
-
-status_t AwesomePlayer::initAudioDecoder() {
- ATRACE_CALL();
-
- sp<MetaData> meta = mAudioTrack->getFormat();
-
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
- // Check whether there is a hardware codec for this stream
- // This doesn't guarantee that the hardware has a free stream
- // but it avoids us attempting to open (and re-open) an offload
- // stream to hardware that doesn't have the necessary codec
- audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
- if (mAudioSink != NULL) {
- streamType = mAudioSink->getAudioStreamType();
- }
-
- mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL),
- isStreamingHTTP(), streamType);
-
- if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
- ALOGV("createAudioPlayer: bypass OMX (raw)");
- mAudioSource = mAudioTrack;
- } else {
- // If offloading we still create a OMX decoder as a fall-back
- // but we don't start it
- mOmxSource = OMXCodec::Create(
- mClient.interface(), mAudioTrack->getFormat(),
- false, // createEncoder
- mAudioTrack);
-
- if (mOffloadAudio) {
- ALOGV("createAudioPlayer: bypass OMX (offload)");
- mAudioSource = mAudioTrack;
- } else {
- mAudioSource = mOmxSource;
- }
- }
-
- if (mAudioSource != NULL) {
- int64_t durationUs;
- if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
- Mutex::Autolock autoLock(mMiscStateLock);
- if (mDurationUs < 0 || durationUs > mDurationUs) {
- mDurationUs = durationUs;
- }
- }
-
- status_t err = mAudioSource->start();
-
- if (err != OK) {
- mAudioSource.clear();
- mOmxSource.clear();
- return err;
- }
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
- // For legacy reasons we're simply going to ignore the absence
- // of an audio decoder for QCELP instead of aborting playback
- // altogether.
- return OK;
- }
-
- if (mAudioSource != NULL) {
- Mutex::Autolock autoLock(mStatsLock);
- TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);
- const char *component;
- if (!mAudioSource->getFormat()
- ->findCString(kKeyDecoderComponent, &component)) {
- component = "none";
- }
-
- stat->mDecoderName = component;
- }
-
- return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
-}
-
-void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
- CHECK(source != NULL);
-
- mVideoTrack = source;
-}
-
-status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
- ATRACE_CALL();
-
- // Either the application or the DRM system can independently say
- // that there must be a hardware-protected path to an external video sink.
- // For now we always require a hardware-protected path to external video sink
- // if content is DRMed, but eventually this could be optional per DRM agent.
- // When the application wants protection, then
- // (USE_SURFACE_ALLOC && (mSurface != 0) &&
- // (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp))
- // will be true, but that part is already handled by SurfaceFlinger.
-
-#ifdef DEBUG_HDCP
- // For debugging, we allow a system property to control the protected usage.
- // In case of uninitialized or unexpected property, we default to "DRM only".
- bool setProtectionBit = false;
- char value[PROPERTY_VALUE_MAX];
- if (property_get("persist.sys.hdcp_checking", value, NULL)) {
- if (!strcmp(value, "never")) {
- // nop
- } else if (!strcmp(value, "always")) {
- setProtectionBit = true;
- } else if (!strcmp(value, "drm-only")) {
- if (mDecryptHandle != NULL) {
- setProtectionBit = true;
- }
- // property value is empty, or unexpected value
- } else {
- if (mDecryptHandle != NULL) {
- setProtectionBit = true;
- }
- }
- // can' read property value
- } else {
- if (mDecryptHandle != NULL) {
- setProtectionBit = true;
- }
- }
- // note that usage bit is already cleared, so no need to clear it in the "else" case
- if (setProtectionBit) {
- flags |= OMXCodec::kEnableGrallocUsageProtected;
- }
-#else
- if (mDecryptHandle != NULL) {
- flags |= OMXCodec::kEnableGrallocUsageProtected;
- }
-#endif
- ALOGV("initVideoDecoder flags=0x%x", flags);
- mVideoSource = OMXCodec::Create(
- mClient.interface(), mVideoTrack->getFormat(),
- false, // createEncoder
- mVideoTrack,
- NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
-
- if (mVideoSource != NULL) {
- int64_t durationUs;
- if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
- Mutex::Autolock autoLock(mMiscStateLock);
- if (mDurationUs < 0 || durationUs > mDurationUs) {
- mDurationUs = durationUs;
- }
- }
-
- status_t err = mVideoSource->start();
-
- if (err != OK) {
- ALOGE("failed to start video source");
- mVideoSource.clear();
- return err;
- }
- }
-
- if (mVideoSource != NULL) {
- const char *componentName;
- CHECK(mVideoSource->getFormat()
- ->findCString(kKeyDecoderComponent, &componentName));
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);
-
- stat->mDecoderName = componentName;
- }
-
- static const char *kPrefix = "OMX.Nvidia.";
- static const char *kSuffix = ".decode";
- static const size_t kSuffixLength = strlen(kSuffix);
-
- size_t componentNameLength = strlen(componentName);
-
- if (!strncmp(componentName, kPrefix, strlen(kPrefix))
- && componentNameLength >= kSuffixLength
- && !strcmp(&componentName[
- componentNameLength - kSuffixLength], kSuffix)) {
- modifyFlags(SLOW_DECODER_HACK, SET);
- }
- }
-
- return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
-}
-
-void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
- ATRACE_CALL();
-
- if (mSeeking == SEEK_VIDEO_ONLY) {
- mSeeking = NO_SEEK;
- return;
- }
-
- if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) {
- return;
- }
-
- // If we paused, then seeked, then resumed, it is possible that we have
- // signaled SEEK_COMPLETE at a copmletely different media time than where
- // we are now resuming. Signal new position to media time provider.
- // Cannot signal another SEEK_COMPLETE, as existing clients may not expect
- // multiple SEEK_COMPLETE responses to a single seek() request.
- if (mSeekNotificationSent && llabs((long long)(mSeekTimeUs - videoTimeUs)) > 10000) {
- // notify if we are resuming more than 10ms away from desired seek time
- notifyListener_l(MEDIA_SKIPPED);
- }
-
- if (mAudioPlayer != NULL) {
- ALOGV("seeking audio to %" PRId64 " us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
-
- // If we don't have a video time, seek audio to the originally
- // requested seek time instead.
-
- mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
- mWatchForAudioSeekComplete = true;
- mWatchForAudioEOS = true;
- } else if (!mSeekNotificationSent) {
- // If we're playing video only, report seek complete now,
- // otherwise audio player will notify us later.
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- mSeekNotificationSent = true;
- }
-
- modifyFlags(FIRST_FRAME, SET);
- mSeeking = NO_SEEK;
-
- if (mDecryptHandle != NULL) {
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::PAUSE, 0);
- mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
- Playback::START, videoTimeUs / 1000);
- }
-}
-
-void AwesomePlayer::onVideoEvent() {
- ATRACE_CALL();
- Mutex::Autolock autoLock(mLock);
- if (!mVideoEventPending) {
- // The event has been cancelled in reset_l() but had already
- // been scheduled for execution at that time.
- return;
- }
- mVideoEventPending = false;
-
- if (mSeeking != NO_SEEK) {
- if (mVideoBuffer) {
- mVideoBuffer->release();
- mVideoBuffer = NULL;
- }
-
- if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL
- && !(mFlags & SEEK_PREVIEW)) {
- // We're going to seek the video source first, followed by
- // the audio source.
- // In order to avoid jumps in the DataSource offset caused by
- // the audio codec prefetching data from the old locations
- // while the video codec is already reading data from the new
- // locations, we'll "pause" the audio source, causing it to
- // stop reading input data until a subsequent seek.
-
- if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
- mAudioPlayer->pause();
-
- modifyFlags(AUDIO_RUNNING, CLEAR);
- }
- mAudioSource->pause();
- }
- }
-
- if (!mVideoBuffer) {
- MediaSource::ReadOptions options;
- if (mSeeking != NO_SEEK) {
- ALOGV("seeking to %" PRId64 " us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
-
- options.setSeekTo(
- mSeekTimeUs,
- mSeeking == SEEK_VIDEO_ONLY
- ? MediaSource::ReadOptions::SEEK_NEXT_SYNC
- : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
- }
- for (;;) {
- status_t err = mVideoSource->read(&mVideoBuffer, &options);
- options.clearSeekTo();
-
- if (err != OK) {
- CHECK(mVideoBuffer == NULL);
-
- if (err == INFO_FORMAT_CHANGED) {
- ALOGV("VideoSource signalled format change.");
-
- notifyVideoSize_l();
-
- if (mVideoRenderer != NULL) {
- mVideoRendererIsPreview = false;
- initRenderer_l();
- }
- continue;
- }
-
- // So video playback is complete, but we may still have
- // a seek request pending that needs to be applied
- // to the audio track.
- if (mSeeking != NO_SEEK) {
- ALOGV("video stream ended while seeking!");
- }
- finishSeekIfNecessary(-1);
-
- if (mAudioPlayer != NULL
- && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
- startAudioPlayer_l();
- }
-
- modifyFlags(VIDEO_AT_EOS, SET);
- postStreamDoneEvent_l(err);
- return;
- }
-
- if (mVideoBuffer->range_length() == 0) {
- // Some decoders, notably the PV AVC software decoder
- // return spurious empty buffers that we just want to ignore.
-
- mVideoBuffer->release();
- mVideoBuffer = NULL;
- continue;
- }
-
- break;
- }
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- ++mStats.mNumVideoFramesDecoded;
- }
- }
-
- int64_t timeUs;
- CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
-
- mLastVideoTimeUs = timeUs;
-
- if (mSeeking == SEEK_VIDEO_ONLY) {
- if (mSeekTimeUs > timeUs) {
- ALOGI("XXX mSeekTimeUs = %" PRId64 " us, timeUs = %" PRId64 " us",
- mSeekTimeUs, timeUs);
- }
- }
-
- {
- Mutex::Autolock autoLock(mMiscStateLock);
- mVideoTimeUs = timeUs;
- }
-
- SeekType wasSeeking = mSeeking;
- finishSeekIfNecessary(timeUs);
-
- if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
- status_t err = startAudioPlayer_l();
- if (err != OK) {
- ALOGE("Starting the audio player failed w/ err %d", err);
- return;
- }
- }
-
- if ((mFlags & TEXTPLAYER_INITIALIZED)
- && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
- mTextDriver->start();
- modifyFlags(TEXT_RUNNING, SET);
- }
-
- TimeSource *ts =
- ((mFlags & AUDIO_AT_EOS) || !(mFlags & AUDIOPLAYER_STARTED))
- ? &mSystemTimeSource : mTimeSource;
- int64_t systemTimeUs = mSystemTimeSource.getRealTimeUs();
- int64_t looperTimeUs = ALooper::GetNowUs();
-
- if (mFlags & FIRST_FRAME) {
- modifyFlags(FIRST_FRAME, CLEAR);
- mSinceLastDropped = 0;
- mClockEstimator->reset();
- mTimeSourceDeltaUs = estimateRealTimeUs(ts, systemTimeUs) - timeUs;
- }
-
- int64_t realTimeUs, mediaTimeUs;
- if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
- && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
- ALOGV("updating TSdelta (%" PRId64 " => %" PRId64 " change %" PRId64 ")",
- mTimeSourceDeltaUs, realTimeUs - mediaTimeUs,
- mTimeSourceDeltaUs - (realTimeUs - mediaTimeUs));
- ATRACE_INT("TS delta change (ms)", (mTimeSourceDeltaUs - (realTimeUs - mediaTimeUs)) / 1E3);
- mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
- }
-
- if (wasSeeking == SEEK_VIDEO_ONLY) {
- int64_t nowUs = estimateRealTimeUs(ts, systemTimeUs) - mTimeSourceDeltaUs;
-
- int64_t latenessUs = nowUs - timeUs;
-
- ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
-
- if (latenessUs > 0) {
- ALOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6);
- }
- }
-
- int64_t latenessUs = 0;
- if (wasSeeking == NO_SEEK) {
- // Let's display the first frame after seeking right away.
-
- int64_t nowUs = estimateRealTimeUs(ts, systemTimeUs) - mTimeSourceDeltaUs;
-
- latenessUs = nowUs - timeUs;
-
- ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
-
- if (latenessUs > 500000ll
- && mAudioPlayer != NULL
- && mAudioPlayer->getMediaTimeMapping(
- &realTimeUs, &mediaTimeUs)) {
- if (mWVMExtractor == NULL) {
- ALOGI("we're much too late (%.2f secs), video skipping ahead",
- latenessUs / 1E6);
-
- mVideoBuffer->release();
- mVideoBuffer = NULL;
-
- mSeeking = SEEK_VIDEO_ONLY;
- mSeekTimeUs = mediaTimeUs;
-
- postVideoEvent_l();
- return;
- } else {
- // The widevine extractor doesn't deal well with seeking
- // audio and video independently. We'll just have to wait
- // until the decoder catches up, which won't be long at all.
- ALOGI("we're very late (%.2f secs)", latenessUs / 1E6);
- }
- }
-
- if (latenessUs > 40000) {
- // We're more than 40ms late.
- ALOGV("we're late by %" PRId64 " us (%.2f secs)",
- latenessUs, latenessUs / 1E6);
-
- if (!(mFlags & SLOW_DECODER_HACK)
- || mSinceLastDropped > FRAME_DROP_FREQ)
- {
- ALOGV("we're late by %" PRId64 " us (%.2f secs) dropping "
- "one after %d frames",
- latenessUs, latenessUs / 1E6, mSinceLastDropped);
-
- mSinceLastDropped = 0;
- mVideoBuffer->release();
- mVideoBuffer = NULL;
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- ++mStats.mNumVideoFramesDropped;
- }
-
- postVideoEvent_l(0);
- return;
- }
- }
-
- if (latenessUs < -30000) {
- // We're more than 30ms early, schedule at most 20 ms before time due
- postVideoEvent_l(latenessUs < -60000 ? 30000 : -latenessUs - 20000);
- return;
- }
- }
-
- if ((mNativeWindow != NULL)
- && (mVideoRendererIsPreview || mVideoRenderer == NULL)) {
- mVideoRendererIsPreview = false;
-
- initRenderer_l();
- }
-
- if (mVideoRenderer != NULL) {
- mSinceLastDropped++;
- mVideoBuffer->meta_data()->setInt64(kKeyTime, looperTimeUs - latenessUs);
-
- mVideoRenderer->render(mVideoBuffer);
- if (!mVideoRenderingStarted) {
- mVideoRenderingStarted = true;
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START);
- }
-
- if (mFlags & PLAYING) {
- notifyIfMediaStarted_l();
- }
- }
-
- mVideoBuffer->release();
- mVideoBuffer = NULL;
-
- if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) {
- modifyFlags(SEEK_PREVIEW, CLEAR);
- return;
- }
-
- /* get next frame time */
- if (wasSeeking == NO_SEEK) {
- MediaSource::ReadOptions options;
- for (;;) {
- status_t err = mVideoSource->read(&mVideoBuffer, &options);
- if (err != OK) {
- // deal with any errors next time
- CHECK(mVideoBuffer == NULL);
- postVideoEvent_l(0);
- return;
- }
-
- if (mVideoBuffer->range_length() != 0) {
- break;
- }
-
- // Some decoders, notably the PV AVC software decoder
- // return spurious empty buffers that we just want to ignore.
-
- mVideoBuffer->release();
- mVideoBuffer = NULL;
- }
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- ++mStats.mNumVideoFramesDecoded;
- }
-
- int64_t nextTimeUs;
- CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &nextTimeUs));
- systemTimeUs = mSystemTimeSource.getRealTimeUs();
- int64_t delayUs = nextTimeUs - estimateRealTimeUs(ts, systemTimeUs) + mTimeSourceDeltaUs;
- ATRACE_INT("Frame delta (ms)", (nextTimeUs - timeUs) / 1E3);
- ALOGV("next frame in %" PRId64, delayUs);
- // try to schedule 30ms before time due
- postVideoEvent_l(delayUs > 60000 ? 30000 : (delayUs < 30000 ? 0 : delayUs - 30000));
- return;
- }
-
- postVideoEvent_l();
-}
-
-int64_t AwesomePlayer::estimateRealTimeUs(TimeSource *ts, int64_t systemTimeUs) {
- if (ts == &mSystemTimeSource) {
- return systemTimeUs;
- } else {
- return (int64_t)mClockEstimator->estimate(systemTimeUs, ts->getRealTimeUs());
- }
-}
-
-void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
- ATRACE_CALL();
-
- if (mVideoEventPending) {
- return;
- }
-
- mVideoEventPending = true;
- mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
-}
-
-void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
- if (mStreamDoneEventPending) {
- return;
- }
- mStreamDoneEventPending = true;
-
- mStreamDoneStatus = status;
- mQueue.postEvent(mStreamDoneEvent);
-}
-
-void AwesomePlayer::postBufferingEvent_l() {
- if (mBufferingEventPending) {
- return;
- }
- mBufferingEventPending = true;
- mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
-}
-
-void AwesomePlayer::postVideoLagEvent_l() {
- if (mVideoLagEventPending) {
- return;
- }
- mVideoLagEventPending = true;
- mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
-}
-
-void AwesomePlayer::postCheckAudioStatusEvent(int64_t delayUs) {
- Mutex::Autolock autoLock(mAudioLock);
- if (mAudioStatusEventPending) {
- return;
- }
- mAudioStatusEventPending = true;
- // Do not honor delay when looping in order to limit audio gap
- if (mFlags & (LOOPING | AUTO_LOOPING)) {
- delayUs = 0;
- }
- mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs);
-}
-
-void AwesomePlayer::postAudioTearDownEvent(int64_t delayUs) {
- Mutex::Autolock autoLock(mAudioLock);
- if (mAudioTearDownEventPending) {
- return;
- }
- mAudioTearDownEventPending = true;
- mQueue.postEventWithDelay(mAudioTearDownEvent, delayUs);
-}
-
-void AwesomePlayer::onCheckAudioStatus() {
- {
- Mutex::Autolock autoLock(mAudioLock);
- if (!mAudioStatusEventPending) {
- // Event was dispatched and while we were blocking on the mutex,
- // has already been cancelled.
- return;
- }
-
- mAudioStatusEventPending = false;
- }
-
- Mutex::Autolock autoLock(mLock);
-
- if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
- mWatchForAudioSeekComplete = false;
-
- if (!mSeekNotificationSent) {
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- mSeekNotificationSent = true;
- }
-
- if (mVideoSource == NULL) {
- // For video the mSeeking flag is always reset in finishSeekIfNecessary
- mSeeking = NO_SEEK;
- }
-
- notifyIfMediaStarted_l();
- }
-
- status_t finalStatus;
- if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
- mWatchForAudioEOS = false;
- modifyFlags(AUDIO_AT_EOS, SET);
- modifyFlags(FIRST_FRAME, SET);
- postStreamDoneEvent_l(finalStatus);
- }
-}
-
-status_t AwesomePlayer::prepare() {
- ATRACE_CALL();
- Mutex::Autolock autoLock(mLock);
- return prepare_l();
-}
-
-status_t AwesomePlayer::prepare_l() {
- if (mFlags & PREPARED) {
- return OK;
- }
-
- if (mFlags & PREPARING) {
- return UNKNOWN_ERROR;
- }
-
- mIsAsyncPrepare = false;
- status_t err = prepareAsync_l();
-
- if (err != OK) {
- return err;
- }
-
- while (mFlags & PREPARING) {
- mPreparedCondition.wait(mLock);
- }
-
- return mPrepareResult;
-}
-
-status_t AwesomePlayer::prepareAsync() {
- ATRACE_CALL();
- Mutex::Autolock autoLock(mLock);
-
- if (mFlags & PREPARING) {
- return UNKNOWN_ERROR; // async prepare already pending
- }
-
- mIsAsyncPrepare = true;
- return prepareAsync_l();
-}
-
-status_t AwesomePlayer::prepareAsync_l() {
- if (mFlags & PREPARING) {
- return UNKNOWN_ERROR; // async prepare already pending
- }
-
- if (!mQueueStarted) {
- mQueue.start();
- mQueueStarted = true;
- }
-
- modifyFlags(PREPARING, SET);
- mAsyncPrepareEvent = new AwesomeEvent(
- this, &AwesomePlayer::onPrepareAsyncEvent);
-
- mQueue.postEvent(mAsyncPrepareEvent);
-
- return OK;
-}
-
-status_t AwesomePlayer::finishSetDataSource_l() {
- ATRACE_CALL();
- sp<DataSource> dataSource;
-
- bool isWidevineStreaming = false;
- if (!strncasecmp("widevine://", mUri.string(), 11)) {
- isWidevineStreaming = true;
-
- String8 newURI = String8("http://");
- newURI.append(mUri.string() + 11);
-
- mUri = newURI;
- }
-
- AString sniffedMIME;
-
- if (!strncasecmp("http://", mUri.string(), 7)
- || !strncasecmp("https://", mUri.string(), 8)
- || isWidevineStreaming) {
- if (mHTTPService == NULL) {
- ALOGE("Attempt to play media from http URI without HTTP service.");
- return UNKNOWN_ERROR;
- }
-
- sp<IMediaHTTPConnection> conn = mHTTPService->makeHTTPConnection();
- mConnectingDataSource = new MediaHTTP(conn);
-
- String8 cacheConfig;
- bool disconnectAtHighwatermark;
- NuCachedSource2::RemoveCacheSpecificHeaders(
- &mUriHeaders, &cacheConfig, &disconnectAtHighwatermark);
-
- mLock.unlock();
- status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
- // force connection at this point, to avoid a race condition between getMIMEType and the
- // caching datasource constructed below, which could result in multiple requests to the
- // server, and/or failed connections.
- String8 contentType = mConnectingDataSource->getMIMEType();
- mLock.lock();
-
- if (err != OK) {
- mConnectingDataSource.clear();
-
- ALOGI("mConnectingDataSource->connect() returned %d", err);
- return err;
- }
-
- if (!isWidevineStreaming) {
- // The widevine extractor does its own caching.
-
-#if 0
- mCachedSource = NuCachedSource2::Create(
- new ThrottledSource(
- mConnectingDataSource, 50 * 1024 /* bytes/sec */));
-#else
- mCachedSource = NuCachedSource2::Create(
- mConnectingDataSource,
- cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
- disconnectAtHighwatermark);
-#endif
-
- dataSource = mCachedSource;
- } else {
- dataSource = mConnectingDataSource;
- }
-
- mConnectingDataSource.clear();
-
- if (strncasecmp(contentType.string(), "audio/", 6)) {
- // We're not doing this for streams that appear to be audio-only
- // streams to ensure that even low bandwidth streams start
- // playing back fairly instantly.
-
- // We're going to prefill the cache before trying to instantiate
- // the extractor below, as the latter is an operation that otherwise
- // could block on the datasource for a significant amount of time.
- // During that time we'd be unable to abort the preparation phase
- // without this prefill.
- if (mCachedSource != NULL) {
- // We're going to prefill the cache before trying to instantiate
- // the extractor below, as the latter is an operation that otherwise
- // could block on the datasource for a significant amount of time.
- // During that time we'd be unable to abort the preparation phase
- // without this prefill.
-
- mLock.unlock();
-
- // Initially make sure we have at least 192 KB for the sniff
- // to complete without blocking.
- static const size_t kMinBytesForSniffing = 192 * 1024;
-
- off64_t metaDataSize = -1ll;
- for (;;) {
- status_t finalStatus;
- size_t cachedDataRemaining =
- mCachedSource->approxDataRemaining(&finalStatus);
-
- if (finalStatus != OK
- || (metaDataSize >= 0
- && (off64_t)cachedDataRemaining >= metaDataSize)
- || (mFlags & PREPARE_CANCELLED)) {
- break;
- }
-
- ALOGV("now cached %zu bytes of data", cachedDataRemaining);
-
- if (metaDataSize < 0
- && cachedDataRemaining >= kMinBytesForSniffing) {
- String8 tmp;
- float confidence;
- sp<AMessage> meta;
- if (!dataSource->sniff(&tmp, &confidence, &meta)) {
- mLock.lock();
- return UNKNOWN_ERROR;
- }
-
- // We successfully identified the file's extractor to
- // be, remember this mime type so we don't have to
- // sniff it again when we call MediaExtractor::Create()
- // below.
- sniffedMIME = tmp.string();
-
- if (meta == NULL
- || !meta->findInt64("meta-data-size",
- reinterpret_cast<int64_t*>(&metaDataSize))) {
- metaDataSize = kHighWaterMarkBytes;
- }
-
- CHECK_GE(metaDataSize, 0ll);
- ALOGV("metaDataSize = %lld bytes", (long long)metaDataSize);
- }
-
- usleep(200000);
- }
-
- mLock.lock();
- }
-
- if (mFlags & PREPARE_CANCELLED) {
- ALOGI("Prepare cancelled while waiting for initial cache fill.");
- return UNKNOWN_ERROR;
- }
- }
- } else {
- dataSource = DataSource::CreateFromURI(
- mHTTPService, mUri.string(), &mUriHeaders);
- }
-
- if (dataSource == NULL) {
- return UNKNOWN_ERROR;
- }
-
- sp<MediaExtractor> extractor;
-
- if (isWidevineStreaming) {
- String8 mimeType;
- float confidence;
- sp<AMessage> dummy;
- bool success;
-
- // SniffWVM is potentially blocking since it may require network access.
- // Do not call it with mLock held.
- mLock.unlock();
- success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
- mLock.lock();
-
- if (!success
- || strcasecmp(
- mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
- return ERROR_UNSUPPORTED;
- }
-
- mWVMExtractor = new WVMExtractor(dataSource);
- mWVMExtractor->setAdaptiveStreamingMode(true);
- if (mUIDValid)
- mWVMExtractor->setUID(mUID);
- extractor = mWVMExtractor;
- } else {
- extractor = MediaExtractor::Create(
- dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
-
- if (extractor == NULL) {
- return UNKNOWN_ERROR;
- }
- }
-
- if (extractor->getDrmFlag()) {
- checkDrmStatus(dataSource);
- }
-
- status_t err = setDataSource_l(extractor);
-
- if (err != OK) {
- mWVMExtractor.clear();
-
- return err;
- }
-
- return OK;
-}
-
-void AwesomePlayer::abortPrepare(status_t err) {
- CHECK(err != OK);
-
- if (mIsAsyncPrepare) {
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
- }
-
- mPrepareResult = err;
- modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);
- mAsyncPrepareEvent = NULL;
- mPreparedCondition.broadcast();
- mAudioTearDown = false;
-}
-
-// static
-bool AwesomePlayer::ContinuePreparation(void *cookie) {
- AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
-
- return (me->mFlags & PREPARE_CANCELLED) == 0;
-}
-
-void AwesomePlayer::onPrepareAsyncEvent() {
- Mutex::Autolock autoLock(mLock);
- beginPrepareAsync_l();
-}
-
-void AwesomePlayer::beginPrepareAsync_l() {
- if (mFlags & PREPARE_CANCELLED) {
- ALOGI("prepare was cancelled before doing anything");
- abortPrepare(UNKNOWN_ERROR);
- return;
- }
-
- if (mUri.size() > 0) {
- status_t err = finishSetDataSource_l();
-
- if (err != OK) {
- abortPrepare(err);
- return;
- }
- }
-
- if (mVideoTrack != NULL && mVideoSource == NULL) {
- status_t err = initVideoDecoder();
-
- if (err != OK) {
- abortPrepare(err);
- return;
- }
- }
-
- if (mAudioTrack != NULL && mAudioSource == NULL) {
- status_t err = initAudioDecoder();
-
- if (err != OK) {
- abortPrepare(err);
- return;
- }
- }
-
- modifyFlags(PREPARING_CONNECTED, SET);
-
- if (isStreamingHTTP()) {
- postBufferingEvent_l();
- } else {
- finishAsyncPrepare_l();
- }
-}
-
-void AwesomePlayer::finishAsyncPrepare_l() {
- if (mIsAsyncPrepare) {
- if (mVideoSource == NULL) {
- notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
- } else {
- notifyVideoSize_l();
- }
-
- notifyListener_l(MEDIA_PREPARED);
- }
-
- mPrepareResult = OK;
- modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);
- modifyFlags(PREPARED, SET);
- mAsyncPrepareEvent = NULL;
- mPreparedCondition.broadcast();
-
- if (mAudioTearDown) {
- if (mPrepareResult == OK) {
- if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
- seekTo_l(mAudioTearDownPosition);
- }
-
- if (mAudioTearDownWasPlaying) {
- modifyFlags(CACHE_UNDERRUN, CLEAR);
- play_l();
- }
- }
- mAudioTearDown = false;
- }
-}
-
-uint32_t AwesomePlayer::flags() const {
- return mExtractorFlags;
-}
-
-void AwesomePlayer::postAudioEOS(int64_t delayUs) {
- postCheckAudioStatusEvent(delayUs);
-}
-
-void AwesomePlayer::postAudioSeekComplete() {
- postCheckAudioStatusEvent(0);
-}
-
-void AwesomePlayer::postAudioTearDown() {
- postAudioTearDownEvent(0);
-}
-
-status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
- switch (key) {
- case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS:
- {
- return setCacheStatCollectFreq(request);
- }
- default:
- {
- return ERROR_UNSUPPORTED;
- }
- }
-}
-
-status_t AwesomePlayer::setCacheStatCollectFreq(const Parcel &request) {
- if (mCachedSource != NULL) {
- int32_t freqMs = request.readInt32();
- ALOGD("Request to keep cache stats in the past %d ms",
- freqMs);
- return mCachedSource->setCacheStatCollectFreq(freqMs);
- }
- return ERROR_UNSUPPORTED;
-}
-
-status_t AwesomePlayer::getParameter(int key, Parcel *reply) {
- switch (key) {
- case KEY_PARAMETER_AUDIO_CHANNEL_COUNT:
- {
- int32_t channelCount;
- if (mAudioTrack == 0 ||
- !mAudioTrack->getFormat()->findInt32(kKeyChannelCount, &channelCount)) {
- channelCount = 0;
- }
- reply->writeInt32(channelCount);
- }
- return OK;
- default:
- {
- return ERROR_UNSUPPORTED;
- }
- }
-}
-
-status_t AwesomePlayer::setPlaybackSettings(const AudioPlaybackRate &rate) {
- Mutex::Autolock autoLock(mLock);
- // cursory sanity check for non-audio and paused cases
- if ((rate.mSpeed != 0.f && rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN)
- || rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX
- || rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN
- || rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) {
- return BAD_VALUE;
- }
-
- status_t err = OK;
- if (rate.mSpeed == 0.f) {
- if (mFlags & PLAYING) {
- modifyFlags(CACHE_UNDERRUN, CLEAR); // same as pause
- err = pause_l();
- }
- if (err == OK) {
- // save settings (using old speed) in case player is resumed
- AudioPlaybackRate newRate = rate;
- newRate.mSpeed = mPlaybackSettings.mSpeed;
- mPlaybackSettings = newRate;
- }
- return err;
- }
- if (mAudioPlayer != NULL) {
- err = mAudioPlayer->setPlaybackRate(rate);
- }
- if (err == OK) {
- mPlaybackSettings = rate;
- if (!(mFlags & PLAYING)) {
- play_l();
- }
- }
- return err;
-}
-
-status_t AwesomePlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- if (mAudioPlayer != NULL) {
- status_t err = mAudioPlayer->getPlaybackRate(rate);
- if (err == OK) {
- mPlaybackSettings = *rate;
- Mutex::Autolock autoLock(mLock);
- if (!(mFlags & PLAYING)) {
- rate->mSpeed = 0.f;
- }
- }
- return err;
- }
- *rate = mPlaybackSettings;
- return OK;
-}
-
-status_t AwesomePlayer::getTrackInfo(Parcel *reply) const {
- Mutex::Autolock autoLock(mLock);
- size_t trackCount = mExtractor->countTracks();
- if (mTextDriver != NULL) {
- trackCount += mTextDriver->countExternalTracks();
- }
-
- reply->writeInt32(trackCount);
- for (size_t i = 0; i < mExtractor->countTracks(); ++i) {
- sp<MetaData> meta = mExtractor->getTrackMetaData(i);
-
- const char *_mime;
- CHECK(meta->findCString(kKeyMIMEType, &_mime));
-
- String8 mime = String8(_mime);
-
- reply->writeInt32(2); // 2 fields
-
- if (!strncasecmp(mime.string(), "video/", 6)) {
- reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO);
- } else if (!strncasecmp(mime.string(), "audio/", 6)) {
- reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO);
- } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
- reply->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
- } else {
- reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN);
- }
-
- const char *lang;
- if (!meta->findCString(kKeyMediaLanguage, &lang)) {
- lang = "und";
- }
- reply->writeString16(String16(lang));
- }
-
- if (mTextDriver != NULL) {
- mTextDriver->getExternalTrackInfo(reply);
- }
- return OK;
-}
-
-status_t AwesomePlayer::selectAudioTrack_l(
- const sp<MediaSource>& source, size_t trackIndex) {
-
- ALOGI("selectAudioTrack_l: trackIndex=%zu, mFlags=0x%x", trackIndex, mFlags);
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- if ((ssize_t)trackIndex == mActiveAudioTrackIndex) {
- ALOGI("Track %zu is active. Does nothing.", trackIndex);
- return OK;
- }
- //mStats.mFlags = mFlags;
- }
-
- if (mSeeking != NO_SEEK) {
- ALOGE("Selecting a track while seeking is not supported");
- return ERROR_UNSUPPORTED;
- }
-
- if ((mFlags & PREPARED) == 0) {
- ALOGE("Data source has not finished preparation");
- return ERROR_UNSUPPORTED;
- }
-
- CHECK(source != NULL);
- bool wasPlaying = (mFlags & PLAYING) != 0;
-
- pause_l();
-
- int64_t curTimeUs;
- CHECK_EQ(getPosition(&curTimeUs), (status_t)OK);
-
- if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED))
- && mAudioSource != NULL) {
- // If we had an audio player, it would have effectively
- // taken possession of the audio source and stopped it when
- // _it_ is stopped. Otherwise this is still our responsibility.
- mAudioSource->stop();
- }
- mAudioSource.clear();
- mOmxSource.clear();
-
- mTimeSource = NULL;
-
- delete mAudioPlayer;
- mAudioPlayer = NULL;
-
- modifyFlags(AUDIOPLAYER_STARTED, CLEAR);
-
- setAudioSource(source);
-
- modifyFlags(AUDIO_AT_EOS, CLEAR);
- modifyFlags(AT_EOS, CLEAR);
-
- status_t err;
- if ((err = initAudioDecoder()) != OK) {
- ALOGE("Failed to init audio decoder: 0x%x", err);
- return err;
- }
-
- mSeekNotificationSent = true;
- seekTo_l(curTimeUs);
-
- if (wasPlaying) {
- play_l();
- }
-
- mActiveAudioTrackIndex = trackIndex;
-
- return OK;
-}
-
-status_t AwesomePlayer::selectTrack(size_t trackIndex, bool select) {
- ATRACE_CALL();
- ALOGV("selectTrack: trackIndex = %zu and select=%d", trackIndex, select);
- Mutex::Autolock autoLock(mLock);
- size_t trackCount = mExtractor->countTracks();
- if (mTextDriver != NULL) {
- trackCount += mTextDriver->countExternalTracks();
- }
- if (trackIndex >= trackCount) {
- ALOGE("Track index (%zu) is out of range [0, %zu)", trackIndex, trackCount);
- return ERROR_OUT_OF_RANGE;
- }
-
- bool isAudioTrack = false;
- if (trackIndex < mExtractor->countTracks()) {
- sp<MetaData> meta = mExtractor->getTrackMetaData(trackIndex);
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
- isAudioTrack = !strncasecmp(mime, "audio/", 6);
-
- if (!isAudioTrack && strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) != 0) {
- ALOGE("Track %zu is not either audio or timed text", trackIndex);
- return ERROR_UNSUPPORTED;
- }
- }
-
- if (isAudioTrack) {
- if (!select) {
- ALOGE("Deselect an audio track (%zu) is not supported", trackIndex);
- return ERROR_UNSUPPORTED;
- }
- return selectAudioTrack_l(mExtractor->getTrack(trackIndex), trackIndex);
- }
-
- // Timed text track handling
- if (mTextDriver == NULL) {
- return INVALID_OPERATION;
- }
-
- status_t err = OK;
- if (select) {
- err = mTextDriver->selectTrack(trackIndex);
- if (err == OK) {
- modifyFlags(TEXTPLAYER_INITIALIZED, SET);
- if (mFlags & PLAYING && !(mFlags & TEXT_RUNNING)) {
- mTextDriver->start();
- modifyFlags(TEXT_RUNNING, SET);
- }
- }
- } else {
- err = mTextDriver->unselectTrack(trackIndex);
- if (err == OK) {
- modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR);
- modifyFlags(TEXT_RUNNING, CLEAR);
- }
- }
- return err;
-}
-
-size_t AwesomePlayer::countTracks() const {
- return mExtractor->countTracks() + mTextDriver->countExternalTracks();
-}
-
-status_t AwesomePlayer::setVideoScalingMode(int32_t mode) {
- Mutex::Autolock lock(mLock);
- return setVideoScalingMode_l(mode);
-}
-
-status_t AwesomePlayer::setVideoScalingMode_l(int32_t mode) {
- mVideoScalingMode = mode;
- if (mNativeWindow != NULL) {
- status_t err = native_window_set_scaling_mode(
- mNativeWindow.get(), mVideoScalingMode);
- if (err != OK) {
- ALOGW("Failed to set scaling mode: %d", err);
- }
- return err;
- }
- return OK;
-}
-
-status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) {
- ATRACE_CALL();
- if (NULL == reply) {
- return android::BAD_VALUE;
- }
- int32_t methodId;
- status_t ret = request.readInt32(&methodId);
- if (ret != android::OK) {
- return ret;
- }
- switch(methodId) {
- case INVOKE_ID_SET_VIDEO_SCALING_MODE:
- {
- int mode = request.readInt32();
- return setVideoScalingMode(mode);
- }
-
- case INVOKE_ID_GET_TRACK_INFO:
- {
- return getTrackInfo(reply);
- }
- case INVOKE_ID_ADD_EXTERNAL_SOURCE:
- {
- Mutex::Autolock autoLock(mLock);
- if (mTextDriver == NULL) {
- mTextDriver = new TimedTextDriver(mListener, mHTTPService);
- }
- // String values written in Parcel are UTF-16 values.
- String8 uri(request.readString16());
- String8 mimeType(request.readString16());
- size_t nTracks = countTracks();
- return mTextDriver->addOutOfBandTextSource(nTracks, uri, mimeType);
- }
- case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD:
- {
- Mutex::Autolock autoLock(mLock);
- if (mTextDriver == NULL) {
- mTextDriver = new TimedTextDriver(mListener, mHTTPService);
- }
- int fd = request.readFileDescriptor();
- off64_t offset = request.readInt64();
- off64_t length = request.readInt64();
- String8 mimeType(request.readString16());
- size_t nTracks = countTracks();
- return mTextDriver->addOutOfBandTextSource(
- nTracks, fd, offset, length, mimeType);
- }
- case INVOKE_ID_SELECT_TRACK:
- {
- int trackIndex = request.readInt32();
- return selectTrack(trackIndex, true /* select */);
- }
- case INVOKE_ID_UNSELECT_TRACK:
- {
- int trackIndex = request.readInt32();
- return selectTrack(trackIndex, false /* select */);
- }
- default:
- {
- return ERROR_UNSUPPORTED;
- }
- }
- // It will not reach here.
- return OK;
-}
-
-bool AwesomePlayer::isStreamingHTTP() const {
- return mCachedSource != NULL || mWVMExtractor != NULL;
-}
-
-status_t AwesomePlayer::dump(
- int fd, const Vector<String16> & /* args */) const {
- Mutex::Autolock autoLock(mStatsLock);
-
- FILE *out = fdopen(dup(fd), "w");
-
- fprintf(out, " AwesomePlayer\n");
- if (mStats.mFd < 0) {
- fprintf(out, " URI(%s)", uriDebugString(mUri, mFlags & INCOGNITO).c_str());
- } else {
- fprintf(out, " fd(%d)", mStats.mFd);
- }
-
- fprintf(out, ", flags(0x%08x)", mStats.mFlags);
-
- if (mStats.mBitrate >= 0) {
- fprintf(out, ", bitrate(%" PRId64 " bps)", mStats.mBitrate);
- }
-
- fprintf(out, "\n");
-
- for (size_t i = 0; i < mStats.mTracks.size(); ++i) {
- const TrackStat &stat = mStats.mTracks.itemAt(i);
-
- fprintf(out, " Track %zu\n", i + 1);
- fprintf(out, " MIME(%s)", stat.mMIME.string());
-
- if (!stat.mDecoderName.isEmpty()) {
- fprintf(out, ", decoder(%s)", stat.mDecoderName.string());
- }
-
- fprintf(out, "\n");
-
- if ((ssize_t)i == mStats.mVideoTrackIndex) {
- fprintf(out,
- " videoDimensions(%d x %d), "
- "numVideoFramesDecoded(%" PRId64 "), "
- "numVideoFramesDropped(%" PRId64 ")\n",
- mStats.mVideoWidth,
- mStats.mVideoHeight,
- mStats.mNumVideoFramesDecoded,
- mStats.mNumVideoFramesDropped);
- }
- }
-
- fclose(out);
- out = NULL;
-
- return OK;
-}
-
-void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) {
- switch (mode) {
- case SET:
- mFlags |= value;
- break;
- case CLEAR:
- if ((value & CACHE_UNDERRUN) && (mFlags & CACHE_UNDERRUN)) {
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
- }
- mFlags &= ~value;
- break;
- case ASSIGN:
- mFlags = value;
- break;
- default:
- TRESPASS();
- }
-
- {
- Mutex::Autolock autoLock(mStatsLock);
- mStats.mFlags = mFlags;
- }
-}
-
-void AwesomePlayer::onAudioTearDownEvent() {
-
- Mutex::Autolock autoLock(mLock);
- if (!mAudioTearDownEventPending) {
- return;
- }
- mAudioTearDownEventPending = false;
-
- ALOGV("onAudioTearDownEvent");
-
- // stream info is cleared by reset_l() so copy what we need
- mAudioTearDownWasPlaying = (mFlags & PLAYING);
- KeyedVector<String8, String8> uriHeaders(mUriHeaders);
- sp<DataSource> fileSource(mFileSource);
-
- mStatsLock.lock();
- String8 uri(mStats.mURI);
- mStatsLock.unlock();
-
- // get current position so we can start recreated stream from here
- getPosition(&mAudioTearDownPosition);
-
- sp<IMediaHTTPService> savedHTTPService = mHTTPService;
-
- bool wasLooping = mFlags & LOOPING;
- // Reset and recreate
- reset_l();
-
- status_t err;
-
- if (fileSource != NULL) {
- mFileSource = fileSource;
- err = setDataSource_l(fileSource);
- } else {
- err = setDataSource_l(savedHTTPService, uri, &uriHeaders);
- }
-
- mFlags |= PREPARING;
- if ( err != OK ) {
- // This will force beingPrepareAsync_l() to notify
- // a MEDIA_ERROR to the client and abort the prepare
- mFlags |= PREPARE_CANCELLED;
- }
- if (wasLooping) {
- mFlags |= LOOPING;
- }
-
- mAudioTearDown = true;
- mIsAsyncPrepare = true;
-
- // Call prepare for the host decoding
- beginPrepareAsync_l();
-}
-
-} // namespace android
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index e17fdf8..e6303ba 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -64,7 +64,7 @@
mIDataSource->readAt(offset + totalNumRead, numToRead);
// A negative return value represents an error. Pass it on.
if (numRead < 0) {
- return numRead;
+ return numRead == ERROR_END_OF_STREAM && totalNumRead > 0 ? totalNumRead : numRead;
}
// A zero return value signals EOS. Return the bytes read so far.
if (numRead == 0) {
@@ -95,6 +95,10 @@
return OK;
}
+uint32_t CallbackDataSource::flags() {
+ return mIDataSource->getFlags();
+}
+
TinyCacheSource::TinyCacheSource(const sp<DataSource>& source)
: mSource(source), mCachedOffset(0), mCachedSize(0) {
}
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 66280da..64d4302 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -22,6 +22,9 @@
#include <OMX_Component.h>
#include <binder/IPCThreadState.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include <media/hardware/HardwareAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/MediaDefs.h>
@@ -139,8 +142,8 @@
size.height = -1;
sp<ICamera> camera;
- return new CameraSource(camera, NULL, 0, clientName, -1,
- size, -1, NULL, false);
+ return new CameraSource(camera, NULL, 0, clientName, Camera::USE_CALLING_UID,
+ Camera::USE_CALLING_PID, size, -1, NULL, false);
}
// static
@@ -150,13 +153,14 @@
int32_t cameraId,
const String16& clientName,
uid_t clientUid,
+ pid_t clientPid,
Size videoSize,
int32_t frameRate,
const sp<IGraphicBufferProducer>& surface,
bool storeMetaDataInVideoBuffers) {
CameraSource *source = new CameraSource(camera, proxy, cameraId,
- clientName, clientUid, videoSize, frameRate, surface,
+ clientName, clientUid, clientPid, videoSize, frameRate, surface,
storeMetaDataInVideoBuffers);
return source;
}
@@ -167,6 +171,7 @@
int32_t cameraId,
const String16& clientName,
uid_t clientUid,
+ pid_t clientPid,
Size videoSize,
int32_t frameRate,
const sp<IGraphicBufferProducer>& surface,
@@ -190,7 +195,7 @@
mVideoSize.height = -1;
mInitCheck = init(camera, proxy, cameraId,
- clientName, clientUid,
+ clientName, clientUid, clientPid,
videoSize, frameRate,
storeMetaDataInVideoBuffers);
if (mInitCheck != OK) releaseCamera();
@@ -202,10 +207,10 @@
status_t CameraSource::isCameraAvailable(
const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
- int32_t cameraId, const String16& clientName, uid_t clientUid) {
+ int32_t cameraId, const String16& clientName, uid_t clientUid, pid_t clientPid) {
if (camera == 0) {
- mCamera = Camera::connect(cameraId, clientName, clientUid);
+ mCamera = Camera::connect(cameraId, clientName, clientUid, clientPid);
if (mCamera == 0) return -EBUSY;
mCameraFlags &= ~FLAGS_HOT_CAMERA;
} else {
@@ -489,6 +494,7 @@
int32_t cameraId,
const String16& clientName,
uid_t clientUid,
+ pid_t clientPid,
Size videoSize,
int32_t frameRate,
bool storeMetaDataInVideoBuffers) {
@@ -496,19 +502,91 @@
ALOGV("init");
status_t err = OK;
int64_t token = IPCThreadState::self()->clearCallingIdentity();
- err = initWithCameraAccess(camera, proxy, cameraId, clientName, clientUid,
+ err = initWithCameraAccess(camera, proxy, cameraId, clientName, clientUid, clientPid,
videoSize, frameRate,
storeMetaDataInVideoBuffers);
IPCThreadState::self()->restoreCallingIdentity(token);
return err;
}
+status_t CameraSource::initBufferQueue(uint32_t width, uint32_t height,
+ uint32_t format, android_dataspace dataSpace, uint32_t bufferCount) {
+ ALOGV("initBufferQueue");
+
+ if (mVideoBufferConsumer != nullptr || mVideoBufferProducer != nullptr) {
+ ALOGE("%s: Buffer queue already exists", __FUNCTION__);
+ return ALREADY_EXISTS;
+ }
+
+ // Create a buffer queue.
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN;
+ if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ usage = GRALLOC_USAGE_HW_VIDEO_ENCODER;
+ }
+
+ bufferCount += kConsumerBufferCount;
+
+ mVideoBufferConsumer = new BufferItemConsumer(consumer, usage, bufferCount);
+ mVideoBufferConsumer->setName(String8::format("StageFright-CameraSource"));
+ mVideoBufferProducer = producer;
+
+ status_t res = mVideoBufferConsumer->setDefaultBufferSize(width, height);
+ if (res != OK) {
+ ALOGE("%s: Could not set buffer dimensions %dx%d: %s (%d)", __FUNCTION__, width, height,
+ strerror(-res), res);
+ return res;
+ }
+
+ res = mVideoBufferConsumer->setDefaultBufferFormat(format);
+ if (res != OK) {
+ ALOGE("%s: Could not set buffer format %d: %s (%d)", __FUNCTION__, format,
+ strerror(-res), res);
+ return res;
+ }
+
+ res = mVideoBufferConsumer->setDefaultBufferDataSpace(dataSpace);
+ if (res != OK) {
+ ALOGE("%s: Could not set data space %d: %s (%d)", __FUNCTION__, dataSpace,
+ strerror(-res), res);
+ return res;
+ }
+
+ res = mCamera->setVideoTarget(mVideoBufferProducer);
+ if (res != OK) {
+ ALOGE("%s: Failed to set video target: %s (%d)", __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ // Create memory heap to store buffers as VideoNativeMetadata.
+ size_t bufferSize = sizeof(VideoNativeMetadata);
+ mMemoryHeapBase = new MemoryHeapBase(bufferSize * bufferCount, 0,
+ "StageFright-CameraSource-BufferHeap");
+ for (uint32_t i = 0; i < bufferCount; i++) {
+ mMemoryBases.push_back(new MemoryBase(mMemoryHeapBase, i * bufferSize, bufferSize));
+ }
+
+ mBufferQueueListener = new BufferQueueListener(mVideoBufferConsumer, this);
+ res = mBufferQueueListener->run("CameraSource-BufferQueueListener");
+ if (res != OK) {
+ ALOGE("%s: Could not run buffer queue listener thread: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ return res;
+ }
+
+ return OK;
+}
+
status_t CameraSource::initWithCameraAccess(
const sp<ICamera>& camera,
const sp<ICameraRecordingProxy>& proxy,
int32_t cameraId,
const String16& clientName,
uid_t clientUid,
+ pid_t clientPid,
Size videoSize,
int32_t frameRate,
bool storeMetaDataInVideoBuffers) {
@@ -516,7 +594,7 @@
status_t err = OK;
if ((err = isCameraAvailable(camera, proxy, cameraId,
- clientName, clientUid)) != OK) {
+ clientName, clientUid, clientPid)) != OK) {
ALOGE("Camera connection could not be established.");
return err;
}
@@ -551,12 +629,23 @@
CHECK_EQ((status_t)OK, mCamera->setPreviewTarget(mSurface));
}
- // By default, do not store metadata in video buffers
- mIsMetaDataStoredInVideoBuffers = false;
- mCamera->storeMetaDataInBuffers(false);
+ // By default, store real data in video buffers.
+ mVideoBufferMode = ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV;
if (storeMetaDataInVideoBuffers) {
- if (OK == mCamera->storeMetaDataInBuffers(true)) {
- mIsMetaDataStoredInVideoBuffers = true;
+ if (OK == mCamera->setVideoBufferMode(ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE)) {
+ mVideoBufferMode = ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE;
+ } else if (OK == mCamera->setVideoBufferMode(
+ ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA)) {
+ mVideoBufferMode = ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA;
+ }
+ }
+
+ if (mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV) {
+ err = mCamera->setVideoBufferMode(ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV);
+ if (err != OK) {
+ ALOGE("%s: Setting video buffer mode to VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV failed: "
+ "%s (err=%d)", __FUNCTION__, strerror(-err), err);
+ return err;
}
}
@@ -596,28 +685,41 @@
// will connect to the camera in ICameraRecordingProxy::startRecording.
int64_t token = IPCThreadState::self()->clearCallingIdentity();
status_t err;
- if (mNumInputBuffers > 0) {
+
+ if (mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE) {
+ // Initialize buffer queue.
+ err = initBufferQueue(mVideoSize.width, mVideoSize.height, mEncoderFormat,
+ (android_dataspace_t)mEncoderDataSpace,
+ mNumInputBuffers > 0 ? mNumInputBuffers : 1);
+ if (err != OK) {
+ ALOGE("%s: Failed to initialize buffer queue: %s (err=%d)", __FUNCTION__,
+ strerror(-err), err);
+ return err;
+ }
+ } else {
+ if (mNumInputBuffers > 0) {
+ err = mCamera->sendCommand(
+ CAMERA_CMD_SET_VIDEO_BUFFER_COUNT, mNumInputBuffers, 0);
+
+ // This could happen for CameraHAL1 clients; thus the failure is
+ // not a fatal error
+ if (err != OK) {
+ ALOGW("Failed to set video buffer count to %d due to %d",
+ mNumInputBuffers, err);
+ }
+ }
+
err = mCamera->sendCommand(
- CAMERA_CMD_SET_VIDEO_BUFFER_COUNT, mNumInputBuffers, 0);
+ CAMERA_CMD_SET_VIDEO_FORMAT, mEncoderFormat, mEncoderDataSpace);
// This could happen for CameraHAL1 clients; thus the failure is
// not a fatal error
if (err != OK) {
- ALOGW("Failed to set video buffer count to %d due to %d",
- mNumInputBuffers, err);
+ ALOGW("Failed to set video encoder format/dataspace to %d, %d due to %d",
+ mEncoderFormat, mEncoderDataSpace, err);
}
}
- err = mCamera->sendCommand(
- CAMERA_CMD_SET_VIDEO_FORMAT, mEncoderFormat, mEncoderDataSpace);
-
- // This could happen for CameraHAL1 clients; thus the failure is
- // not a fatal error
- if (err != OK) {
- ALOGW("Failed to set video encoder format/dataspace to %d, %d due to %d",
- mEncoderFormat, mEncoderDataSpace, err);
- }
-
err = OK;
if (mCameraFlags & FLAGS_HOT_CAMERA) {
mCamera->unlock();
@@ -690,10 +792,14 @@
void CameraSource::stopCameraRecording() {
ALOGV("stopCameraRecording");
if (mCameraFlags & FLAGS_HOT_CAMERA) {
- mCameraRecordingProxy->stopRecording();
+ if (mCameraRecordingProxy != 0) {
+ mCameraRecordingProxy->stopRecording();
+ }
} else {
- mCamera->setListener(NULL);
- mCamera->stopRecording();
+ if (mCamera != 0) {
+ mCamera->setListener(NULL);
+ mCamera->stopRecording();
+ }
}
}
@@ -771,6 +877,14 @@
CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
}
+ if (mBufferQueueListener != nullptr) {
+ mBufferQueueListener->requestExit();
+ mBufferQueueListener->join();
+ mBufferQueueListener.clear();
+ }
+
+ mVideoBufferConsumer.clear();
+ mVideoBufferProducer.clear();
releaseCamera();
ALOGD("reset: X");
@@ -779,7 +893,33 @@
void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
ALOGV("releaseRecordingFrame");
- if (mCameraRecordingProxy != NULL) {
+
+ if (mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE) {
+ // Return the buffer to buffer queue in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = frame->getMemory(&offset, &size);
+ if (heap->getHeapID() != mMemoryHeapBase->getHeapID()) {
+ ALOGE("%s: Mismatched heap ID, ignoring release (got %x, expected %x)", __FUNCTION__,
+ heap->getHeapID(), mMemoryHeapBase->getHeapID());
+ return;
+ }
+
+ VideoNativeMetadata *payload = reinterpret_cast<VideoNativeMetadata*>(
+ (uint8_t*)heap->getBase() + offset);
+
+ // Find the corresponding buffer item for the native window buffer.
+ ssize_t index = mReceivedBufferItemMap.indexOfKey(payload->pBuffer);
+ if (index == NAME_NOT_FOUND) {
+ ALOGE("%s: Couldn't find buffer item for %p", __FUNCTION__, payload->pBuffer);
+ return;
+ }
+
+ BufferItem buffer = mReceivedBufferItemMap.valueAt(index);
+ mReceivedBufferItemMap.removeItemsAt(index);
+ mVideoBufferConsumer->releaseBuffer(buffer);
+ mMemoryBases.push_back(frame);
+ } else if (mCameraRecordingProxy != NULL) {
mCameraRecordingProxy->releaseRecordingFrame(frame);
} else if (mCamera != NULL) {
int64_t token = IPCThreadState::self()->clearCallingIdentity();
@@ -871,29 +1011,23 @@
return OK;
}
-void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
- int32_t msgType __unused, const sp<IMemory> &data) {
- ALOGV("dataCallbackTimestamp: timestamp %lld us", (long long)timestampUs);
- Mutex::Autolock autoLock(mLock);
+bool CameraSource::shouldSkipFrameLocked(int64_t timestampUs) {
if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
ALOGV("Drop frame at %lld/%lld us", (long long)timestampUs, (long long)mStartTimeUs);
- releaseOneRecordingFrame(data);
- return;
+ return true;
}
// May need to skip frame or modify timestamp. Currently implemented
// by the subclass CameraSourceTimeLapse.
if (skipCurrentFrame(timestampUs)) {
- releaseOneRecordingFrame(data);
- return;
+ return true;
}
if (mNumFramesReceived > 0) {
if (timestampUs <= mLastFrameTimestampUs) {
ALOGW("Dropping frame with backward timestamp %lld (last %lld)",
(long long)timestampUs, (long long)mLastFrameTimestampUs);
- releaseOneRecordingFrame(data);
- return;
+ return true;
}
if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) {
++mNumGlitches;
@@ -908,12 +1042,25 @@
if (timestampUs < mStartTimeUs) {
// Frame was captured before recording was started
// Drop it without updating the statistical data.
- releaseOneRecordingFrame(data);
- return;
+ return true;
}
mStartTimeUs = timestampUs - mStartTimeUs;
}
}
+
+ return false;
+}
+
+void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
+ int32_t msgType __unused, const sp<IMemory> &data) {
+ ALOGV("dataCallbackTimestamp: timestamp %lld us", (long long)timestampUs);
+ Mutex::Autolock autoLock(mLock);
+
+ if (shouldSkipFrameLocked(timestampUs)) {
+ releaseOneRecordingFrame(data);
+ return;
+ }
+
++mNumFramesReceived;
CHECK(data != NULL && data->size() > 0);
@@ -925,9 +1072,97 @@
mFrameAvailableCondition.signal();
}
+CameraSource::BufferQueueListener::BufferQueueListener(const sp<BufferItemConsumer>& consumer,
+ const sp<CameraSource>& cameraSource) {
+ mConsumer = consumer;
+ mConsumer->setFrameAvailableListener(this);
+ mCameraSource = cameraSource;
+}
+
+void CameraSource::BufferQueueListener::onFrameAvailable(const BufferItem& /*item*/) {
+ ALOGV("%s: onFrameAvailable", __FUNCTION__);
+
+ Mutex::Autolock l(mLock);
+
+ if (!mFrameAvailable) {
+ mFrameAvailable = true;
+ mFrameAvailableSignal.signal();
+ }
+}
+
+bool CameraSource::BufferQueueListener::threadLoop() {
+ if (mConsumer == nullptr || mCameraSource == nullptr) {
+ return false;
+ }
+
+ {
+ Mutex::Autolock l(mLock);
+ while (!mFrameAvailable) {
+ if (mFrameAvailableSignal.waitRelative(mLock, kFrameAvailableTimeout) == TIMED_OUT) {
+ return true;
+ }
+ }
+ mFrameAvailable = false;
+ }
+
+ BufferItem buffer;
+ while (mConsumer->acquireBuffer(&buffer, 0) == OK) {
+ mCameraSource->processBufferQueueFrame(buffer);
+ }
+
+ return true;
+}
+
+void CameraSource::processBufferQueueFrame(const BufferItem& buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ int64_t timestampUs = buffer.mTimestamp / 1000;
+ if (shouldSkipFrameLocked(timestampUs)) {
+ mVideoBufferConsumer->releaseBuffer(buffer);
+ return;
+ }
+
+ if (mMemoryBases.empty()) {
+ ALOGW("%s: No available memory base. Dropping a recording frame.", __FUNCTION__);
+ mVideoBufferConsumer->releaseBuffer(buffer);
+ return;
+ }
+
+ ++mNumFramesReceived;
+
+ // Find a available memory slot to store the buffer as VideoNativeMetadata.
+ sp<IMemory> data = *mMemoryBases.begin();
+ mMemoryBases.erase(mMemoryBases.begin());
+
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = data->getMemory(&offset, &size);
+ VideoNativeMetadata *payload = reinterpret_cast<VideoNativeMetadata*>(
+ (uint8_t*)heap->getBase() + offset);
+ memset(payload, 0, sizeof(VideoNativeMetadata));
+ payload->eType = kMetadataBufferTypeANWBuffer;
+ payload->pBuffer = buffer.mGraphicBuffer->getNativeBuffer();
+ payload->nFenceFd = -1;
+
+ // Add the mapping so we can find the corresponding buffer item to release to the buffer queue
+ // when the encoder returns the native window buffer.
+ mReceivedBufferItemMap.add(payload->pBuffer, buffer);
+
+ mFramesReceived.push_back(data);
+ int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
+ mFrameTimes.push_back(timeUs);
+ ALOGV("initial delay: %" PRId64 ", current time stamp: %" PRId64,
+ mStartTimeUs, timeUs);
+ mFrameAvailableCondition.signal();
+}
+
bool CameraSource::isMetaDataStoredInVideoBuffers() const {
ALOGV("isMetaDataStoredInVideoBuffers");
- return mIsMetaDataStoredInVideoBuffers;
+
+ // Output buffers will contain metadata if camera sends us buffer in metadata mode or via
+ // buffer queue.
+ return (mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA ||
+ mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE);
}
CameraSource::ProxyListener::ProxyListener(const sp<CameraSource>& source) {
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 0acd9d0..202ec42 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -40,6 +40,7 @@
int32_t cameraId,
const String16& clientName,
uid_t clientUid,
+ pid_t clientPid,
Size videoSize,
int32_t videoFrameRate,
const sp<IGraphicBufferProducer>& surface,
@@ -48,7 +49,7 @@
CameraSourceTimeLapse *source = new
CameraSourceTimeLapse(camera, proxy, cameraId,
- clientName, clientUid,
+ clientName, clientUid, clientPid,
videoSize, videoFrameRate, surface,
timeBetweenFrameCaptureUs,
storeMetaDataInVideoBuffers);
@@ -68,12 +69,13 @@
int32_t cameraId,
const String16& clientName,
uid_t clientUid,
+ pid_t clientPid,
Size videoSize,
int32_t videoFrameRate,
const sp<IGraphicBufferProducer>& surface,
int64_t timeBetweenFrameCaptureUs,
bool storeMetaDataInVideoBuffers)
- : CameraSource(camera, proxy, cameraId, clientName, clientUid,
+ : CameraSource(camera, proxy, cameraId, clientName, clientUid, clientPid,
videoSize, videoFrameRate, surface,
storeMetaDataInVideoBuffers),
mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate),
diff --git a/media/libstagefright/ClockEstimator.cpp b/media/libstagefright/ClockEstimator.cpp
deleted file mode 100644
index 34d1e42..0000000
--- a/media/libstagefright/ClockEstimator.cpp
+++ /dev/null
@@ -1,177 +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.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "ClockEstimator"
-#include <utils/Log.h>
-
-#include <math.h>
-#include <media/stagefright/ClockEstimator.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace android {
-
-WindowedLinearFitEstimator::WindowedLinearFitEstimator(
- size_t headLength, double headFactor, size_t mainLength, double tailFactor)
- : mHeadFactorInv(1. / headFactor),
- mTailFactor(tailFactor),
- mHistoryLength(mainLength + headLength),
- mHeadLength(headLength) {
- reset();
- mXHistory.resize(mHistoryLength);
- mYHistory.resize(mHistoryLength);
- mFirstWeight = pow(headFactor, mHeadLength);
-}
-
-WindowedLinearFitEstimator::LinearFit::LinearFit() {
- reset();
-}
-
-void WindowedLinearFitEstimator::LinearFit::reset() {
- mX = mXX = mY = mYY = mXY = mW = 0.;
-}
-
-double WindowedLinearFitEstimator::LinearFit::size() const {
- double s = mW * mW + mX * mX + mY * mY + mXX * mXX + mXY * mXY + mYY * mYY;
- if (s > 1e72) {
- // 1e72 corresponds to clock monotonic time of about 8 years
- ALOGW("estimator is overflowing: w=%g x=%g y=%g xx=%g xy=%g yy=%g",
- mW, mX, mY, mXX, mXY, mYY);
- }
- return s;
-}
-
-void WindowedLinearFitEstimator::LinearFit::add(double x, double y, double w) {
- mW += w;
- mX += w * x;
- mY += w * y;
- mXX += w * x * x;
- mXY += w * x * y;
- mYY += w * y * y;
-}
-
-void WindowedLinearFitEstimator::LinearFit::combine(const LinearFit &lf) {
- mW += lf.mW;
- mX += lf.mX;
- mY += lf.mY;
- mXX += lf.mXX;
- mXY += lf.mXY;
- mYY += lf.mYY;
-}
-
-void WindowedLinearFitEstimator::LinearFit::scale(double w) {
- mW *= w;
- mX *= w;
- mY *= w;
- mXX *= w;
- mXY *= w;
- mYY *= w;
-}
-
-double WindowedLinearFitEstimator::LinearFit::interpolate(double x) {
- double div = mW * mXX - mX * mX;
- if (fabs(div) < 1e-5 * mW * mW) {
- // this only should happen on the first value
- return x;
- // assuming a = 1, we could also return x + (mY - mX) / mW;
- }
- double a_div = (mW * mXY - mX * mY);
- double b_div = (mXX * mY - mX * mXY);
- ALOGV("a=%.4g b=%.4g in=%g out=%g",
- a_div / div, b_div / div, x, (a_div * x + b_div) / div);
- return (a_div * x + b_div) / div;
-}
-
-double WindowedLinearFitEstimator::estimate(double x, double y) {
- /*
- * TODO: We could update the head by adding the new sample to it
- * and amplifying it, but this approach can lead to unbounded
- * error. Instead, we recalculate the head at each step, which
- * is computationally more expensive. We could balance the two
- * methods by recalculating just before the error becomes
- * significant.
- */
- const bool update_head = false;
- if (update_head) {
- // add new sample to the head
- mHead.scale(mHeadFactorInv); // amplify head
- mHead.add(x, y, mFirstWeight);
- }
-
- /*
- * TRICKY: place elements into the circular buffer at decreasing
- * indices, so that we can access past elements by addition
- * (thereby avoiding potentially negative indices.)
- */
- if (mNumSamples >= mHeadLength) {
- // move last head sample from head to the main window
- size_t lastHeadIx = (mSampleIx + mHeadLength) % mHistoryLength;
- if (update_head) {
- mHead.add(mXHistory[lastHeadIx], mYHistory[lastHeadIx], -1.); // remove
- }
- mMain.add(mXHistory[lastHeadIx], mYHistory[lastHeadIx], 1.);
- if (mNumSamples >= mHistoryLength) {
- // move last main sample from main window to tail
- mMain.add(mXHistory[mSampleIx], mYHistory[mSampleIx], -1.); // remove
- mTail.add(mXHistory[mSampleIx], mYHistory[mSampleIx], 1.);
- mTail.scale(mTailFactor); // attenuate tail
- }
- }
-
- mXHistory.editItemAt(mSampleIx) = x;
- mYHistory.editItemAt(mSampleIx) = y;
- if (mNumSamples < mHistoryLength) {
- ++mNumSamples;
- }
-
- // recalculate head unless we were using the update method
- if (!update_head) {
- mHead.reset();
- double w = mFirstWeight;
- for (size_t headIx = 0; headIx < mHeadLength && headIx < mNumSamples; ++headIx) {
- size_t ix = (mSampleIx + headIx) % mHistoryLength;
- mHead.add(mXHistory[ix], mYHistory[ix], w);
- w *= mHeadFactorInv;
- }
- }
-
- if (mSampleIx > 0) {
- --mSampleIx;
- } else {
- mSampleIx = mHistoryLength - 1;
- }
-
- // return estimation result
- LinearFit total;
- total.combine(mHead);
- total.combine(mMain);
- total.combine(mTail);
- return total.interpolate(x);
-}
-
-void WindowedLinearFitEstimator::reset() {
- mHead.reset();
- mMain.reset();
- mTail.reset();
- mNumSamples = 0;
- mSampleIx = mHistoryLength - 1;
-}
-
-}; // namespace android
-
-
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index 9cb6e86..255dcd0 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -35,7 +35,7 @@
class DRMSource : public MediaSource {
public:
- DRMSource(const sp<MediaSource> &mediaSource,
+ DRMSource(const sp<IMediaSource> &mediaSource,
const sp<DecryptHandle> &decryptHandle,
DrmManagerClient *managerClient,
int32_t trackId, DrmBuffer *ipmpBox);
@@ -50,7 +50,7 @@
virtual ~DRMSource();
private:
- sp<MediaSource> mOriginalMediaSource;
+ sp<IMediaSource> mOriginalMediaSource;
sp<DecryptHandle> mDecryptHandle;
DrmManagerClient* mDrmManagerClient;
size_t mTrackId;
@@ -64,7 +64,7 @@
////////////////////////////////////////////////////////////////////////////////
-DRMSource::DRMSource(const sp<MediaSource> &mediaSource,
+DRMSource::DRMSource(const sp<IMediaSource> &mediaSource,
const sp<DecryptHandle> &decryptHandle,
DrmManagerClient *managerClient,
int32_t trackId, DrmBuffer *ipmpBox)
@@ -247,8 +247,8 @@
return mOriginalExtractor->countTracks();
}
-sp<MediaSource> DRMExtractor::getTrack(size_t index) {
- sp<MediaSource> originalMediaSource = mOriginalExtractor->getTrack(index);
+sp<IMediaSource> DRMExtractor::getTrack(size_t index) {
+ sp<IMediaSource> originalMediaSource = mOriginalExtractor->getTrack(index);
originalMediaSource->getFormat()->setInt32(kKeyIsDRM, 1);
int32_t trackID;
@@ -258,8 +258,9 @@
ipmpBox.data = mOriginalExtractor->getDrmTrackInfo(trackID, &(ipmpBox.length));
CHECK(ipmpBox.length > 0);
- return new DRMSource(originalMediaSource, mDecryptHandle, mDrmManagerClient,
- trackID, &ipmpBox);
+ return interface_cast<IMediaSource>(
+ new DRMSource(originalMediaSource, mDecryptHandle, mDrmManagerClient,
+ trackID, &ipmpBox));
}
sp<MetaData> DRMExtractor::getTrackMetaData(size_t index, uint32_t flags) {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 5020c6c..163a527 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -48,6 +48,8 @@
#include <cutils/properties.h>
+#include <private/android_filesystem_config.h>
+
namespace android {
bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
@@ -173,7 +175,10 @@
RegisterSniffer_l(SniffMP3);
RegisterSniffer_l(SniffAAC);
RegisterSniffer_l(SniffMPEG2PS);
- RegisterSniffer_l(SniffWVM);
+ if (getuid() == AID_MEDIA) {
+ // WVM only in the media server process
+ RegisterSniffer_l(SniffWVM);
+ }
RegisterSniffer_l(SniffMidi);
char value[PROPERTY_VALUE_MAX];
diff --git a/media/libstagefright/DataURISource.cpp b/media/libstagefright/DataURISource.cpp
index 2c39314..2a61c3a 100644
--- a/media/libstagefright/DataURISource.cpp
+++ b/media/libstagefright/DataURISource.cpp
@@ -42,7 +42,8 @@
AString encoded(commaPos + 1);
// Strip CR and LF...
- for (size_t i = encoded.size(); i-- > 0;) {
+ for (size_t i = encoded.size(); i > 0;) {
+ i--;
if (encoded.c_str()[i] == '\r' || encoded.c_str()[i] == '\n') {
encoded.erase(i, 1);
}
diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp
index 89a91f7..6e99d02 100644
--- a/media/libstagefright/FLACExtractor.cpp
+++ b/media/libstagefright/FLACExtractor.cpp
@@ -807,7 +807,7 @@
return mInitCheck == OK ? 1 : 0;
}
-sp<MediaSource> FLACExtractor::getTrack(size_t index)
+sp<IMediaSource> FLACExtractor::getTrack(size_t index)
{
if (mInitCheck != OK || index > 0) {
return NULL;
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index 565f156..5d762d8 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -20,6 +20,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/FileSource.h>
+#include <media/stagefright/Utils.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
@@ -38,6 +39,7 @@
mDrmBufSize(0),
mDrmBuf(NULL){
+ ALOGV("%s", filename);
mFd = open(filename, O_LARGEFILE | O_RDONLY);
if (mFd >= 0) {
@@ -56,6 +58,9 @@
mDrmBufOffset(0),
mDrmBufSize(0),
mDrmBuf(NULL){
+ ALOGV("fd=%d (%s), offset=%lld, length=%lld",
+ fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
+
CHECK(offset >= 0);
CHECK(length >= 0);
}
@@ -99,8 +104,8 @@
if (offset >= mLength) {
return 0; // read beyond EOF.
}
- int64_t numAvailable = mLength - offset;
- if ((int64_t)size > numAvailable) {
+ uint64_t numAvailable = mLength - offset;
+ if ((uint64_t)size > numAvailable) {
size = numAvailable;
}
}
@@ -166,7 +171,7 @@
}
if (mDrmBuf != NULL && mDrmBufSize > 0 && (offset + mOffset) >= mDrmBufOffset
- && (offset + mOffset + size) <= (mDrmBufOffset + mDrmBufSize)) {
+ && (offset + mOffset + size) <= static_cast<size_t>(mDrmBufOffset + mDrmBufSize)) {
/* Use buffered data */
memcpy(data, (void*)(mDrmBuf+(offset+mOffset-mDrmBufOffset)), size);
return size;
@@ -177,7 +182,7 @@
DRM_CACHE_SIZE, offset + mOffset);
if (mDrmBufSize > 0) {
int64_t dataRead = 0;
- dataRead = size > mDrmBufSize ? mDrmBufSize : size;
+ dataRead = size > static_cast<size_t>(mDrmBufSize) ? mDrmBufSize : size;
memcpy(data, (void*)mDrmBuf, dataRead);
return dataRead;
} else {
diff --git a/media/libstagefright/HevcUtils.cpp b/media/libstagefright/HevcUtils.cpp
new file mode 100644
index 0000000..087c903
--- /dev/null
+++ b/media/libstagefright/HevcUtils.cpp
@@ -0,0 +1,337 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "HevcUtils"
+
+#include <cstring>
+
+#include "include/HevcUtils.h"
+#include "include/avc_utils.h"
+
+#include <media/stagefright/foundation/ABitReader.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+static const uint8_t kHevcNalUnitTypes[5] = {
+ kHevcNalUnitTypeVps,
+ kHevcNalUnitTypeSps,
+ kHevcNalUnitTypePps,
+ kHevcNalUnitTypePrefixSei,
+ kHevcNalUnitTypeSuffixSei,
+};
+
+HevcParameterSets::HevcParameterSets() {
+}
+
+status_t HevcParameterSets::addNalUnit(const uint8_t* data, size_t size) {
+ uint8_t nalUnitType = (data[0] >> 1) & 0x3f;
+ status_t err = OK;
+ switch (nalUnitType) {
+ case 32: // VPS
+ err = parseVps(data + 2, size - 2);
+ break;
+ case 33: // SPS
+ err = parseSps(data + 2, size - 2);
+ break;
+ case 34: // PPS
+ err = parsePps(data + 2, size - 2);
+ break;
+ case 39: // Prefix SEI
+ case 40: // Suffix SEI
+ // Ignore
+ break;
+ default:
+ ALOGE("Unrecognized NAL unit type.");
+ return ERROR_MALFORMED;
+ }
+
+ if (err != OK) {
+ return err;
+ }
+
+ sp<ABuffer> buffer = ABuffer::CreateAsCopy(data, size);
+ buffer->setInt32Data(nalUnitType);
+ mNalUnits.push(buffer);
+ return OK;
+}
+
+template <typename T>
+static bool findParam(uint32_t key, T *param,
+ KeyedVector<uint32_t, uint64_t> ¶ms) {
+ CHECK(param);
+ if (params.indexOfKey(key) < 0) {
+ return false;
+ }
+ *param = (T) params[key];
+ return true;
+}
+
+bool HevcParameterSets::findParam8(uint32_t key, uint8_t *param) {
+ return findParam(key, param, mParams);
+}
+
+bool HevcParameterSets::findParam16(uint32_t key, uint16_t *param) {
+ return findParam(key, param, mParams);
+}
+
+bool HevcParameterSets::findParam32(uint32_t key, uint32_t *param) {
+ return findParam(key, param, mParams);
+}
+
+bool HevcParameterSets::findParam64(uint32_t key, uint64_t *param) {
+ return findParam(key, param, mParams);
+}
+
+size_t HevcParameterSets::getNumNalUnitsOfType(uint8_t type) {
+ size_t num = 0;
+ for (size_t i = 0; i < mNalUnits.size(); ++i) {
+ if (getType(i) == type) {
+ ++num;
+ }
+ }
+ return num;
+}
+
+uint8_t HevcParameterSets::getType(size_t index) {
+ CHECK_LT(index, mNalUnits.size());
+ return mNalUnits[index]->int32Data();
+}
+
+size_t HevcParameterSets::getSize(size_t index) {
+ CHECK_LT(index, mNalUnits.size());
+ return mNalUnits[index]->size();
+}
+
+bool HevcParameterSets::write(size_t index, uint8_t* dest, size_t size) {
+ CHECK_LT(index, mNalUnits.size());
+ const sp<ABuffer>& nalUnit = mNalUnits[index];
+ if (size < nalUnit->size()) {
+ ALOGE("dest buffer size too small: %zu vs. %zu to be written",
+ size, nalUnit->size());
+ return false;
+ }
+ memcpy(dest, nalUnit->data(), nalUnit->size());
+ return true;
+}
+
+status_t HevcParameterSets::parseVps(const uint8_t* data, size_t size) {
+ // See Rec. ITU-T H.265 v3 (04/2015) Chapter 7.3.2.1 for reference
+ NALBitReader reader(data, size);
+ // Skip vps_video_parameter_set_id
+ reader.skipBits(4);
+ // Skip vps_base_layer_internal_flag
+ reader.skipBits(1);
+ // Skip vps_base_layer_available_flag
+ reader.skipBits(1);
+ // Skip vps_max_layers_minus_1
+ reader.skipBits(6);
+ // Skip vps_temporal_id_nesting_flags
+ reader.skipBits(1);
+ // Skip reserved
+ reader.skipBits(16);
+
+ mParams.add(kGeneralProfileSpace, reader.getBits(2));
+ mParams.add(kGeneralTierFlag, reader.getBits(1));
+ mParams.add(kGeneralProfileIdc, reader.getBits(5));
+ mParams.add(kGeneralProfileCompatibilityFlags, reader.getBits(32));
+ mParams.add(
+ kGeneralConstraintIndicatorFlags,
+ ((uint64_t)reader.getBits(16) << 32) | reader.getBits(32));
+ mParams.add(kGeneralLevelIdc, reader.getBits(8));
+ // 96 bits total for general profile.
+
+ return OK;
+}
+
+status_t HevcParameterSets::parseSps(const uint8_t* data, size_t size) {
+ // See Rec. ITU-T H.265 v3 (04/2015) Chapter 7.3.2.2 for reference
+ NALBitReader reader(data, size);
+ // Skip sps_video_parameter_set_id
+ reader.skipBits(4);
+ uint8_t maxSubLayersMinus1 = reader.getBits(3);
+ // Skip sps_temporal_id_nesting_flag;
+ reader.skipBits(1);
+ // Skip general profile
+ reader.skipBits(96);
+ if (maxSubLayersMinus1 > 0) {
+ bool subLayerProfilePresentFlag[8];
+ bool subLayerLevelPresentFlag[8];
+ for (int i = 0; i < maxSubLayersMinus1; ++i) {
+ subLayerProfilePresentFlag[i] = reader.getBits(1);
+ subLayerLevelPresentFlag[i] = reader.getBits(1);
+ }
+ // Skip reserved
+ reader.skipBits(2 * (8 - maxSubLayersMinus1));
+ for (int i = 0; i < maxSubLayersMinus1; ++i) {
+ if (subLayerProfilePresentFlag[i]) {
+ // Skip profile
+ reader.skipBits(88);
+ }
+ if (subLayerLevelPresentFlag[i]) {
+ // Skip sub_layer_level_idc[i]
+ reader.skipBits(8);
+ }
+ }
+ }
+ // Skip sps_seq_parameter_set_id
+ parseUE(&reader);
+ uint8_t chromaFormatIdc = parseUE(&reader);
+ mParams.add(kChromaFormatIdc, chromaFormatIdc);
+ if (chromaFormatIdc == 3) {
+ // Skip separate_colour_plane_flag
+ reader.skipBits(1);
+ }
+ // Skip pic_width_in_luma_samples
+ parseUE(&reader);
+ // Skip pic_height_in_luma_samples
+ parseUE(&reader);
+ if (reader.getBits(1) /* i.e. conformance_window_flag */) {
+ // Skip conf_win_left_offset
+ parseUE(&reader);
+ // Skip conf_win_right_offset
+ parseUE(&reader);
+ // Skip conf_win_top_offset
+ parseUE(&reader);
+ // Skip conf_win_bottom_offset
+ parseUE(&reader);
+ }
+ mParams.add(kBitDepthLumaMinus8, parseUE(&reader));
+ mParams.add(kBitDepthChromaMinus8, parseUE(&reader));
+
+ return OK;
+}
+
+status_t HevcParameterSets::parsePps(
+ const uint8_t* data __unused, size_t size __unused) {
+ return OK;
+}
+
+status_t HevcParameterSets::makeHvcc(uint8_t *hvcc, size_t *hvccSize,
+ size_t nalSizeLength) {
+ if (hvcc == NULL || hvccSize == NULL
+ || (nalSizeLength != 4 && nalSizeLength != 2)) {
+ return BAD_VALUE;
+ }
+ // ISO 14496-15: HEVC file format
+ size_t size = 23; // 23 bytes in the header
+ size_t numOfArrays = 0;
+ const size_t numNalUnits = getNumNalUnits();
+ for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) {
+ uint8_t type = kHevcNalUnitTypes[i];
+ size_t numNalus = getNumNalUnitsOfType(type);
+ if (numNalus == 0) {
+ continue;
+ }
+ ++numOfArrays;
+ size += 3;
+ for (size_t j = 0; j < numNalUnits; ++j) {
+ if (getType(j) != type) {
+ continue;
+ }
+ size += 2 + getSize(j);
+ }
+ }
+ uint8_t generalProfileSpace, generalTierFlag, generalProfileIdc;
+ if (!findParam8(kGeneralProfileSpace, &generalProfileSpace)
+ || !findParam8(kGeneralTierFlag, &generalTierFlag)
+ || !findParam8(kGeneralProfileIdc, &generalProfileIdc)) {
+ return ERROR_MALFORMED;
+ }
+ uint32_t compatibilityFlags;
+ uint64_t constraintIdcFlags;
+ if (!findParam32(kGeneralProfileCompatibilityFlags, &compatibilityFlags)
+ || !findParam64(kGeneralConstraintIndicatorFlags, &constraintIdcFlags)) {
+ return ERROR_MALFORMED;
+ }
+ uint8_t generalLevelIdc;
+ if (!findParam8(kGeneralLevelIdc, &generalLevelIdc)) {
+ return ERROR_MALFORMED;
+ }
+ uint8_t chromaFormatIdc, bitDepthLumaMinus8, bitDepthChromaMinus8;
+ if (!findParam8(kChromaFormatIdc, &chromaFormatIdc)
+ || !findParam8(kBitDepthLumaMinus8, &bitDepthLumaMinus8)
+ || !findParam8(kBitDepthChromaMinus8, &bitDepthChromaMinus8)) {
+ return ERROR_MALFORMED;
+ }
+ if (size > *hvccSize) {
+ return NO_MEMORY;
+ }
+ *hvccSize = size;
+
+ uint8_t *header = hvcc;
+ header[0] = 1;
+ header[1] = (kGeneralProfileSpace << 6) | (kGeneralTierFlag << 5) | kGeneralProfileIdc;
+ header[2] = (compatibilityFlags >> 24) & 0xff;
+ header[3] = (compatibilityFlags >> 16) & 0xff;
+ header[4] = (compatibilityFlags >> 8) & 0xff;
+ header[5] = compatibilityFlags & 0xff;
+ header[6] = (constraintIdcFlags >> 40) & 0xff;
+ header[7] = (constraintIdcFlags >> 32) & 0xff;
+ header[8] = (constraintIdcFlags >> 24) & 0xff;
+ header[9] = (constraintIdcFlags >> 16) & 0xff;
+ header[10] = (constraintIdcFlags >> 8) & 0xff;
+ header[11] = constraintIdcFlags & 0xff;
+ header[12] = generalLevelIdc;
+ // FIXME: parse min_spatial_segmentation_idc.
+ header[13] = 0xf0;
+ header[14] = 0;
+ // FIXME: derive parallelismType properly.
+ header[15] = 0xfc;
+ header[16] = 0xfc | chromaFormatIdc;
+ header[17] = 0xf8 | bitDepthLumaMinus8;
+ header[18] = 0xf8 | bitDepthChromaMinus8;
+ // FIXME: derive avgFrameRate
+ header[19] = 0;
+ header[20] = 0;
+ // constantFrameRate, numTemporalLayers, temporalIdNested all set to 0.
+ header[21] = nalSizeLength - 1;
+ header[22] = numOfArrays;
+ header += 23;
+ for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) {
+ uint8_t type = kHevcNalUnitTypes[i];
+ size_t numNalus = getNumNalUnitsOfType(type);
+ if (numNalus == 0) {
+ continue;
+ }
+ // array_completeness set to 0.
+ header[0] = type;
+ header[1] = (numNalus >> 8) & 0xff;
+ header[2] = numNalus & 0xff;
+ header += 3;
+ for (size_t j = 0; j < numNalUnits; ++j) {
+ if (getType(j) != type) {
+ continue;
+ }
+ header[0] = (getSize(j) >> 8) & 0xff;
+ header[1] = getSize(j) & 0xff;
+ if (!write(j, header + 2, size - (header - (uint8_t *)hvcc))) {
+ return NO_MEMORY;
+ }
+ header += (2 + getSize(j));
+ }
+ }
+ CHECK_EQ(header - size, hvcc);
+
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 2e54e8c..7240e1a 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -400,7 +400,7 @@
return mInitCheck != OK ? 0 : 1;
}
-sp<MediaSource> MP3Extractor::getTrack(size_t index) {
+sp<IMediaSource> MP3Extractor::getTrack(size_t index) {
if (mInitCheck != OK || index != 0) {
return NULL;
}
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index ef07aa0..a9e8846 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -35,7 +35,7 @@
namespace android {
struct MPEG2TSWriter::SourceInfo : public AHandler {
- SourceInfo(const sp<MediaSource> &source);
+ SourceInfo(const sp<IMediaSource> &source);
void start(const sp<AMessage> ¬ify);
void stop();
@@ -69,7 +69,7 @@
kWhatRead = 'read',
};
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
sp<ALooper> mLooper;
sp<AMessage> mNotify;
@@ -93,7 +93,7 @@
DISALLOW_EVIL_CONSTRUCTORS(SourceInfo);
};
-MPEG2TSWriter::SourceInfo::SourceInfo(const sp<MediaSource> &source)
+MPEG2TSWriter::SourceInfo::SourceInfo(const sp<IMediaSource> &source)
: mSource(source),
mLooper(new ALooper),
mEOSReceived(false),
@@ -523,7 +523,7 @@
}
}
-status_t MPEG2TSWriter::addSource(const sp<MediaSource> &source) {
+status_t MPEG2TSWriter::addSource(const sp<IMediaSource> &source) {
CHECK(!mStarted);
sp<MetaData> meta = source->getFormat();
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
old mode 100755
new mode 100644
index e4f8384..6f4a65b
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -766,6 +766,11 @@
status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
ALOGV("entering parseChunk %lld/%d", (long long)*offset, depth);
+
+ if (*offset < 0) {
+ ALOGE("b/23540914");
+ return ERROR_MALFORMED;
+ }
uint32_t hdr[2];
if (mDataSource->readAt(*offset, hdr, 8) < 8) {
return ERROR_IO;
@@ -831,7 +836,12 @@
PathAdder autoAdder(&mPath, chunk_type);
- off64_t chunk_data_size = *offset + chunk_size - data_offset;
+ // (data_offset - *offset) is either 8 or 16
+ off64_t chunk_data_size = chunk_size - (data_offset - *offset);
+ if (chunk_data_size < 0) {
+ ALOGE("b/23540914");
+ return ERROR_MALFORMED;
+ }
if (chunk_type != FOURCC('c', 'p', 'r', 't')
&& chunk_type != FOURCC('c', 'o', 'v', 'r')
@@ -929,6 +939,11 @@
}
if (isTrack) {
+ int32_t trackId;
+ // There must be exact one track header per track.
+ if (!mLastTrack->meta->findInt32(kKeyTrackID, &trackId)) {
+ mLastTrack->skipTrack = true;
+ }
if (mLastTrack->skipTrack) {
Track *cur = mFirstTrack;
@@ -1022,7 +1037,7 @@
int64_t delay = (media_time * samplerate + 500000) / 1000000;
mLastTrack->meta->setInt32(kKeyEncoderDelay, delay);
- int64_t paddingus = duration - (segment_duration + media_time);
+ int64_t paddingus = duration - (int64_t)(segment_duration + media_time);
if (paddingus < 0) {
// track duration from media header (which is what kKeyDuration is) might
// be slightly shorter than the segment duration, which would make the
@@ -2820,7 +2835,7 @@
}
}
-sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
+sp<IMediaSource> MPEG4Extractor::getTrack(size_t index) {
status_t err;
if ((err = readMetaData()) != OK) {
return NULL;
@@ -2851,10 +2866,46 @@
break;
}
}
+ } else {
+ ALOGE("b/21657957");
+ return NULL;
}
ALOGV("getTrack called, pssh: %zu", mPssh.size());
+ const char *mime;
+ if (!track->meta->findCString(kKeyMIMEType, &mime)) {
+ return NULL;
+ }
+
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!track->meta->findData(kKeyAVCC, &type, &data, &size)) {
+ return NULL;
+ }
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ if (size < 7 || ptr[0] != 1) { // configurationVersion == 1
+ return NULL;
+ }
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!track->meta->findData(kKeyHVCC, &type, &data, &size)) {
+ return NULL;
+ }
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ if (size < 22 || ptr[0] != 1) { // configurationVersion == 1
+ return NULL;
+ }
+ }
+
return new MPEG4Source(this,
track->meta, mDataSource, track->timescale, track->sampleTable,
mSidxEntries, trex, mMoofOffset);
@@ -3310,7 +3361,7 @@
const uint8_t *ptr = (const uint8_t *)data;
- CHECK(size >= 7);
+ CHECK(size >= 22);
CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
mNALLengthSize = 1 + (ptr[14 + 7] & 3);
@@ -4698,12 +4749,18 @@
// The smallest valid chunk is 16 bytes long in this case.
return false;
}
+
} else if (chunkSize < 8) {
// The smallest valid chunk is 8 bytes long.
return false;
}
- off64_t chunkDataSize = offset + chunkSize - chunkDataOffset;
+ // (data_offset - offset) is either 8 or 16
+ off64_t chunkDataSize = chunkSize - (chunkDataOffset - offset);
+ if (chunkDataSize < 0) {
+ ALOGE("b/23540914");
+ return ERROR_MALFORMED;
+ }
char chunkstring[5];
MakeFourCCString(chunkType, chunkstring);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 47f114a..a5d9484 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -41,7 +41,7 @@
#include <cutils/properties.h>
#include "include/ESDS.h"
-
+#include "include/HevcUtils.h"
#ifndef __predict_false
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
@@ -70,12 +70,24 @@
#endif
static const char kMetaKey_CaptureFps[] = "com.android.capture.fps";
+static const uint8_t kMandatoryHevcNalUnitTypes[3] = {
+ kHevcNalUnitTypeVps,
+ kHevcNalUnitTypeSps,
+ kHevcNalUnitTypePps,
+};
+static const uint8_t kHevcNalUnitTypes[5] = {
+ kHevcNalUnitTypeVps,
+ kHevcNalUnitTypeSps,
+ kHevcNalUnitTypePps,
+ kHevcNalUnitTypePrefixSei,
+ kHevcNalUnitTypeSuffixSei,
+};
/* uncomment to include model and build in meta */
//#define SHOW_MODEL_BUILD 1
class MPEG4Writer::Track {
public:
- Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId);
+ Track(MPEG4Writer *owner, const sp<IMediaSource> &source, size_t trackId);
~Track();
@@ -89,6 +101,7 @@
void writeTrackHeader(bool use32BitOffset = true);
void bufferChunk(int64_t timestampUs);
bool isAvc() const { return mIsAvc; }
+ bool isHevc() const { return mIsHevc; }
bool isAudio() const { return mIsAudio; }
bool isMPEG4() const { return mIsMPEG4; }
void addChunkOffset(off64_t offset);
@@ -228,12 +241,13 @@
MPEG4Writer *mOwner;
sp<MetaData> mMeta;
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
volatile bool mDone;
volatile bool mPaused;
volatile bool mResumed;
volatile bool mStarted;
bool mIsAvc;
+ bool mIsHevc;
bool mIsAudio;
bool mIsMPEG4;
int32_t mTrackId;
@@ -299,10 +313,17 @@
const uint8_t *parseParamSet(
const uint8_t *data, size_t length, int type, size_t *paramSetLen);
+ status_t copyCodecSpecificData(const uint8_t *data, size_t size, size_t minLength = 0);
+
status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size);
status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size);
status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size);
+ status_t makeHEVCCodecSpecificData(const uint8_t *data, size_t size);
+ status_t copyHEVCCodecSpecificData(const uint8_t *data, size_t size);
+ status_t parseHEVCCodecSpecificData(
+ const uint8_t *data, size_t size, HevcParameterSets ¶mSets);
+
// Track authoring progress status
void trackProgressStatus(int64_t timeUs, status_t err = OK);
void initTrackingProgressStatus(MetaData *params);
@@ -340,6 +361,7 @@
void writeD263Box();
void writePaspBox();
void writeAvccBox();
+ void writeHvccBox();
void writeUrlBox();
void writeDrefBox();
void writeDinfBox();
@@ -463,6 +485,8 @@
return "s263";
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
return "avc1";
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
+ return "hvc1";
}
} else {
ALOGE("Track (%s) other than video or audio is not supported", mime);
@@ -470,7 +494,7 @@
return NULL;
}
-status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
+status_t MPEG4Writer::addSource(const sp<IMediaSource> &source) {
Mutex::Autolock l(mLock);
if (mStarted) {
ALOGE("Attempt to add source AFTER recording is started");
@@ -999,7 +1023,11 @@
// MP4 file uses time counting seconds since midnight, Jan. 1, 1904
// while time function returns Unix epoch values which starts
// at 1970-01-01. Lets add the number of seconds between them
- uint32_t mpeg4Time = now + (66 * 365 + 17) * (24 * 60 * 60);
+ static const uint32_t delta = (66 * 365 + 17) * (24 * 60 * 60);
+ if (now < 0 || uint32_t(now) > UINT32_MAX - delta) {
+ return 0;
+ }
+ uint32_t mpeg4Time = uint32_t(now) + delta;
return mpeg4Time;
}
@@ -1432,7 +1460,7 @@
////////////////////////////////////////////////////////////////////////////////
MPEG4Writer::Track::Track(
- MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
+ MPEG4Writer *owner, const sp<IMediaSource> &source, size_t trackId)
: mOwner(owner),
mMeta(source->getFormat()),
mSource(source),
@@ -1461,6 +1489,7 @@
const char *mime;
mMeta->findCString(kKeyMIMEType, &mime);
mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
+ mIsHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
mIsAudio = !strncasecmp(mime, "audio/", 6);
mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
@@ -1556,31 +1585,26 @@
const char *mime;
CHECK(mMeta->findCString(kKeyMIMEType, &mime));
+ uint32_t type;
+ const void *data = NULL;
+ size_t size = 0;
if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
- uint32_t type;
- const void *data;
- size_t size;
- if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
- mCodecSpecificData = malloc(size);
- mCodecSpecificDataSize = size;
- memcpy(mCodecSpecificData, data, size);
- mGotAllCodecSpecificData = true;
- }
+ mMeta->findData(kKeyAVCC, &type, &data, &size);
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+ mMeta->findData(kKeyHVCC, &type, &data, &size);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
|| !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
- uint32_t type;
- const void *data;
- size_t size;
if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
ESDS esds(data, size);
- if (esds.getCodecSpecificInfo(&data, &size) == OK) {
- mCodecSpecificData = malloc(size);
- mCodecSpecificDataSize = size;
- memcpy(mCodecSpecificData, data, size);
- mGotAllCodecSpecificData = true;
+ if (esds.getCodecSpecificInfo(&data, &size) != OK) {
+ data = NULL;
+ size = 0;
}
}
}
+ if (data != NULL && copyCodecSpecificData((uint8_t *)data, size) == OK) {
+ mGotAllCodecSpecificData = true;
+ }
}
MPEG4Writer::Track::~Track() {
@@ -1657,7 +1681,7 @@
while (!chunk->mSamples.empty()) {
List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
- off64_t offset = chunk->mTrack->isAvc()
+ off64_t offset = (chunk->mTrack->isAvc() || chunk->mTrack->isHevc())
? addLengthPrefixedSample_l(*it)
: addSample_l(*it);
@@ -1964,13 +1988,30 @@
// 2 bytes for each of the parameter set length field
// plus the 7 bytes for the header
- if (size < 4 + 7) {
+ return copyCodecSpecificData(data, size, 4 + 7);
+}
+
+status_t MPEG4Writer::Track::copyHEVCCodecSpecificData(
+ const uint8_t *data, size_t size) {
+ ALOGV("copyHEVCCodecSpecificData");
+
+ // Min length of HEVC CSD is 23. (ISO/IEC 14496-15:2014 Chapter 8.3.3.1.2)
+ return copyCodecSpecificData(data, size, 23);
+}
+
+status_t MPEG4Writer::Track::copyCodecSpecificData(
+ const uint8_t *data, size_t size, size_t minLength) {
+ if (size < minLength) {
ALOGE("Codec specific data length too short: %zu", size);
return ERROR_MALFORMED;
}
- mCodecSpecificDataSize = size;
mCodecSpecificData = malloc(size);
+ if (mCodecSpecificData == NULL) {
+ ALOGE("Failed allocating codec specific data");
+ return NO_MEMORY;
+ }
+ mCodecSpecificDataSize = size;
memcpy(mCodecSpecificData, data, size);
return OK;
}
@@ -2093,6 +2134,11 @@
// ISO 14496-15: AVC file format
mCodecSpecificDataSize += 7; // 7 more bytes in the header
mCodecSpecificData = malloc(mCodecSpecificDataSize);
+ if (mCodecSpecificData == NULL) {
+ mCodecSpecificDataSize = 0;
+ ALOGE("Failed allocating codec specific data");
+ return NO_MEMORY;
+ }
uint8_t *header = (uint8_t *)mCodecSpecificData;
header[0] = 1; // version
header[1] = mProfileIdc; // profile indication
@@ -2141,6 +2187,96 @@
return OK;
}
+
+status_t MPEG4Writer::Track::parseHEVCCodecSpecificData(
+ const uint8_t *data, size_t size, HevcParameterSets ¶mSets) {
+
+ ALOGV("parseHEVCCodecSpecificData");
+ const uint8_t *tmp = data;
+ const uint8_t *nextStartCode = data;
+ size_t bytesLeft = size;
+ while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
+ nextStartCode = findNextStartCode(tmp + 4, bytesLeft - 4);
+ if (nextStartCode == NULL) {
+ return ERROR_MALFORMED;
+ }
+ status_t err = paramSets.addNalUnit(tmp + 4, (nextStartCode - tmp) - 4);
+ if (err != OK) {
+ return ERROR_MALFORMED;
+ }
+
+ // Move on to find the next parameter set
+ bytesLeft -= nextStartCode - tmp;
+ tmp = nextStartCode;
+ }
+
+ size_t csdSize = 23;
+ const size_t numNalUnits = paramSets.getNumNalUnits();
+ for (size_t i = 0; i < ARRAY_SIZE(kMandatoryHevcNalUnitTypes); ++i) {
+ int type = kMandatoryHevcNalUnitTypes[i];
+ size_t numParamSets = paramSets.getNumNalUnitsOfType(type);
+ if (numParamSets == 0) {
+ ALOGE("Cound not find NAL unit of type %d", type);
+ return ERROR_MALFORMED;
+ }
+ }
+ for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) {
+ int type = kHevcNalUnitTypes[i];
+ size_t numParamSets = paramSets.getNumNalUnitsOfType(type);
+ if (numParamSets > 0xffff) {
+ ALOGE("Too many seq parameter sets (%zu) found", numParamSets);
+ return ERROR_MALFORMED;
+ }
+ csdSize += 3;
+ for (size_t j = 0; j < numNalUnits; ++j) {
+ if (paramSets.getType(j) != type) {
+ continue;
+ }
+ csdSize += 2 + paramSets.getSize(j);
+ }
+ }
+ mCodecSpecificDataSize = csdSize;
+ return OK;
+}
+
+status_t MPEG4Writer::Track::makeHEVCCodecSpecificData(
+ const uint8_t *data, size_t size) {
+
+ if (mCodecSpecificData != NULL) {
+ ALOGE("Already have codec specific data");
+ return ERROR_MALFORMED;
+ }
+
+ if (size < 4) {
+ ALOGE("Codec specific data length too short: %zu", size);
+ return ERROR_MALFORMED;
+ }
+
+ // Data is in the form of HEVCCodecSpecificData
+ if (memcmp("\x00\x00\x00\x01", data, 4)) {
+ return copyHEVCCodecSpecificData(data, size);
+ }
+
+ HevcParameterSets paramSets;
+ if (parseHEVCCodecSpecificData(data, size, paramSets) != OK) {
+ return ERROR_MALFORMED;
+ }
+
+ mCodecSpecificData = malloc(mCodecSpecificDataSize);
+ if (mCodecSpecificData == NULL) {
+ mCodecSpecificDataSize = 0;
+ ALOGE("Failed allocating codec specific data");
+ return NO_MEMORY;
+ }
+ status_t err = paramSets.makeHvcc((uint8_t *)mCodecSpecificData,
+ &mCodecSpecificDataSize, mOwner->useNalLengthFour() ? 5 : 2);
+ if (err != OK) {
+ return err;
+ }
+
+ return OK;
+}
+
/*
* Updates the drift time from the audio track so that
* the video track can get the updated drift time information
@@ -2224,13 +2360,15 @@
+ buffer->range_offset(),
buffer->range_length());
CHECK_EQ((status_t)OK, err);
- } else if (mIsMPEG4) {
- mCodecSpecificDataSize = buffer->range_length();
- mCodecSpecificData = malloc(mCodecSpecificDataSize);
- memcpy(mCodecSpecificData,
+ } else if (mIsHevc) {
+ status_t err = makeHEVCCodecSpecificData(
(const uint8_t *)buffer->data()
+ buffer->range_offset(),
- buffer->range_length());
+ buffer->range_length());
+ CHECK_EQ((status_t)OK, err);
+ } else if (mIsMPEG4) {
+ copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(),
+ buffer->range_length());
}
buffer->release();
@@ -2250,10 +2388,10 @@
buffer->release();
buffer = NULL;
- if (mIsAvc) StripStartcode(copy);
+ if (mIsAvc || mIsHevc) StripStartcode(copy);
size_t sampleSize = copy->range_length();
- if (mIsAvc) {
+ if (mIsAvc || mIsHevc) {
if (mOwner->useNalLengthFour()) {
sampleSize += 4;
} else {
@@ -2453,7 +2591,7 @@
trackProgressStatus(timestampUs);
}
if (!hasMultipleTracks) {
- off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
+ off64_t offset = (mIsAvc || mIsHevc) ? mOwner->addLengthPrefixedSample_l(copy)
: mOwner->addSample_l(copy);
uint32_t count = (mOwner->use32BitFileOffset()
@@ -2705,7 +2843,8 @@
CHECK(mMeta->findCString(kKeyMIMEType, &mime));
if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
- !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
+ !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime) ||
+ !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
if (!mCodecSpecificData ||
mCodecSpecificDataSize <= 0) {
ALOGE("Missing codec specific data");
@@ -2811,6 +2950,8 @@
writeD263Box();
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
writeAvccBox();
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
+ writeHvccBox();
}
writePaspBox();
@@ -3066,6 +3207,20 @@
mOwner->endBox(); // avcC
}
+
+void MPEG4Writer::Track::writeHvccBox() {
+ CHECK(mCodecSpecificData);
+ CHECK_GE(mCodecSpecificDataSize, 5);
+
+ // Patch avcc's lengthSize field to match the number
+ // of bytes we use to indicate the size of a nal unit.
+ uint8_t *ptr = (uint8_t *)mCodecSpecificData;
+ ptr[21] = (ptr[21] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
+ mOwner->beginBox("hvcC");
+ mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
+ mOwner->endBox(); // hvcC
+}
+
void MPEG4Writer::Track::writeD263Box() {
mOwner->beginBox("d263");
mOwner->writeInt32(0); // vendor
diff --git a/media/libstagefright/MediaBufferGroup.cpp b/media/libstagefright/MediaBufferGroup.cpp
deleted file mode 100644
index 6ac6d4a..0000000
--- a/media/libstagefright/MediaBufferGroup.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "MediaBufferGroup"
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaBufferGroup.h>
-
-namespace android {
-
-MediaBufferGroup::MediaBufferGroup()
- : mFirstBuffer(NULL),
- mLastBuffer(NULL) {
-}
-
-MediaBufferGroup::~MediaBufferGroup() {
- MediaBuffer *next;
- for (MediaBuffer *buffer = mFirstBuffer; buffer != NULL;
- buffer = next) {
- next = buffer->nextBuffer();
-
- CHECK_EQ(buffer->refcount(), 0);
-
- buffer->setObserver(NULL);
- buffer->release();
- }
-}
-
-void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
- Mutex::Autolock autoLock(mLock);
-
- buffer->setObserver(this);
-
- if (mLastBuffer) {
- mLastBuffer->setNextBuffer(buffer);
- } else {
- mFirstBuffer = buffer;
- }
-
- mLastBuffer = buffer;
-}
-
-status_t MediaBufferGroup::acquire_buffer(
- MediaBuffer **out, bool nonBlocking) {
- Mutex::Autolock autoLock(mLock);
-
- for (;;) {
- for (MediaBuffer *buffer = mFirstBuffer;
- buffer != NULL; buffer = buffer->nextBuffer()) {
- if (buffer->refcount() == 0) {
- buffer->add_ref();
- buffer->reset();
-
- *out = buffer;
- goto exit;
- }
- }
-
- if (nonBlocking) {
- *out = NULL;
- return WOULD_BLOCK;
- }
-
- // All buffers are in use. Block until one of them is returned to us.
- mCondition.wait(mLock);
- }
-
-exit:
- return OK;
-}
-
-void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
- Mutex::Autolock autoLock(mLock);
- mCondition.signal();
-}
-
-} // namespace android
diff --git a/media/libstagefright/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
index 2641e4e..3aa0061 100644
--- a/media/libstagefright/MediaClock.cpp
+++ b/media/libstagefright/MediaClock.cpp
@@ -25,6 +25,10 @@
namespace android {
+// Maximum allowed time backwards from anchor change.
+// If larger than this threshold, it's treated as discontinuity.
+static const int64_t kAnchorFluctuationAllowedUs = 10000ll;
+
MediaClock::MediaClock()
: mAnchorTimeMediaUs(-1),
mAnchorTimeRealUs(-1),
@@ -64,9 +68,20 @@
ALOGW("reject anchor time since it leads to negative media time.");
return;
}
+
+ if (maxTimeMediaUs != -1) {
+ mMaxTimeMediaUs = maxTimeMediaUs;
+ }
+ if (mAnchorTimeRealUs != -1) {
+ int64_t oldNowMediaUs =
+ mAnchorTimeMediaUs + (nowUs - mAnchorTimeRealUs) * (double)mPlaybackRate;
+ if (nowMediaUs < oldNowMediaUs
+ && nowMediaUs > oldNowMediaUs - kAnchorFluctuationAllowedUs) {
+ return;
+ }
+ }
mAnchorTimeRealUs = nowUs;
mAnchorTimeMediaUs = nowMediaUs;
- mMaxTimeMediaUs = maxTimeMediaUs;
}
void MediaClock::updateMaxTimeMedia(int64_t maxTimeMediaUs) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index c2ffdf2..fb1f401 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -44,7 +44,6 @@
#include <media/stagefright/MediaFilter.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/PersistentSurface.h>
#include <media/stagefright/SurfaceUtils.h>
#include <mediautils/BatteryNotifier.h>
@@ -171,7 +170,7 @@
// static
sp<MediaCodec> MediaCodec::CreateByType(
- const sp<ALooper> &looper, const char *mime, bool encoder, status_t *err, pid_t pid) {
+ const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err, pid_t pid) {
sp<MediaCodec> codec = new MediaCodec(looper, pid);
const status_t ret = codec->init(mime, true /* nameIsType */, encoder);
@@ -183,7 +182,7 @@
// static
sp<MediaCodec> MediaCodec::CreateByComponentName(
- const sp<ALooper> &looper, const char *name, status_t *err, pid_t pid) {
+ const sp<ALooper> &looper, const AString &name, status_t *err, pid_t pid) {
sp<MediaCodec> codec = new MediaCodec(looper, pid);
const status_t ret = codec->init(name, false /* nameIsType */, false /* encoder */);
@@ -194,6 +193,22 @@
}
// 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;
CHECK_EQ(client.connect(), (status_t)OK);
@@ -299,6 +314,18 @@
response->postReply(replyID);
}
+//static
+sp<CodecBase> MediaCodec::GetCodecBase(const AString &name, bool nameIsType) {
+ // at this time only ACodec specifies a mime type.
+ if (nameIsType || name.startsWithIgnoreCase("omx.")) {
+ return new ACodec;
+ } else if (name.startsWithIgnoreCase("android.filter.")) {
+ return new MediaFilter;
+ } else {
+ return NULL;
+ }
+}
+
status_t MediaCodec::init(const AString &name, bool nameIsType, bool encoder) {
mResourceManagerService->init();
@@ -312,12 +339,8 @@
// we need to invest in an extra looper to free the main event
// queue.
- if (nameIsType || !strncasecmp(name.c_str(), "omx.", 4)) {
- mCodec = new ACodec;
- } else if (!nameIsType
- && !strncasecmp(name.c_str(), "android.filter.", 15)) {
- mCodec = new MediaFilter;
- } else {
+ mCodec = GetCodecBase(name, nameIsType);
+ if (mCodec == NULL) {
return NAME_NOT_FOUND;
}
@@ -423,6 +446,13 @@
if (!format->findInt32("rotation-degrees", &mRotationDegrees)) {
mRotationDegrees = 0;
}
+
+ // Prevent possible integer overflow in downstream code.
+ if (mInitIsEncoder
+ && (uint64_t)mVideoWidth * mVideoHeight > (uint64_t)INT32_MAX / 4) {
+ ALOGE("buffer size is too big, width=%d, height=%d", mVideoWidth, mVideoHeight);
+ return BAD_VALUE;
+ }
}
msg->setMessage("format", format);
@@ -681,6 +711,7 @@
const uint8_t key[16],
const uint8_t iv[16],
CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern &pattern,
int64_t presentationTimeUs,
uint32_t flags,
AString *errorDetailMsg) {
@@ -696,6 +727,8 @@
msg->setPointer("key", (void *)key);
msg->setPointer("iv", (void *)iv);
msg->setInt32("mode", mode);
+ msg->setInt32("encryptBlocks", pattern.mEncryptBlocks);
+ msg->setInt32("skipBlocks", pattern.mSkipBlocks);
msg->setInt64("timeUs", presentationTimeUs);
msg->setInt32("flags", flags);
msg->setPointer("errorDetailMsg", errorDetailMsg);
@@ -873,33 +906,54 @@
size_t portIndex, size_t index,
sp<ABuffer> *buffer, sp<AMessage> *format) {
// use mutex instead of a context switch
-
if (mReleasedByResourceManager) {
+ ALOGE("getBufferAndFormat - resource already released");
return DEAD_OBJECT;
}
+ if (buffer == NULL) {
+ ALOGE("getBufferAndFormat - null ABuffer");
+ return INVALID_OPERATION;
+ }
+
+ if (format == NULL) {
+ ALOGE("getBufferAndFormat - null AMessage");
+ return INVALID_OPERATION;
+ }
+
buffer->clear();
format->clear();
+
if (!isExecuting()) {
+ ALOGE("getBufferAndFormat - not executing");
return INVALID_OPERATION;
}
// we do not want mPortBuffers to change during this section
// we also don't want mOwnedByClient to change during this
Mutex::Autolock al(mBufferLock);
+
Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
- if (index < buffers->size()) {
- const BufferInfo &info = buffers->itemAt(index);
- if (info.mOwnedByClient) {
- // by the time buffers array is initialized, crypto is set
- if (portIndex == kPortIndexInput && mCrypto != NULL) {
- *buffer = info.mEncryptedData;
- } else {
- *buffer = info.mData;
- }
- *format = info.mFormat;
- }
+ if (index >= buffers->size()) {
+ ALOGE("getBufferAndFormat - trying to get buffer with "
+ "bad index (index=%zu buffer_size=%zu)", index, buffers->size());
+ return INVALID_OPERATION;
}
+
+ const BufferInfo &info = buffers->itemAt(index);
+ if (!info.mOwnedByClient) {
+ ALOGE("getBufferAndFormat - invalid operation "
+ "(the index %zu is not owned by client)", index);
+ return INVALID_OPERATION;
+ }
+
+ // by the time buffers array is initialized, crypto is set
+ *buffer = (portIndex == kPortIndexInput && mCrypto != NULL) ?
+ info.mEncryptedData :
+ info.mData;
+
+ *format = info.mFormat;
+
return OK;
}
@@ -1303,6 +1357,8 @@
info.mBufferID = portDesc->bufferIDAt(i);
info.mOwnedByClient = false;
info.mData = portDesc->bufferAt(i);
+ info.mNativeHandle = portDesc->handleAt(i);
+ info.mMemRef = portDesc->memRefAt(i);
if (portIndex == kPortIndexInput && mCrypto != NULL) {
sp<IMemory> mem = mDealer->allocate(info.mData->capacity());
@@ -1875,7 +1931,7 @@
mCodec->initiateShutdown(
msg->what() == kWhatStop /* keepComponentAllocated */);
- returnBuffersToCodec();
+ returnBuffersToCodec(reclaimed);
if (mSoftRenderer != NULL && (mFlags & kFlagPushBlankBuffersOnShutdown)) {
pushBlankBuffersToNativeWindow(mSurface.get());
@@ -2200,6 +2256,9 @@
if (!format->findBuffer(AStringPrintf("csd-%u", i).c_str(), &csd)) {
break;
}
+ if (csd->size() == 0) {
+ ALOGW("csd-%zu size is 0", i);
+ }
mCSD.push_back(csd);
++i;
@@ -2278,12 +2337,12 @@
updateBatteryStat();
}
-void MediaCodec::returnBuffersToCodec() {
- returnBuffersToCodecOnPort(kPortIndexInput);
- returnBuffersToCodecOnPort(kPortIndexOutput);
+void MediaCodec::returnBuffersToCodec(bool isReclaim) {
+ returnBuffersToCodecOnPort(kPortIndexInput, isReclaim);
+ returnBuffersToCodecOnPort(kPortIndexOutput, isReclaim);
}
-void MediaCodec::returnBuffersToCodecOnPort(int32_t portIndex) {
+void MediaCodec::returnBuffersToCodecOnPort(int32_t portIndex, bool isReclaim) {
CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
Mutex::Autolock al(mBufferLock);
@@ -2295,7 +2354,13 @@
if (info->mNotify != NULL) {
sp<AMessage> msg = info->mNotify;
info->mNotify = NULL;
- info->mOwnedByClient = false;
+ if (isReclaim && info->mOwnedByClient) {
+ ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
+ portIndex, i);
+ } else {
+ info->mMemRef = NULL;
+ info->mOwnedByClient = false;
+ }
if (portIndex == kPortIndexInput) {
/* no error, just returning buffers */
@@ -2357,6 +2422,7 @@
// We allow the simpler queueInputBuffer API to be used even in
// secure mode, by fabricating a single unencrypted subSample.
CryptoPlugin::SubSample ss;
+ CryptoPlugin::Pattern pattern;
if (msg->findSize("size", &size)) {
if (mCrypto != NULL) {
@@ -2367,6 +2433,8 @@
numSubSamples = 1;
key = NULL;
iv = NULL;
+ pattern.mEncryptBlocks = 0;
+ pattern.mSkipBlocks = 0;
}
} else {
if (mCrypto == NULL) {
@@ -2377,6 +2445,8 @@
CHECK(msg->findSize("numSubSamples", &numSubSamples));
CHECK(msg->findPointer("key", (void **)&key));
CHECK(msg->findPointer("iv", (void **)&iv));
+ CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
+ CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
int32_t tmp;
CHECK(msg->findInt32("mode", &tmp));
@@ -2424,16 +2494,27 @@
AString *errorDetailMsg;
CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
+ void *dst_pointer = info->mData->base();
+ ICrypto::DestinationType dst_type = ICrypto::kDestinationTypeOpaqueHandle;
+
+ if (info->mNativeHandle != NULL) {
+ dst_pointer = (void *)info->mNativeHandle.get();
+ dst_type = ICrypto::kDestinationTypeNativeHandle;
+ } else if ((mFlags & kFlagIsSecure) == 0) {
+ dst_type = ICrypto::kDestinationTypeVmPointer;
+ }
+
ssize_t result = mCrypto->decrypt(
- (mFlags & kFlagIsSecure) != 0,
+ dst_type,
key,
iv,
mode,
+ pattern,
info->mSharedEncryptedBuffer,
offset,
subSamples,
numSubSamples,
- info->mData->base(),
+ dst_pointer,
errorDetailMsg);
if (result < 0) {
@@ -2789,25 +2870,15 @@
}
void MediaCodec::updateBatteryStat() {
+ if (!mIsVideo) {
+ return;
+ }
+
if (mState == CONFIGURED && !mBatteryStatNotified) {
- BatteryNotifier& notifier(BatteryNotifier::getInstance());
-
- if (mIsVideo) {
- notifier.noteStartVideo();
- } else {
- notifier.noteStartAudio();
- }
-
+ BatteryNotifier::getInstance().noteStartVideo();
mBatteryStatNotified = true;
} else if (mState == UNINITIALIZED && mBatteryStatNotified) {
- BatteryNotifier& notifier(BatteryNotifier::getInstance());
-
- if (mIsVideo) {
- notifier.noteStopVideo();
- } else {
- notifier.noteStopAudio();
- }
-
+ BatteryNotifier::getInstance().noteStopVideo();
mBatteryStatNotified = false;
}
}
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 5edc04c..0fb5072 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -30,16 +30,17 @@
#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/OMXCodec.h>
#include <sys/stat.h>
#include <utils/threads.h>
#include <cutils/properties.h>
-#include <libexpat/expat.h>
+#include <expat.h>
namespace android {
@@ -751,15 +752,19 @@
ALOGV("initializeCapabilities %s:%s",
mCurrentInfo->mName.c_str(), type);
- CodecCapabilities caps;
- status_t err = QueryCodec(
- mOMX,
- mCurrentInfo->mName.c_str(),
+ 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);
@@ -1115,4 +1120,85 @@
return mGlobalSettings;
}
+//static
+bool MediaCodecList::isSoftwareCodec(const AString &componentName) {
+ return componentName.startsWithIgnoreCase("OMX.google.")
+ || !componentName.startsWithIgnoreCase("OMX.");
+}
+
+static int compareSoftwareCodecsFirst(const AString *name1, const AString *name2) {
+ // sort order 1: software codecs are first (lower)
+ bool isSoftwareCodec1 = MediaCodecList::isSoftwareCodec(*name1);
+ bool isSoftwareCodec2 = MediaCodecList::isSoftwareCodec(*name2);
+ if (isSoftwareCodec1 != isSoftwareCodec2) {
+ return isSoftwareCodec2 - isSoftwareCodec1;
+ }
+
+ // sort order 2: OMX codecs are first (lower)
+ bool isOMX1 = name1->startsWithIgnoreCase("OMX.");
+ bool isOMX2 = name2->startsWithIgnoreCase("OMX.");
+ return isOMX2 - isOMX1;
+}
+
+//static
+void MediaCodecList::findMatchingCodecs(
+ const char *mime, bool encoder, uint32_t flags, Vector<AString> *matches) {
+ matches->clear();
+
+ const sp<IMediaCodecList> list = getInstance();
+ if (list == NULL) {
+ return;
+ }
+
+ size_t index = 0;
+ for (;;) {
+ ssize_t matchIndex =
+ list->findCodecByType(mime, encoder, index);
+
+ if (matchIndex < 0) {
+ break;
+ }
+
+ index = matchIndex + 1;
+
+ const sp<MediaCodecInfo> info = list->getCodecInfo(matchIndex);
+ CHECK(info != NULL);
+ AString componentName = info->getCodecName();
+
+ if (!((flags & kHardwareCodecsOnly) && !isSoftwareCodec(componentName))) {
+ matches->push(componentName);
+ ALOGV("matching '%s'", componentName.c_str());
+ }
+ }
+
+ if (flags & kPreferSoftwareCodecs) {
+ 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;
+}
+
} // namespace android
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 7f9f824..3a3a538 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -30,6 +30,7 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
@@ -42,15 +43,19 @@
const int kDefaultSwVideoEncoderFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
const int kDefaultSwVideoEncoderDataSpace = HAL_DATASPACE_BT709;
+const int kStopTimeoutUs = 300000; // allow 1 sec for shutting down encoder
+
struct MediaCodecSource::Puller : public AHandler {
Puller(const sp<MediaSource> &source);
status_t start(const sp<MetaData> &meta, const sp<AMessage> ¬ify);
void stop();
-
+ void stopSource();
void pause();
void resume();
+ bool readBuffer(MediaBuffer **buffer);
+
protected:
virtual void onMessageReceived(const sp<AMessage> &msg);
virtual ~Puller();
@@ -60,17 +65,31 @@
kWhatStart = 'msta',
kWhatStop,
kWhatPull,
- kWhatPause,
- kWhatResume,
};
sp<MediaSource> mSource;
sp<AMessage> mNotify;
sp<ALooper> mLooper;
- int32_t mPullGeneration;
bool mIsAudio;
- bool mPaused;
- bool mReachedEOS;
+
+ struct Queue {
+ Queue()
+ : mReadPendingSince(0),
+ mPaused(false),
+ mPulling(false) { }
+ int64_t mReadPendingSince;
+ bool mPaused;
+ bool mPulling;
+ Vector<MediaBuffer *> mReadBuffers;
+
+ void flush();
+ // if queue is empty, return false and set *|buffer| to NULL . Otherwise, pop
+ // buffer from front of the queue, place it into *|buffer| and return true.
+ bool readBuffer(MediaBuffer **buffer);
+ // add a buffer to the back of the queue
+ void pushBuffer(MediaBuffer *mbuf);
+ };
+ Mutexed<Queue> mQueue;
status_t postSynchronouslyAndReturnError(const sp<AMessage> &msg);
void schedulePull();
@@ -82,10 +101,8 @@
MediaCodecSource::Puller::Puller(const sp<MediaSource> &source)
: mSource(source),
mLooper(new ALooper()),
- mPullGeneration(0),
- mIsAudio(false),
- mPaused(false),
- mReachedEOS(false) {
+ mIsAudio(false)
+{
sp<MetaData> meta = source->getFormat();
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -100,6 +117,33 @@
mLooper->stop();
}
+void MediaCodecSource::Puller::Queue::pushBuffer(MediaBuffer *mbuf) {
+ mReadBuffers.push_back(mbuf);
+}
+
+bool MediaCodecSource::Puller::Queue::readBuffer(MediaBuffer **mbuf) {
+ if (mReadBuffers.empty()) {
+ *mbuf = NULL;
+ return false;
+ }
+ *mbuf = *mReadBuffers.begin();
+ mReadBuffers.erase(mReadBuffers.begin());
+ return true;
+}
+
+void MediaCodecSource::Puller::Queue::flush() {
+ MediaBuffer *mbuf;
+ while (readBuffer(&mbuf)) {
+ // there are no null buffers in the queue
+ mbuf->release();
+ }
+}
+
+bool MediaCodecSource::Puller::readBuffer(MediaBuffer **mbuf) {
+ Mutexed<Queue>::Locked queue(mQueue);
+ return queue->readBuffer(mbuf);
+}
+
status_t MediaCodecSource::Puller::postSynchronouslyAndReturnError(
const sp<AMessage> &msg) {
sp<AMessage> response;
@@ -116,8 +160,7 @@
return err;
}
-status_t MediaCodecSource::Puller::start(const sp<MetaData> &meta,
- const sp<AMessage> ¬ify) {
+status_t MediaCodecSource::Puller::start(const sp<MetaData> &meta, const sp<AMessage> ¬ify) {
ALOGV("puller (%s) start", mIsAudio ? "audio" : "video");
mLooper->start(
false /* runOnCallingThread */,
@@ -132,41 +175,46 @@
}
void MediaCodecSource::Puller::stop() {
- // Stop source from caller's thread instead of puller's looper.
- // mSource->stop() is thread-safe, doing it outside the puller's
- // looper allows us to at least stop if source gets stuck.
- // If source gets stuck in read(), the looper would never
- // be able to process the stop(), which could lead to ANR.
+ bool interrupt = false;
+ {
+ // mark stopping before actually reaching kWhatStop on the looper, so the pulling will
+ // stop.
+ Mutexed<Queue>::Locked queue(mQueue);
+ queue->mPulling = false;
+ interrupt = queue->mReadPendingSince && (queue->mReadPendingSince < ALooper::GetNowUs() - 1000000);
+ queue->flush(); // flush any unprocessed pulled buffers
+ }
- ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video");
- mSource->stop();
- ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video");
+ if (interrupt) {
+ // call source->stop if read has been pending for over a second
+ // TODO: we should really call this if kWhatStop has not returned for more than a second.
+ mSource->stop();
+ }
+}
+void MediaCodecSource::Puller::stopSource() {
(new AMessage(kWhatStop, this))->post();
}
void MediaCodecSource::Puller::pause() {
- (new AMessage(kWhatPause, this))->post();
+ Mutexed<Queue>::Locked queue(mQueue);
+ queue->mPaused = true;
}
void MediaCodecSource::Puller::resume() {
- (new AMessage(kWhatResume, this))->post();
+ Mutexed<Queue>::Locked queue(mQueue);
+ queue->mPaused = false;
}
void MediaCodecSource::Puller::schedulePull() {
- sp<AMessage> msg = new AMessage(kWhatPull, this);
- msg->setInt32("generation", mPullGeneration);
- msg->post();
+ (new AMessage(kWhatPull, this))->post();
}
void MediaCodecSource::Puller::handleEOS() {
- if (!mReachedEOS) {
- ALOGV("puller (%s) posting EOS", mIsAudio ? "audio" : "video");
- mReachedEOS = true;
- sp<AMessage> notify = mNotify->dup();
- notify->setPointer("accessUnit", NULL);
- notify->post();
- }
+ ALOGV("puller (%s) posting EOS", mIsAudio ? "audio" : "video");
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("eos", 1);
+ msg->post();
}
void MediaCodecSource::Puller::onMessageReceived(const sp<AMessage> &msg) {
@@ -176,7 +224,10 @@
sp<RefBase> obj;
CHECK(msg->findObject("meta", &obj));
- mReachedEOS = false;
+ {
+ Mutexed<Queue>::Locked queue(mQueue);
+ queue->mPulling = true;
+ }
status_t err = mSource->start(static_cast<MetaData *>(obj.get()));
@@ -195,61 +246,52 @@
case kWhatStop:
{
- ++mPullGeneration;
-
- handleEOS();
+ mSource->stop();
break;
}
case kWhatPull:
{
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
-
- if (generation != mPullGeneration) {
+ Mutexed<Queue>::Locked queue(mQueue);
+ queue->mReadPendingSince = ALooper::GetNowUs();
+ if (!queue->mPulling) {
+ handleEOS();
break;
}
- MediaBuffer *mbuf;
+ queue.unlock();
+ MediaBuffer *mbuf = NULL;
status_t err = mSource->read(&mbuf);
+ queue.lock();
- if (mPaused) {
- if (err == OK) {
+ queue->mReadPendingSince = 0;
+ // if we need to discard buffer
+ if (!queue->mPulling || queue->mPaused || err != OK) {
+ if (mbuf != NULL) {
mbuf->release();
mbuf = NULL;
}
-
- msg->post();
- break;
- }
-
- if (err != OK) {
- if (err == ERROR_END_OF_STREAM) {
+ if (queue->mPulling && err == OK) {
+ msg->post(); // if simply paused, keep pulling source
+ } else if (err == ERROR_END_OF_STREAM) {
ALOGV("stream ended, mbuf %p", mbuf);
- } else {
+ } else if (err != OK) {
ALOGE("error %d reading stream.", err);
}
- handleEOS();
- } else {
- sp<AMessage> notify = mNotify->dup();
-
- notify->setPointer("accessUnit", mbuf);
- notify->post();
-
- msg->post();
}
- break;
- }
- case kWhatPause:
- {
- mPaused = true;
- break;
- }
+ if (mbuf != NULL) {
+ queue->pushBuffer(mbuf);
+ }
- case kWhatResume:
- {
- mPaused = false;
+ queue.unlock();
+
+ if (mbuf != NULL) {
+ mNotify->post();
+ msg->post();
+ } else {
+ handleEOS();
+ }
break;
}
@@ -258,6 +300,11 @@
}
}
+MediaCodecSource::Output::Output()
+ : mEncoderReachedEOS(false),
+ mErrorCode(OK) {
+}
+
// static
sp<MediaCodecSource> MediaCodecSource::Create(
const sp<ALooper> &looper,
@@ -274,6 +321,12 @@
return NULL;
}
+void MediaCodecSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
+ sp<AMessage> msg = new AMessage(kWhatSetInputBufferTimeOffset, mReflector);
+ msg->setInt64("time-offset-us", timeOffsetUs);
+ postSynchronouslyAndReturnError(msg);
+}
+
status_t MediaCodecSource::start(MetaData* params) {
sp<AMessage> msg = new AMessage(kWhatStart, mReflector);
msg->setObject("meta", params);
@@ -282,21 +335,7 @@
status_t MediaCodecSource::stop() {
sp<AMessage> msg = new AMessage(kWhatStop, mReflector);
- status_t err = postSynchronouslyAndReturnError(msg);
-
- // mPuller->stop() needs to be done outside MediaCodecSource's looper,
- // as it contains a synchronous call to stop the underlying MediaSource,
- // which often waits for all outstanding MediaBuffers to return, but
- // MediaBuffers are only returned when MediaCodecSource looper gets
- // to process them.
-
- if (mPuller != NULL) {
- ALOGI("puller (%s) stopping", mIsVideo ? "video" : "audio");
- mPuller->stop();
- ALOGI("puller (%s) stopped", mIsVideo ? "video" : "audio");
- }
-
- return err;
+ return postSynchronouslyAndReturnError(msg);
}
status_t MediaCodecSource::pause() {
@@ -311,18 +350,18 @@
status_t MediaCodecSource::read(
MediaBuffer** buffer, const ReadOptions* /* options */) {
- Mutex::Autolock autolock(mOutputBufferLock);
+ Mutexed<Output>::Locked output(mOutput);
*buffer = NULL;
- while (mOutputBufferQueue.size() == 0 && !mEncoderReachedEOS) {
- mOutputBufferCond.wait(mOutputBufferLock);
+ while (output->mBufferQueue.size() == 0 && !output->mEncoderReachedEOS) {
+ output.waitForCondition(output->mCond);
}
- if (!mEncoderReachedEOS) {
- *buffer = *mOutputBufferQueue.begin();
- mOutputBufferQueue.erase(mOutputBufferQueue.begin());
+ if (!output->mEncoderReachedEOS) {
+ *buffer = *output->mBufferQueue.begin();
+ output->mBufferQueue.erase(output->mBufferQueue.begin());
return OK;
}
- return mErrorCode;
+ return output->mErrorCode;
}
void MediaCodecSource::signalBufferReturned(MediaBuffer *buffer) {
@@ -348,9 +387,9 @@
mEncoderFormat(0),
mEncoderDataSpace(0),
mGraphicBufferConsumer(consumer),
+ mInputBufferTimeOffsetUs(0),
mFirstSampleTimeUs(-1ll),
- mEncoderReachedEOS(false),
- mErrorCode(OK) {
+ mGeneration(0) {
CHECK(mLooper != NULL);
AString mime;
@@ -401,24 +440,39 @@
AString outputMIME;
CHECK(mOutputFormat->findString("mime", &outputMIME));
- mEncoder = MediaCodec::CreateByType(
- mCodecLooper, outputMIME.c_str(), true /* encoder */);
+ Vector<AString> matchingCodecs;
+ MediaCodecList::findMatchingCodecs(
+ outputMIME.c_str(), true /* encoder */,
+ ((mFlags & FLAG_PREFER_SOFTWARE_CODEC) ? MediaCodecList::kPreferSoftwareCodecs : 0),
+ &matchingCodecs);
- if (mEncoder == NULL) {
- return NO_INIT;
+ status_t err = NO_INIT;
+ for (size_t ix = 0; ix < matchingCodecs.size(); ++ix) {
+ mEncoder = MediaCodec::CreateByComponentName(
+ mCodecLooper, matchingCodecs[ix]);
+
+ if (mEncoder == NULL) {
+ continue;
+ }
+
+ ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str());
+
+ mEncoderActivityNotify = new AMessage(kWhatEncoderActivity, mReflector);
+ mEncoder->setCallback(mEncoderActivityNotify);
+
+ err = mEncoder->configure(
+ mOutputFormat,
+ NULL /* nativeWindow */,
+ NULL /* crypto */,
+ MediaCodec::CONFIGURE_FLAG_ENCODE);
+
+ if (err == OK) {
+ break;
+ }
+ mEncoder->release();
+ mEncoder = NULL;
}
- ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str());
-
- mEncoderActivityNotify = new AMessage(kWhatEncoderActivity, mReflector);
- mEncoder->setCallback(mEncoderActivityNotify);
-
- status_t err = mEncoder->configure(
- mOutputFormat,
- NULL /* nativeWindow */,
- NULL /* crypto */,
- MediaCodec::CONFIGURE_FLAG_ENCODE);
-
if (err != OK) {
return err;
}
@@ -462,8 +516,11 @@
return err;
}
- mEncoderReachedEOS = false;
- mErrorCode = OK;
+ {
+ Mutexed<Output>::Locked output(mOutput);
+ output->mEncoderReachedEOS = false;
+ output->mErrorCode = OK;
+ }
return OK;
}
@@ -475,14 +532,6 @@
mEncoder->release();
mEncoder.clear();
-
- while (!mInputBufferQueue.empty()) {
- MediaBuffer *mbuf = *mInputBufferQueue.begin();
- mInputBufferQueue.erase(mInputBufferQueue.begin());
- if (mbuf != NULL) {
- mbuf->release();
- }
- }
}
status_t MediaCodecSource::postSynchronouslyAndReturnError(
@@ -502,25 +551,32 @@
}
void MediaCodecSource::signalEOS(status_t err) {
- if (!mEncoderReachedEOS) {
- ALOGV("encoder (%s) reached EOS", mIsVideo ? "video" : "audio");
- {
- Mutex::Autolock autoLock(mOutputBufferLock);
+ bool reachedEOS = false;
+ {
+ Mutexed<Output>::Locked output(mOutput);
+ reachedEOS = output->mEncoderReachedEOS;
+ if (!reachedEOS) {
+ ALOGV("encoder (%s) reached EOS", mIsVideo ? "video" : "audio");
// release all unread media buffers
- for (List<MediaBuffer*>::iterator it = mOutputBufferQueue.begin();
- it != mOutputBufferQueue.end(); it++) {
+ for (List<MediaBuffer*>::iterator it = output->mBufferQueue.begin();
+ it != output->mBufferQueue.end(); it++) {
(*it)->release();
}
- mOutputBufferQueue.clear();
- mEncoderReachedEOS = true;
- mErrorCode = err;
- mOutputBufferCond.signal();
- }
+ output->mBufferQueue.clear();
+ output->mEncoderReachedEOS = true;
+ output->mErrorCode = err;
+ output->mCond.signal();
- releaseEncoder();
+ reachedEOS = true;
+ output.unlock();
+ releaseEncoder();
+ }
}
- if (mStopping && mEncoderReachedEOS) {
+
+ if (mStopping && reachedEOS) {
ALOGI("encoder (%s) stopped", mIsVideo ? "video" : "audio");
+ mPuller->stopSource();
+ ALOGV("source (%s) stopped", mIsVideo ? "video" : "audio");
// posting reply to everyone that's waiting
List<sp<AReplyToken>>::iterator it;
for (it = mStopReplyIDQueue.begin();
@@ -529,6 +585,7 @@
}
mStopReplyIDQueue.clear();
mStopping = false;
+ ++mGeneration;
}
}
@@ -554,11 +611,8 @@
}
status_t MediaCodecSource::feedEncoderInputBuffers() {
- while (!mInputBufferQueue.empty()
- && !mAvailEncoderInputIndices.empty()) {
- MediaBuffer* mbuf = *mInputBufferQueue.begin();
- mInputBufferQueue.erase(mInputBufferQueue.begin());
-
+ MediaBuffer* mbuf = NULL;
+ while (!mAvailEncoderInputIndices.empty() && mPuller->readBuffer(&mbuf)) {
size_t bufferIndex = *mAvailEncoderInputIndices.begin();
mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin());
@@ -568,6 +622,7 @@
if (mbuf != NULL) {
CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
+ timeUs += mInputBufferTimeOffsetUs;
// push decoding time for video, or drift time for audio
if (mIsVideo) {
@@ -676,30 +731,19 @@
switch (msg->what()) {
case kWhatPullerNotify:
{
- MediaBuffer *mbuf;
- CHECK(msg->findPointer("accessUnit", (void**)&mbuf));
-
- if (mbuf == NULL) {
- ALOGV("puller (%s) reached EOS",
- mIsVideo ? "video" : "audio");
+ int32_t eos = 0;
+ if (msg->findInt32("eos", &eos) && eos) {
+ ALOGV("puller (%s) reached EOS", mIsVideo ? "video" : "audio");
signalEOS();
- }
-
- if (mEncoder == NULL) {
- ALOGV("got msg '%s' after encoder shutdown.",
- msg->debugString().c_str());
-
- if (mbuf != NULL) {
- mbuf->release();
- }
-
break;
}
- mInputBufferQueue.push_back(mbuf);
+ if (mEncoder == NULL) {
+ ALOGV("got msg '%s' after encoder shutdown.", msg->debugString().c_str());
+ break;
+ }
feedEncoderInputBuffers();
-
break;
}
case kWhatEncoderActivity:
@@ -749,6 +793,9 @@
if (mIsVideo) {
int64_t decodingTimeUs;
if (mFlags & FLAG_USE_SURFACE_INPUT) {
+ // Time offset is not applied at
+ // feedEncoderInputBuffer() in surface input case.
+ timeUs += mInputBufferTimeOffsetUs;
// GraphicBufferSource is supposed to discard samples
// queued before start, and offset timeUs by start time
CHECK_GE(timeUs, 0ll);
@@ -788,9 +835,9 @@
mbuf->add_ref();
{
- Mutex::Autolock autoLock(mOutputBufferLock);
- mOutputBufferQueue.push_back(mbuf);
- mOutputBufferCond.signal();
+ Mutexed<Output>::Locked output(mOutput);
+ output->mBufferQueue.push_back(mbuf);
+ output->mCond.signal();
}
mEncoder->releaseOutputBuffer(index);
@@ -824,7 +871,7 @@
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
- if (mEncoderReachedEOS) {
+ if (mOutput.lock()->mEncoderReachedEOS) {
// if we already reached EOS, reply and return now
ALOGI("encoder (%s) already stopped",
mIsVideo ? "video" : "audio");
@@ -842,17 +889,41 @@
mStopping = true;
// if using surface, signal source EOS and wait for EOS to come back.
- // otherwise, release encoder and post EOS if haven't done already
+ // otherwise, stop puller (which also clears the input buffer queue)
+ // and wait for the EOS message. We cannot call source->stop() because
+ // the encoder may still be processing input buffers.
if (mFlags & FLAG_USE_SURFACE_INPUT) {
mEncoder->signalEndOfInputStream();
} else {
- signalEOS();
+ mPuller->stop();
}
+
+ // complete stop even if encoder/puller stalled
+ sp<AMessage> timeoutMsg = new AMessage(kWhatStopStalled, mReflector);
+ timeoutMsg->setInt32("generation", mGeneration);
+ timeoutMsg->post(kStopTimeoutUs);
break;
}
+
+ case kWhatStopStalled:
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+ if (generation != mGeneration) {
+ break;
+ }
+
+ if (!(mFlags & FLAG_USE_SURFACE_INPUT)) {
+ ALOGV("source (%s) stopping", mIsVideo ? "video" : "audio");
+ mPuller->stopSource();
+ ALOGV("source (%s) stopped", mIsVideo ? "video" : "audio");
+ }
+ signalEOS();
+ }
+
case kWhatPause:
{
- if (mFlags && FLAG_USE_SURFACE_INPUT) {
+ if (mFlags & FLAG_USE_SURFACE_INPUT) {
suspend();
} else {
CHECK(mPuller != NULL);
@@ -860,6 +931,17 @@
}
break;
}
+ case kWhatSetInputBufferTimeOffset:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ CHECK(msg->findInt64("time-offset-us", &mInputBufferTimeOffsetUs));
+
+ sp<AMessage> response = new AMessage;
+ response->postReply(replyID);
+ break;
+ }
default:
TRESPASS();
}
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 2a50692..845462b 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -28,6 +28,7 @@
const char *MEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp";
const char *MEDIA_MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw";
+const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
@@ -62,6 +63,7 @@
const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
const char *MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
const char *MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608";
+const char *MEDIA_MIMETYPE_TEXT_CEA_708 = "text/cea-708";
const char *MEDIA_MIMETYPE_DATA_TIMED_ID3 = "application/x-id3v4";
} // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index e21fe6e..fe66a58 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -17,6 +17,8 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaExtractor"
#include <utils/Log.h>
+#include <inttypes.h>
+#include <pwd.h>
#include "include/AMRExtractor.h"
#include "include/MP3Extractor.h"
@@ -33,15 +35,34 @@
#include "matroska/MatroskaExtractor.h"
+#include <binder/IServiceManager.h>
+#include <binder/MemoryDealer.h>
+
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
+#include <media/IMediaExtractorService.h>
+#include <cutils/properties.h>
#include <utils/String8.h>
+#include <private/android_filesystem_config.h>
+
namespace android {
+MediaExtractor::MediaExtractor():
+ mIsDrm(false) {
+ if (!LOG_NDEBUG) {
+ uid_t uid = getuid();
+ struct passwd *pw = getpwuid(uid);
+ ALOGI("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
+ }
+
+}
+
+
sp<MetaData> MediaExtractor::getMetaData() {
return new MetaData;
}
@@ -50,9 +71,106 @@
return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
}
+
+
+class RemoteDataSource : public BnDataSource {
+public:
+ enum {
+ kBufferSize = 64 * 1024,
+ };
+
+ static sp<IDataSource> wrap(const sp<DataSource> &source);
+ virtual ~RemoteDataSource();
+
+ virtual sp<IMemory> getIMemory();
+ virtual ssize_t readAt(off64_t offset, size_t size);
+ virtual status_t getSize(off64_t* size);
+ virtual void close();
+ virtual uint32_t getFlags();
+
+private:
+ sp<IMemory> mMemory;
+ sp<DataSource> mSource;
+ RemoteDataSource(const sp<DataSource> &source);
+ DISALLOW_EVIL_CONSTRUCTORS(RemoteDataSource);
+};
+
+
+sp<IDataSource> RemoteDataSource::wrap(const sp<DataSource> &source) {
+ return new RemoteDataSource(source);
+}
+RemoteDataSource::RemoteDataSource(const sp<DataSource> &source) {
+ mSource = source;
+ sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "RemoteDataSource");
+ mMemory = memoryDealer->allocate(kBufferSize);
+ if (mMemory == NULL) {
+ ALOGE("Failed to allocate memory!");
+ }
+}
+RemoteDataSource::~RemoteDataSource() {
+ close();
+}
+sp<IMemory> RemoteDataSource::getIMemory() {
+ return mMemory;
+}
+ssize_t RemoteDataSource::readAt(off64_t offset, size_t size) {
+ ALOGV("readAt(%" PRId64 ", %zu)", offset, size);
+ return mSource->readAt(offset, mMemory->pointer(), size);
+}
+status_t RemoteDataSource::getSize(off64_t* size) {
+ return mSource->getSize(size);
+}
+void RemoteDataSource::close() {
+ mSource = NULL;
+}
+uint32_t RemoteDataSource::getFlags() {
+ return mSource->flags();
+}
+
// static
-sp<MediaExtractor> MediaExtractor::Create(
+sp<IMediaExtractor> MediaExtractor::Create(
const sp<DataSource> &source, const char *mime) {
+ ALOGV("MediaExtractor::Create %s", mime);
+
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("media.stagefright.extractremote", value, NULL)
+ && (!strcmp("0", value) || !strcasecmp("false", value))) {
+ // local extractor
+ ALOGW("creating media extractor in calling process");
+ return CreateFromService(source, mime);
+ } else {
+ // remote extractor
+ ALOGV("get service manager");
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
+
+ // Check if it's WVM, since WVMExtractor needs to be created in the media server process,
+ // not the extractor process.
+ String8 mime8;
+ float confidence;
+ sp<AMessage> meta;
+ if (SniffWVM(source, &mime8, &confidence, &meta) &&
+ !strcasecmp(mime8, MEDIA_MIMETYPE_CONTAINER_WVM)) {
+ return new WVMExtractor(source);
+ }
+
+ if (binder != 0) {
+ sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
+ sp<IMediaExtractor> ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime);
+ return ex;
+ } else {
+ ALOGE("extractor service not running");
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+sp<MediaExtractor> MediaExtractor::CreateFromService(
+ const sp<DataSource> &source, const char *mime) {
+
+ ALOGV("MediaExtractor::CreateFromService %s", mime);
+ DataSource::RegisterDefaultSniffers();
+
sp<AMessage> meta;
String8 tmp;
@@ -110,7 +228,7 @@
ret = new MatroskaExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
ret = new MPEG2TSExtractor(source);
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM) && getuid() == AID_MEDIA) {
// Return now. WVExtractor should not have the DrmFlag set in the block below.
return new WVMExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
index 576471a..a17757a 100644
--- a/media/libstagefright/MediaSource.cpp
+++ b/media/libstagefright/MediaSource.cpp
@@ -22,56 +22,4 @@
MediaSource::~MediaSource() {}
-////////////////////////////////////////////////////////////////////////////////
-
-MediaSource::ReadOptions::ReadOptions() {
- reset();
-}
-
-void MediaSource::ReadOptions::reset() {
- mOptions = 0;
- mSeekTimeUs = 0;
- mLatenessUs = 0;
- mNonBlocking = false;
-}
-
-void MediaSource::ReadOptions::setNonBlocking() {
- mNonBlocking = true;
-}
-
-void MediaSource::ReadOptions::clearNonBlocking() {
- mNonBlocking = false;
-}
-
-bool MediaSource::ReadOptions::getNonBlocking() const {
- return mNonBlocking;
-}
-
-void MediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
- mOptions |= kSeekTo_Option;
- mSeekTimeUs = time_us;
- mSeekMode = mode;
-}
-
-void MediaSource::ReadOptions::clearSeekTo() {
- mOptions &= ~kSeekTo_Option;
- mSeekTimeUs = 0;
- mSeekMode = SEEK_CLOSEST_SYNC;
-}
-
-bool MediaSource::ReadOptions::getSeekTo(
- int64_t *time_us, SeekMode *mode) const {
- *time_us = mSeekTimeUs;
- *mode = mSeekMode;
- return (mOptions & kSeekTo_Option) != 0;
-}
-
-void MediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
- mLatenessUs = lateness_us;
-}
-
-int64_t MediaSource::ReadOptions::getLateBy() const {
- return mLatenessUs;
-}
-
} // namespace android
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index 3a45e25..6f2d868 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -635,7 +635,7 @@
ALOGV("acquired buffer %#llx from input", (long long)bufferItem.mGraphicBuffer->getId());
- status = mInput->detachBuffer(bufferItem.mBuf);
+ status = mInput->detachBuffer(bufferItem.mSlot);
if (status != NO_ERROR) {
ALOGE("detaching buffer from input failed (%d)", status);
if (status == NO_INIT) {
@@ -677,7 +677,6 @@
bufferItem.mCrop,
static_cast<int32_t>(bufferItem.mScalingMode),
bufferItem.mTransform,
- bufferItem.mIsDroppable,
bufferItem.mFence);
// Attach and queue the buffer to the output.
diff --git a/media/libstagefright/MidiExtractor.cpp b/media/libstagefright/MidiExtractor.cpp
index f6b8c84f..7525f57 100644
--- a/media/libstagefright/MidiExtractor.cpp
+++ b/media/libstagefright/MidiExtractor.cpp
@@ -281,7 +281,7 @@
return mInitCheck == OK ? 1 : 0;
}
-sp<MediaSource> MidiExtractor::getTrack(size_t index)
+sp<IMediaSource> MidiExtractor::getTrack(size_t index)
{
if (mInitCheck != OK || index > 0) {
return NULL;
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index f24cf3a..dd7f6b9 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -110,7 +110,8 @@
// at the container mime type.
// The cryptoPluginMode ensures that the extractor will actually
// give us data in a call to MediaSource::read(), unlike its
- // default mode that we use from AwesomePlayer.
+ // default mode that we used in AwesomePlayer.
+ // TODO: change default mode
static_cast<WVMExtractor *>(mImpl.get())->setCryptoPluginMode(true);
} else if (mImpl->getDrmFlag()) {
// For all other drm content, we don't want to expose decrypted
@@ -129,6 +130,9 @@
status_t NuMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
+ ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
+ fd, nameForFd(fd).c_str(), (long long) offset, (long long) size);
+
Mutex::Autolock autoLock(mLock);
if (mImpl != NULL) {
@@ -186,6 +190,10 @@
for (size_t i = 0; i < mImpl->countTracks(); ++i) {
sp<MetaData> meta = mImpl->getTrackMetaData(i);
+ if (meta == NULL) {
+ ALOGW("no metadata for track %zu", i);
+ continue;
+ }
int32_t bitrate;
if (!meta->findInt32(kKeyBitRate, &bitrate)) {
@@ -278,7 +286,7 @@
}
}
- sp<MediaSource> source = mImpl->getTrack(index);
+ sp<IMediaSource> source = mImpl->getTrack(index);
CHECK_EQ((status_t)OK, source->start());
@@ -442,6 +450,59 @@
return OK;
}
+status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer) {
+ int32_t numPageSamples;
+ if (!info->mSample->meta_data()->findInt32(
+ kKeyValidSamples, &numPageSamples)) {
+ numPageSamples = -1;
+ }
+
+ memcpy((uint8_t *)buffer->data() + info->mSample->range_length(),
+ &numPageSamples,
+ sizeof(numPageSamples));
+
+ uint32_t type;
+ const void *data;
+ size_t size, size2;
+ if (info->mSample->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+ // Signal numPageSamples (a plain int32_t) is appended at the end,
+ // i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes
+ if (SIZE_MAX - size < sizeof(int32_t)) {
+ return -ENOMEM;
+ }
+
+ size_t newSize = size + sizeof(int32_t);
+ sp<ABuffer> abuf = new ABuffer(newSize);
+ uint8_t *adata = static_cast<uint8_t *>(abuf->data());
+ if (adata == NULL) {
+ return -ENOMEM;
+ }
+
+ // append 0 to encrypted sizes
+ int32_t zero = 0;
+ memcpy(adata, data, size);
+ memcpy(adata + size, &zero, sizeof(zero));
+ info->mSample->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize);
+
+ if (info->mSample->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) {
+ if (size2 != size) {
+ return ERROR_MALFORMED;
+ }
+ memcpy(adata, data, size);
+ } else {
+ // if sample meta data does not include plain size array, assume filled with zeros,
+ // i.e. entire buffer is encrypted
+ memset(adata, 0, size);
+ }
+ // append sizeof(numPageSamples) to plain sizes.
+ int32_t int32Size = sizeof(numPageSamples);
+ memcpy(adata + size, &int32Size, sizeof(int32Size));
+ info->mSample->meta_data()->setData(kKeyPlainSizes, type, adata, newSize);
+ }
+
+ return OK;
+}
+
status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) {
Mutex::Autolock autoLock(mLock);
@@ -471,21 +532,16 @@
memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length());
+ status_t err = OK;
if (info->mTrackFlags & kIsVorbis) {
- int32_t numPageSamples;
- if (!info->mSample->meta_data()->findInt32(
- kKeyValidSamples, &numPageSamples)) {
- numPageSamples = -1;
- }
-
- memcpy((uint8_t *)buffer->data() + info->mSample->range_length(),
- &numPageSamples,
- sizeof(numPageSamples));
+ err = appendVorbisNumPageSamples(info, buffer);
}
- buffer->setRange(0, sampleSize);
+ if (err == OK) {
+ buffer->setRange(0, sampleSize);
+ }
- return OK;
+ return err;
}
status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index e69890d..8e72405 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -25,19 +25,29 @@
#include <binder/IServiceManager.h>
#include <media/IMediaPlayerService.h>
+#include <media/IMediaCodecService.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/OMXClient.h>
+#include <cutils/properties.h>
#include <utils/KeyedVector.h>
#include "include/OMX.h"
namespace android {
+static bool sCodecProcessEnabled = true;
+
struct MuxOMX : public IOMX {
- MuxOMX(const sp<IOMX> &remoteOMX);
+ MuxOMX(const sp<IOMX> &mediaServerOMX, const sp<IOMX> &mediaCodecOMX);
virtual ~MuxOMX();
- virtual IBinder *onAsBinder() { return IInterface::asBinder(mRemoteOMX).get(); }
+ // Nobody should be calling this. In case someone does anyway, just
+ // return the media server IOMX.
+ // TODO: return NULL
+ virtual IBinder *onAsBinder() {
+ ALOGE("MuxOMX::onAsBinder should not be called");
+ return IInterface::asBinder(mMediaServerOMX).get();
+ }
virtual bool livesLocally(node_id node, pid_t pid);
@@ -45,6 +55,7 @@
virtual status_t allocateNode(
const char *name, const sp<IOMXObserver> &observer,
+ sp<IBinder> *nodeBinder,
node_id *node);
virtual status_t freeNode(node_id node);
@@ -82,8 +93,8 @@
node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
OMX_U32 audioHwSync, native_handle_t **sidebandHandle);
- virtual status_t enableGraphicBuffers(
- node_id node, OMX_U32 port_index, OMX_BOOL enable);
+ virtual status_t enableNativeBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL graphic, OMX_BOOL enable);
virtual status_t getGraphicBufferUsage(
node_id node, OMX_U32 port_index, OMX_U32* usage);
@@ -114,9 +125,9 @@
virtual status_t signalEndOfInputStream(node_id node);
- virtual status_t allocateBuffer(
+ virtual status_t allocateSecureBuffer(
node_id node, OMX_U32 port_index, size_t size,
- buffer_id *buffer, void **buffer_data);
+ buffer_id *buffer, void **buffer_data, native_handle_t **native_handle);
virtual status_t allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
@@ -148,23 +159,32 @@
private:
mutable Mutex mLock;
- sp<IOMX> mRemoteOMX;
+ sp<IOMX> mMediaServerOMX;
+ sp<IOMX> mMediaCodecOMX;
sp<IOMX> mLocalOMX;
- KeyedVector<node_id, bool> mIsLocalNode;
+ typedef enum {
+ LOCAL,
+ MEDIAPROCESS,
+ CODECPROCESS
+ } node_location;
+
+ KeyedVector<node_id, node_location> mNodeLocation;
bool isLocalNode(node_id node) const;
bool isLocalNode_l(node_id node) const;
const sp<IOMX> &getOMX(node_id node) const;
const sp<IOMX> &getOMX_l(node_id node) const;
- static bool CanLiveLocally(const char *name);
+ static node_location getPreferredCodecLocation(const char *name);
DISALLOW_EVIL_CONSTRUCTORS(MuxOMX);
};
-MuxOMX::MuxOMX(const sp<IOMX> &remoteOMX)
- : mRemoteOMX(remoteOMX) {
+MuxOMX::MuxOMX(const sp<IOMX> &mediaServerOMX, const sp<IOMX> &mediaCodecOMX)
+ : mMediaServerOMX(mediaServerOMX),
+ mMediaCodecOMX(mediaCodecOMX) {
+ ALOGI("MuxOMX ctor");
}
MuxOMX::~MuxOMX() {
@@ -177,27 +197,49 @@
}
bool MuxOMX::isLocalNode_l(node_id node) const {
- return mIsLocalNode.indexOfKey(node) >= 0;
+ return mNodeLocation.valueFor(node) == LOCAL;
}
// static
-bool MuxOMX::CanLiveLocally(const char *name) {
+MuxOMX::node_location MuxOMX::getPreferredCodecLocation(const char *name) {
+ if (sCodecProcessEnabled) {
+ // all non-secure decoders plus OMX.google.* encoders can go in the codec process
+ if ((strcasestr(name, "decoder") && !strcasestr(name, "secure")) ||
+ !strncasecmp(name, "OMX.google.", 11)) {
+ return CODECPROCESS;
+ }
+ // everything else runs in the media server
+ return MEDIAPROCESS;
+ } else {
#ifdef __LP64__
- (void)name; // disable unused parameter warning
- // 64 bit processes always run OMX remote on MediaServer
- return false;
+ // 64 bit processes always run OMX remote on MediaServer
+ return MEDIAPROCESS;
#else
- // 32 bit processes run only OMX.google.* components locally
- return !strncasecmp(name, "OMX.google.", 11);
+ // 32 bit processes run only OMX.google.* components locally
+ if (!strncasecmp(name, "OMX.google.", 11)) {
+ return LOCAL;
+ }
+ return MEDIAPROCESS;
#endif
+ }
}
const sp<IOMX> &MuxOMX::getOMX(node_id node) const {
- return isLocalNode(node) ? mLocalOMX : mRemoteOMX;
+ Mutex::Autolock autoLock(mLock);
+ return getOMX_l(node);
}
const sp<IOMX> &MuxOMX::getOMX_l(node_id node) const {
- return isLocalNode_l(node) ? mLocalOMX : mRemoteOMX;
+ node_location loc = mNodeLocation.valueFor(node);
+ if (loc == LOCAL) {
+ return mLocalOMX;
+ } else if (loc == MEDIAPROCESS) {
+ return mMediaServerOMX;
+ } else if (loc == CODECPROCESS) {
+ return mMediaCodecOMX;
+ }
+ ALOGE("Couldn't determine node location for node %d: %d, using local", node, loc);
+ return mLocalOMX;
}
bool MuxOMX::livesLocally(node_id node, pid_t pid) {
@@ -216,29 +258,34 @@
status_t MuxOMX::allocateNode(
const char *name, const sp<IOMXObserver> &observer,
+ sp<IBinder> *nodeBinder,
node_id *node) {
Mutex::Autolock autoLock(mLock);
sp<IOMX> omx;
- if (CanLiveLocally(name)) {
+ node_location loc = getPreferredCodecLocation(name);
+ if (loc == CODECPROCESS) {
+ omx = mMediaCodecOMX;
+ } else if (loc == MEDIAPROCESS) {
+ omx = mMediaServerOMX;
+ } else {
if (mLocalOMX == NULL) {
mLocalOMX = new OMX;
}
omx = mLocalOMX;
- } else {
- omx = mRemoteOMX;
}
- status_t err = omx->allocateNode(name, observer, node);
+ status_t err = omx->allocateNode(name, observer, nodeBinder, node);
+ ALOGV("allocated node_id %x on %s OMX", *node, omx == mMediaCodecOMX ? "codecprocess" :
+ omx == mMediaServerOMX ? "mediaserver" : "local");
+
if (err != OK) {
return err;
}
- if (omx == mLocalOMX) {
- mIsLocalNode.add(*node, true);
- }
+ mNodeLocation.add(*node, loc);
return OK;
}
@@ -252,7 +299,7 @@
return err;
}
- mIsLocalNode.removeItem(node);
+ mNodeLocation.removeItem(node);
return OK;
}
@@ -310,9 +357,9 @@
node, portIndex, enable, audioHwSync, sidebandHandle);
}
-status_t MuxOMX::enableGraphicBuffers(
- node_id node, OMX_U32 port_index, OMX_BOOL enable) {
- return getOMX(node)->enableGraphicBuffers(node, port_index, enable);
+status_t MuxOMX::enableNativeBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL graphic, OMX_BOOL enable) {
+ return getOMX(node)->enableNativeBuffers(node, port_index, graphic, enable);
}
status_t MuxOMX::getGraphicBufferUsage(
@@ -352,7 +399,7 @@
sp<IGraphicBufferProducer> *bufferProducer,
sp<IGraphicBufferConsumer> *bufferConsumer) {
// TODO: local or remote? Always use remote for now
- return mRemoteOMX->createPersistentInputSurface(
+ return mMediaServerOMX->createPersistentInputSurface(
bufferProducer, bufferConsumer);
}
@@ -366,11 +413,11 @@
return getOMX(node)->signalEndOfInputStream(node);
}
-status_t MuxOMX::allocateBuffer(
+status_t MuxOMX::allocateSecureBuffer(
node_id node, OMX_U32 port_index, size_t size,
- buffer_id *buffer, void **buffer_data) {
- return getOMX(node)->allocateBuffer(
- node, port_index, size, buffer, buffer_data);
+ buffer_id *buffer, void **buffer_data, native_handle_t **native_handle) {
+ return getOMX(node)->allocateSecureBuffer(
+ node, port_index, size, buffer, buffer_data, native_handle);
}
status_t MuxOMX::allocateBufferWithBackup(
@@ -415,29 +462,53 @@
}
OMXClient::OMXClient() {
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("media.stagefright.codecremote", value, NULL)
+ && (!strcmp("0", value) || !strcasecmp("false", value))) {
+ sCodecProcessEnabled = false;
+ }
}
status_t OMXClient::connect() {
sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.player"));
- sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+ sp<IBinder> playerbinder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> mediaservice = interface_cast<IMediaPlayerService>(playerbinder);
- if (service.get() == NULL) {
+ if (mediaservice.get() == NULL) {
ALOGE("Cannot obtain IMediaPlayerService");
return NO_INIT;
}
- mOMX = service->getOMX();
- if (mOMX.get() == NULL) {
- ALOGE("Cannot obtain IOMX");
+ sp<IOMX> mediaServerOMX = mediaservice->getOMX();
+ if (mediaServerOMX.get() == NULL) {
+ ALOGE("Cannot obtain mediaserver IOMX");
return NO_INIT;
}
- if (!mOMX->livesLocally(0 /* node */, getpid())) {
- ALOGI("Using client-side OMX mux.");
- mOMX = new MuxOMX(mOMX);
+ // If we don't want to use the codec process, and the media server OMX
+ // is local, use it directly instead of going through MuxOMX
+ if (!sCodecProcessEnabled &&
+ mediaServerOMX->livesLocally(0 /* node */, getpid())) {
+ mOMX = mediaServerOMX;
+ return OK;
}
+ sp<IBinder> codecbinder = sm->getService(String16("media.codec"));
+ sp<IMediaCodecService> codecservice = interface_cast<IMediaCodecService>(codecbinder);
+
+ if (codecservice.get() == NULL) {
+ ALOGE("Cannot obtain IMediaCodecService");
+ return NO_INIT;
+ }
+
+ sp<IOMX> mediaCodecOMX = codecservice->getOMX();
+ if (mediaCodecOMX.get() == NULL) {
+ ALOGE("Cannot obtain mediacodec IOMX");
+ return NO_INIT;
+ }
+
+ mOMX = new MuxOMX(mediaServerOMX, mediaCodecOMX);
+
return OK;
}
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
deleted file mode 100644
index b1dde80..0000000
--- a/media/libstagefright/OMXCodec.cpp
+++ /dev/null
@@ -1,4454 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "OMXCodec"
-
-#ifdef __LP64__
-#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
-#endif
-
-#include <utils/Log.h>
-
-#include "include/AACEncoder.h"
-
-#include "include/ESDS.h"
-
-#include <binder/IServiceManager.h>
-#include <binder/MemoryDealer.h>
-#include <binder/ProcessState.h>
-#include <HardwareAPI.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/IMediaPlayerService.h>
-#include <media/stagefright/ACodec.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaCodecList.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/SurfaceUtils.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/SkipCutBuffer.h>
-#include <utils/Vector.h>
-
-#include <OMX_AudioExt.h>
-#include <OMX_Component.h>
-#include <OMX_IndexExt.h>
-#include <OMX_VideoExt.h>
-#include <OMX_AsString.h>
-
-#include "include/avc_utils.h"
-
-namespace android {
-
-// Treat time out as an error if we have not received any output
-// buffers after 3 seconds.
-const static int64_t kBufferFilledEventTimeOutNs = 3000000000LL;
-
-// OMX Spec defines less than 50 color formats. If the query for
-// color format is executed for more than kMaxColorFormatSupported,
-// the query will fail to avoid looping forever.
-// 1000 is more than enough for us to tell whether the omx
-// component in question is buggy or not.
-const static uint32_t kMaxColorFormatSupported = 1000;
-
-#define FACTORY_CREATE_ENCODER(name) \
-static sp<MediaSource> Make##name(const sp<MediaSource> &source, const sp<MetaData> &meta) { \
- return new name(source, meta); \
-}
-
-#define FACTORY_REF(name) { #name, Make##name },
-
-FACTORY_CREATE_ENCODER(AACEncoder)
-
-static sp<MediaSource> InstantiateSoftwareEncoder(
- const char *name, const sp<MediaSource> &source,
- const sp<MetaData> &meta) {
- struct FactoryInfo {
- const char *name;
- sp<MediaSource> (*CreateFunc)(const sp<MediaSource> &, const sp<MetaData> &);
- };
-
- static const FactoryInfo kFactoryInfo[] = {
- FACTORY_REF(AACEncoder)
- };
- for (size_t i = 0;
- i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) {
- if (!strcmp(name, kFactoryInfo[i].name)) {
- return (*kFactoryInfo[i].CreateFunc)(source, meta);
- }
- }
-
- return NULL;
-}
-
-#undef FACTORY_CREATE_ENCODER
-#undef FACTORY_REF
-
-#define CODEC_LOGI(x, ...) ALOGI("[%s] " x, mComponentName, ##__VA_ARGS__)
-#define CODEC_LOGV(x, ...) ALOGV("[%s] " x, mComponentName, ##__VA_ARGS__)
-#define CODEC_LOGW(x, ...) ALOGW("[%s] " x, mComponentName, ##__VA_ARGS__)
-#define CODEC_LOGE(x, ...) ALOGE("[%s] " x, mComponentName, ##__VA_ARGS__)
-
-struct OMXCodecObserver : public BnOMXObserver {
- OMXCodecObserver() {
- }
-
- void setCodec(const sp<OMXCodec> &target) {
- mTarget = target;
- }
-
- // from IOMXObserver
- virtual void onMessages(const std::list<omx_message> &messages) {
- sp<OMXCodec> codec = mTarget.promote();
-
- if (codec.get() != NULL) {
- Mutex::Autolock autoLock(codec->mLock);
- for (std::list<omx_message>::const_iterator it = messages.cbegin();
- it != messages.cend(); ++it) {
- codec->on_message(*it);
- }
- codec.clear();
- }
- }
-
-protected:
- virtual ~OMXCodecObserver() {}
-
-private:
- wp<OMXCodec> mTarget;
-
- OMXCodecObserver(const OMXCodecObserver &);
- OMXCodecObserver &operator=(const OMXCodecObserver &);
-};
-
-template<class T>
-static void InitOMXParams(T *params) {
- COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(OMX_PTR) == 4); // check OMX_PTR is 4 bytes.
- params->nSize = sizeof(T);
- params->nVersion.s.nVersionMajor = 1;
- params->nVersion.s.nVersionMinor = 0;
- params->nVersion.s.nRevision = 0;
- params->nVersion.s.nStep = 0;
-}
-
-static bool IsSoftwareCodec(const char *componentName) {
- if (!strncmp("OMX.google.", componentName, 11)) {
- return true;
- }
-
- if (!strncmp("OMX.", componentName, 4)) {
- return false;
- }
-
- return true;
-}
-
-// A sort order in which OMX software codecs are first, followed
-// by other (non-OMX) software codecs, followed by everything else.
-static int CompareSoftwareCodecsFirst(
- const OMXCodec::CodecNameAndQuirks *elem1,
- const OMXCodec::CodecNameAndQuirks *elem2) {
- bool isOMX1 = !strncmp(elem1->mName.string(), "OMX.", 4);
- bool isOMX2 = !strncmp(elem2->mName.string(), "OMX.", 4);
-
- bool isSoftwareCodec1 = IsSoftwareCodec(elem1->mName.string());
- bool isSoftwareCodec2 = IsSoftwareCodec(elem2->mName.string());
-
- if (isSoftwareCodec1) {
- if (!isSoftwareCodec2) { return -1; }
-
- if (isOMX1) {
- if (isOMX2) { return 0; }
-
- return -1;
- } else {
- if (isOMX2) { return 0; }
-
- return 1;
- }
-
- return -1;
- }
-
- if (isSoftwareCodec2) {
- return 1;
- }
-
- return 0;
-}
-
-// static
-void OMXCodec::findMatchingCodecs(
- const char *mime,
- bool createEncoder, const char *matchComponentName,
- uint32_t flags,
- Vector<CodecNameAndQuirks> *matchingCodecs) {
- matchingCodecs->clear();
-
- const sp<IMediaCodecList> list = MediaCodecList::getInstance();
- if (list == NULL) {
- return;
- }
-
- size_t index = 0;
- for (;;) {
- ssize_t matchIndex =
- list->findCodecByType(mime, createEncoder, index);
-
- if (matchIndex < 0) {
- break;
- }
-
- index = matchIndex + 1;
-
- const sp<MediaCodecInfo> info = list->getCodecInfo(matchIndex);
- CHECK(info != NULL);
- const char *componentName = info->getCodecName();
-
- // If a specific codec is requested, skip the non-matching ones.
- if (matchComponentName && strcmp(componentName, matchComponentName)) {
- continue;
- }
-
- // When requesting software-only codecs, only push software codecs
- // When requesting hardware-only codecs, only push hardware codecs
- // When there is request neither for software-only nor for
- // hardware-only codecs, push all codecs
- if (((flags & kSoftwareCodecsOnly) && IsSoftwareCodec(componentName)) ||
- ((flags & kHardwareCodecsOnly) && !IsSoftwareCodec(componentName)) ||
- (!(flags & (kSoftwareCodecsOnly | kHardwareCodecsOnly)))) {
-
- ssize_t index = matchingCodecs->add();
- CodecNameAndQuirks *entry = &matchingCodecs->editItemAt(index);
- entry->mName = String8(componentName);
- entry->mQuirks = getComponentQuirks(info);
-
- ALOGV("matching '%s' quirks 0x%08x",
- entry->mName.string(), entry->mQuirks);
- }
- }
-
- if (flags & kPreferSoftwareCodecs) {
- matchingCodecs->sort(CompareSoftwareCodecsFirst);
- }
-}
-
-// static
-uint32_t OMXCodec::getComponentQuirks(
- const sp<MediaCodecInfo> &info) {
- uint32_t quirks = 0;
- if (info->hasQuirk("requires-allocate-on-input-ports")) {
- quirks |= kRequiresAllocateBufferOnInputPorts;
- }
- if (info->hasQuirk("requires-allocate-on-output-ports")) {
- quirks |= kRequiresAllocateBufferOnOutputPorts;
- }
- if (info->hasQuirk("output-buffers-are-unreadable")) {
- quirks |= kOutputBuffersAreUnreadable;
- }
-
- return quirks;
-}
-
-// static
-bool OMXCodec::findCodecQuirks(const char *componentName, uint32_t *quirks) {
- const sp<IMediaCodecList> list = MediaCodecList::getInstance();
- if (list == NULL) {
- return false;
- }
-
- ssize_t index = list->findCodecByName(componentName);
-
- if (index < 0) {
- return false;
- }
-
- const sp<MediaCodecInfo> info = list->getCodecInfo(index);
- CHECK(info != NULL);
- *quirks = getComponentQuirks(info);
-
- return true;
-}
-
-// static
-sp<MediaSource> OMXCodec::Create(
- const sp<IOMX> &omx,
- const sp<MetaData> &meta, bool createEncoder,
- const sp<MediaSource> &source,
- const char *matchComponentName,
- uint32_t flags,
- const sp<ANativeWindow> &nativeWindow) {
- int32_t requiresSecureBuffers;
- if (source->getFormat()->findInt32(
- kKeyRequiresSecureBuffers,
- &requiresSecureBuffers)
- && requiresSecureBuffers) {
- flags |= kIgnoreCodecSpecificData;
- flags |= kUseSecureInputBuffers;
- }
-
- const char *mime;
- bool success = meta->findCString(kKeyMIMEType, &mime);
- CHECK(success);
-
- Vector<CodecNameAndQuirks> matchingCodecs;
- findMatchingCodecs(
- mime, createEncoder, matchComponentName, flags, &matchingCodecs);
-
- if (matchingCodecs.isEmpty()) {
- ALOGV("No matching codecs! (mime: %s, createEncoder: %s, "
- "matchComponentName: %s, flags: 0x%x)",
- mime, createEncoder ? "true" : "false", matchComponentName, flags);
- return NULL;
- }
-
- sp<OMXCodecObserver> observer = new OMXCodecObserver;
- IOMX::node_id node = 0;
-
- for (size_t i = 0; i < matchingCodecs.size(); ++i) {
- const char *componentNameBase = matchingCodecs[i].mName.string();
- uint32_t quirks = matchingCodecs[i].mQuirks;
- const char *componentName = componentNameBase;
-
- AString tmp;
- if (flags & kUseSecureInputBuffers) {
- tmp = componentNameBase;
- tmp.append(".secure");
-
- componentName = tmp.c_str();
- }
-
- if (createEncoder) {
- sp<MediaSource> softwareCodec =
- InstantiateSoftwareEncoder(componentName, source, meta);
-
- if (softwareCodec != NULL) {
- ALOGV("Successfully allocated software codec '%s'", componentName);
-
- return softwareCodec;
- }
- }
-
- ALOGV("Attempting to allocate OMX node '%s'", componentName);
-
- if (!createEncoder
- && (quirks & kOutputBuffersAreUnreadable)
- && (flags & kClientNeedsFramebuffer)) {
- if (strncmp(componentName, "OMX.SEC.", 8)) {
- // For OMX.SEC.* decoders we can enable a special mode that
- // gives the client access to the framebuffer contents.
-
- ALOGW("Component '%s' does not give the client access to "
- "the framebuffer contents. Skipping.",
- componentName);
-
- continue;
- }
- }
-
- status_t err = omx->allocateNode(componentName, observer, &node);
- if (err == OK) {
- ALOGV("Successfully allocated OMX node '%s'", componentName);
-
- sp<OMXCodec> codec = new OMXCodec(
- omx, node, quirks, flags,
- createEncoder, mime, componentName,
- source, nativeWindow);
-
- observer->setCodec(codec);
-
- err = codec->configureCodec(meta);
- if (err == OK) {
- return codec;
- }
-
- ALOGV("Failed to configure codec '%s'", componentName);
- }
- }
-
- return NULL;
-}
-
-status_t OMXCodec::parseHEVCCodecSpecificData(
- const void *data, size_t size,
- unsigned *profile, unsigned *level) {
- const uint8_t *ptr = (const uint8_t *)data;
-
- // verify minimum size and configurationVersion == 1.
- if (size < 7 || ptr[0] != 1) {
- return ERROR_MALFORMED;
- }
-
- *profile = (ptr[1] & 31);
- *level = ptr[12];
-
- ptr += 22;
- size -= 22;
-
- size_t numofArrays = (char)ptr[0];
- ptr += 1;
- size -= 1;
- size_t j = 0, i = 0;
- for (i = 0; i < numofArrays; i++) {
- ptr += 1;
- size -= 1;
-
- // Num of nals
- size_t numofNals = U16_AT(ptr);
- ptr += 2;
- size -= 2;
-
- for (j = 0;j < numofNals;j++) {
- if (size < 2) {
- return ERROR_MALFORMED;
- }
-
- size_t length = U16_AT(ptr);
-
- ptr += 2;
- size -= 2;
-
- if (size < length) {
- return ERROR_MALFORMED;
- }
- addCodecSpecificData(ptr, length);
-
- ptr += length;
- size -= length;
- }
- }
- return OK;
-}
-
-status_t OMXCodec::parseAVCCodecSpecificData(
- const void *data, size_t size,
- unsigned *profile, unsigned *level) {
- const uint8_t *ptr = (const uint8_t *)data;
-
- // verify minimum size and configurationVersion == 1.
- if (size < 7 || ptr[0] != 1) {
- return ERROR_MALFORMED;
- }
-
- *profile = ptr[1];
- *level = ptr[3];
-
- // There is decodable content out there that fails the following
- // assertion, let's be lenient for now...
- // CHECK((ptr[4] >> 2) == 0x3f); // reserved
-
- size_t lengthSize __unused = 1 + (ptr[4] & 3);
-
- // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
- // violates it...
- // CHECK((ptr[5] >> 5) == 7); // reserved
-
- size_t numSeqParameterSets = ptr[5] & 31;
-
- ptr += 6;
- size -= 6;
-
- for (size_t i = 0; i < numSeqParameterSets; ++i) {
- if (size < 2) {
- return ERROR_MALFORMED;
- }
-
- size_t length = U16_AT(ptr);
-
- ptr += 2;
- size -= 2;
-
- if (size < length) {
- return ERROR_MALFORMED;
- }
-
- addCodecSpecificData(ptr, length);
-
- ptr += length;
- size -= length;
- }
-
- if (size < 1) {
- return ERROR_MALFORMED;
- }
-
- size_t numPictureParameterSets = *ptr;
- ++ptr;
- --size;
-
- for (size_t i = 0; i < numPictureParameterSets; ++i) {
- if (size < 2) {
- return ERROR_MALFORMED;
- }
-
- size_t length = U16_AT(ptr);
-
- ptr += 2;
- size -= 2;
-
- if (size < length) {
- return ERROR_MALFORMED;
- }
-
- addCodecSpecificData(ptr, length);
-
- ptr += length;
- size -= length;
- }
-
- return OK;
-}
-
-status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
- ALOGV("configureCodec protected=%d",
- (mFlags & kEnableGrallocUsageProtected) ? 1 : 0);
-
- if (!(mFlags & kIgnoreCodecSpecificData)) {
- uint32_t type;
- const void *data;
- size_t size;
- if (meta->findData(kKeyESDS, &type, &data, &size)) {
- ESDS esds((const char *)data, size);
- CHECK_EQ(esds.InitCheck(), (status_t)OK);
-
- const void *codec_specific_data;
- size_t codec_specific_data_size;
- esds.getCodecSpecificInfo(
- &codec_specific_data, &codec_specific_data_size);
-
- addCodecSpecificData(
- codec_specific_data, codec_specific_data_size);
- } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
- // Parse the AVCDecoderConfigurationRecord
-
- unsigned profile, level;
- status_t err;
- if ((err = parseAVCCodecSpecificData(
- data, size, &profile, &level)) != OK) {
- ALOGE("Malformed AVC codec specific data.");
- return err;
- }
-
- CODEC_LOGI(
- "AVC profile = %u (%s), level = %u",
- profile, AVCProfileToString(profile), level);
- } else if (meta->findData(kKeyHVCC, &type, &data, &size)) {
- // Parse the HEVCDecoderConfigurationRecord
-
- unsigned profile, level;
- status_t err;
- if ((err = parseHEVCCodecSpecificData(
- data, size, &profile, &level)) != OK) {
- ALOGE("Malformed HEVC codec specific data.");
- return err;
- }
-
- CODEC_LOGI(
- "HEVC profile = %u , level = %u",
- profile, level);
- } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
- addCodecSpecificData(data, size);
-
- CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
- addCodecSpecificData(data, size);
- } else if (meta->findData(kKeyOpusHeader, &type, &data, &size)) {
- addCodecSpecificData(data, size);
-
- CHECK(meta->findData(kKeyOpusCodecDelay, &type, &data, &size));
- addCodecSpecificData(data, size);
- CHECK(meta->findData(kKeyOpusSeekPreRoll, &type, &data, &size));
- addCodecSpecificData(data, size);
- }
- }
-
- int32_t bitRate = 0;
- if (mIsEncoder) {
- CHECK(meta->findInt32(kKeyBitRate, &bitRate));
- }
- if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mMIME)) {
- setAMRFormat(false /* isWAMR */, bitRate);
- } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mMIME)) {
- setAMRFormat(true /* isWAMR */, bitRate);
- } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mMIME)) {
- int32_t numChannels, sampleRate, aacProfile;
- CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
- CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
-
- if (!meta->findInt32(kKeyAACProfile, &aacProfile)) {
- aacProfile = OMX_AUDIO_AACObjectNull;
- }
-
- int32_t isADTS;
- if (!meta->findInt32(kKeyIsADTS, &isADTS)) {
- isADTS = false;
- }
-
- status_t err = setAACFormat(numChannels, sampleRate, bitRate, aacProfile, isADTS);
- if (err != OK) {
- CODEC_LOGE("setAACFormat() failed (err = %d)", err);
- return err;
- }
- } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_MPEG, mMIME)) {
- int32_t numChannels, sampleRate;
- if (meta->findInt32(kKeyChannelCount, &numChannels)
- && meta->findInt32(kKeySampleRate, &sampleRate)) {
- // Since we did not always check for these, leave them optional
- // and have the decoder figure it all out.
- setRawAudioFormat(
- mIsEncoder ? kPortIndexInput : kPortIndexOutput,
- sampleRate,
- numChannels);
- }
- } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mMIME)) {
- int32_t numChannels;
- int32_t sampleRate;
- CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
- CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
-
- status_t err = setAC3Format(numChannels, sampleRate);
- if (err != OK) {
- CODEC_LOGE("setAC3Format() failed (err = %d)", err);
- return err;
- }
- } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_ALAW, mMIME)
- || !strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_MLAW, mMIME)) {
- // These are PCM-like formats with a fixed sample rate but
- // a variable number of channels.
-
- int32_t sampleRate;
- int32_t numChannels;
- CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
- if (!meta->findInt32(kKeySampleRate, &sampleRate)) {
- sampleRate = 8000;
- }
-
- setG711Format(sampleRate, numChannels);
- } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mMIME)) {
- CHECK(!mIsEncoder);
-
- int32_t numChannels, sampleRate;
- CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
- CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
-
- setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
- }
-
- if (!strncasecmp(mMIME, "video/", 6)) {
-
- if (mIsEncoder) {
- setVideoInputFormat(mMIME, meta);
- } else {
- status_t err = setVideoOutputFormat(
- mMIME, meta);
-
- if (err != OK) {
- return err;
- }
- }
- }
-
- int32_t maxInputSize;
- if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
- setMinBufferSize(kPortIndexInput, (OMX_U32)maxInputSize);
- }
-
- initOutputFormat(meta);
-
- if ((mFlags & kClientNeedsFramebuffer)
- && !strncmp(mComponentName, "OMX.SEC.", 8)) {
- // This appears to no longer be needed???
-
- OMX_INDEXTYPE index;
-
- status_t err =
- mOMX->getExtensionIndex(
- mNode,
- "OMX.SEC.index.ThumbnailMode",
- &index);
-
- if (err != OK) {
- return err;
- }
-
- OMX_BOOL enable = OMX_TRUE;
- err = mOMX->setConfig(mNode, index, &enable, sizeof(enable));
-
- if (err != OK) {
- CODEC_LOGE("setConfig('OMX.SEC.index.ThumbnailMode') "
- "returned error 0x%08x", err);
-
- return err;
- }
-
- mQuirks &= ~kOutputBuffersAreUnreadable;
- }
-
- if (mNativeWindow != NULL
- && !mIsEncoder
- && !strncasecmp(mMIME, "video/", 6)
- && !strncmp(mComponentName, "OMX.", 4)) {
- status_t err = initNativeWindow();
- if (err != OK) {
- return err;
- }
- }
-
- return OK;
-}
-
-void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) {
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
- def.nPortIndex = portIndex;
-
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
-
- if ((portIndex == kPortIndexInput && (mQuirks & kInputBufferSizesAreBogus))
- || (def.nBufferSize < size)) {
- def.nBufferSize = size;
- }
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
-
- err = mOMX->getParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
-
- // Make sure the setting actually stuck.
- if (portIndex == kPortIndexInput
- && (mQuirks & kInputBufferSizesAreBogus)) {
- CHECK_EQ(def.nBufferSize, size);
- } else {
- CHECK(def.nBufferSize >= size);
- }
-}
-
-status_t OMXCodec::setVideoPortFormatType(
- OMX_U32 portIndex,
- OMX_VIDEO_CODINGTYPE compressionFormat,
- OMX_COLOR_FORMATTYPE colorFormat) {
- OMX_VIDEO_PARAM_PORTFORMATTYPE format;
- InitOMXParams(&format);
- format.nPortIndex = portIndex;
- format.nIndex = 0;
- bool found = false;
-
- OMX_U32 index = 0;
- for (;;) {
- format.nIndex = index;
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamVideoPortFormat,
- &format, sizeof(format));
-
- if (err != OK) {
- return err;
- }
-
- // The following assertion is violated by TI's video decoder.
- // CHECK_EQ(format.nIndex, index);
-
-#if 1
- CODEC_LOGV("portIndex: %u, index: %u, eCompressionFormat=%d eColorFormat=%d",
- portIndex,
- index, format.eCompressionFormat, format.eColorFormat);
-#endif
-
- if (format.eCompressionFormat == compressionFormat
- && format.eColorFormat == colorFormat) {
- found = true;
- break;
- }
-
- ++index;
- if (index >= kMaxColorFormatSupported) {
- CODEC_LOGE("color format %d or compression format %d is not supported",
- colorFormat, compressionFormat);
- return UNKNOWN_ERROR;
- }
- }
-
- if (!found) {
- return UNKNOWN_ERROR;
- }
-
- CODEC_LOGV("found a match.");
- status_t err = mOMX->setParameter(
- mNode, OMX_IndexParamVideoPortFormat,
- &format, sizeof(format));
-
- return err;
-}
-
-static size_t getFrameSize(
- OMX_COLOR_FORMATTYPE colorFormat, int32_t width, int32_t height) {
- switch (colorFormat) {
- case OMX_COLOR_FormatYCbYCr:
- case OMX_COLOR_FormatCbYCrY:
- return width * height * 2;
-
- case OMX_COLOR_FormatYUV420Planar:
- case OMX_COLOR_FormatYUV420SemiPlanar:
- case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
- /*
- * FIXME: For the Opaque color format, the frame size does not
- * need to be (w*h*3)/2. It just needs to
- * be larger than certain minimum buffer size. However,
- * currently, this opaque foramt has been tested only on
- * YUV420 formats. If that is changed, then we need to revisit
- * this part in the future
- */
- case OMX_COLOR_FormatAndroidOpaque:
- return (width * height * 3) / 2;
-
- default:
- CHECK(!"Should not be here. Unsupported color format.");
- break;
- }
- return 0;
-}
-
-status_t OMXCodec::findTargetColorFormat(
- const sp<MetaData>& meta, OMX_COLOR_FORMATTYPE *colorFormat) {
- ALOGV("findTargetColorFormat");
- CHECK(mIsEncoder);
-
- *colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
- int32_t targetColorFormat;
- if (meta->findInt32(kKeyColorFormat, &targetColorFormat)) {
- *colorFormat = (OMX_COLOR_FORMATTYPE) targetColorFormat;
- }
-
- // Check whether the target color format is supported.
- return isColorFormatSupported(*colorFormat, kPortIndexInput);
-}
-
-status_t OMXCodec::isColorFormatSupported(
- OMX_COLOR_FORMATTYPE colorFormat, int portIndex) {
- ALOGV("isColorFormatSupported: %d", static_cast<int>(colorFormat));
-
- // Enumerate all the color formats supported by
- // the omx component to see whether the given
- // color format is supported.
- OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
- InitOMXParams(&portFormat);
- portFormat.nPortIndex = portIndex;
- OMX_U32 index = 0;
- portFormat.nIndex = index;
- while (true) {
- if (OMX_ErrorNone != mOMX->getParameter(
- mNode, OMX_IndexParamVideoPortFormat,
- &portFormat, sizeof(portFormat))) {
- break;
- }
- // Make sure that omx component does not overwrite
- // the incremented index (bug 2897413).
- CHECK_EQ(index, portFormat.nIndex);
- if (portFormat.eColorFormat == colorFormat) {
- CODEC_LOGV("Found supported color format: %d", portFormat.eColorFormat);
- return OK; // colorFormat is supported!
- }
- ++index;
- portFormat.nIndex = index;
-
- if (index >= kMaxColorFormatSupported) {
- CODEC_LOGE("More than %u color formats are supported???", index);
- break;
- }
- }
-
- CODEC_LOGE("color format %d is not supported", colorFormat);
- return UNKNOWN_ERROR;
-}
-
-void OMXCodec::setVideoInputFormat(
- const char *mime, const sp<MetaData>& meta) {
-
- int32_t width, height, frameRate, bitRate, stride, sliceHeight;
- bool success = meta->findInt32(kKeyWidth, &width);
- success = success && meta->findInt32(kKeyHeight, &height);
- success = success && meta->findInt32(kKeyFrameRate, &frameRate);
- success = success && meta->findInt32(kKeyBitRate, &bitRate);
- success = success && meta->findInt32(kKeyStride, &stride);
- success = success && meta->findInt32(kKeySliceHeight, &sliceHeight);
- CHECK(success);
- CHECK(stride != 0);
-
- OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
- if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
- compressionFormat = OMX_VIDEO_CodingAVC;
- } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
- compressionFormat = OMX_VIDEO_CodingHEVC;
- } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
- compressionFormat = OMX_VIDEO_CodingMPEG4;
- } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
- compressionFormat = OMX_VIDEO_CodingH263;
- } else {
- ALOGE("Not a supported video mime type: %s", mime);
- CHECK(!"Should not be here. Not a supported video mime type.");
- }
-
- OMX_COLOR_FORMATTYPE colorFormat;
- CHECK_EQ((status_t)OK, findTargetColorFormat(meta, &colorFormat));
-
- status_t err;
- OMX_PARAM_PORTDEFINITIONTYPE def;
- OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
-
- //////////////////////// Input port /////////////////////////
- CHECK_EQ(setVideoPortFormatType(
- kPortIndexInput, OMX_VIDEO_CodingUnused,
- colorFormat), (status_t)OK);
-
- InitOMXParams(&def);
- def.nPortIndex = kPortIndexInput;
-
- err = mOMX->getParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
-
- def.nBufferSize = getFrameSize(colorFormat,
- stride > 0? stride: -stride, sliceHeight);
-
- CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainVideo);
-
- video_def->nFrameWidth = width;
- video_def->nFrameHeight = height;
- video_def->nStride = stride;
- video_def->nSliceHeight = sliceHeight;
- video_def->xFramerate = (frameRate << 16); // Q16 format
- video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
- video_def->eColorFormat = colorFormat;
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
-
- //////////////////////// Output port /////////////////////////
- CHECK_EQ(setVideoPortFormatType(
- kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused),
- (status_t)OK);
- InitOMXParams(&def);
- def.nPortIndex = kPortIndexOutput;
-
- err = mOMX->getParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
-
- CHECK_EQ(err, (status_t)OK);
- CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainVideo);
-
- video_def->nFrameWidth = width;
- video_def->nFrameHeight = height;
- video_def->xFramerate = 0; // No need for output port
- video_def->nBitrate = bitRate; // Q16 format
- video_def->eCompressionFormat = compressionFormat;
- video_def->eColorFormat = OMX_COLOR_FormatUnused;
- if (mQuirks & kRequiresLargerEncoderOutputBuffer) {
- // Increases the output buffer size
- def.nBufferSize = ((def.nBufferSize * 3) >> 1);
- }
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
-
- /////////////////// Codec-specific ////////////////////////
- switch (compressionFormat) {
- case OMX_VIDEO_CodingMPEG4:
- {
- CHECK_EQ(setupMPEG4EncoderParameters(meta), (status_t)OK);
- break;
- }
-
- case OMX_VIDEO_CodingH263:
- CHECK_EQ(setupH263EncoderParameters(meta), (status_t)OK);
- break;
-
- case OMX_VIDEO_CodingAVC:
- {
- CHECK_EQ(setupAVCEncoderParameters(meta), (status_t)OK);
- break;
- }
-
- default:
- CHECK(!"Support for this compressionFormat to be implemented.");
- break;
- }
-}
-
-static OMX_U32 setPFramesSpacing(int32_t iFramesInterval, int32_t frameRate) {
- if (iFramesInterval < 0) {
- return 0xFFFFFFFF;
- } else if (iFramesInterval == 0) {
- return 0;
- }
- OMX_U32 ret = frameRate * iFramesInterval - 1;
- return ret;
-}
-
-status_t OMXCodec::setupErrorCorrectionParameters() {
- OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE errorCorrectionType;
- InitOMXParams(&errorCorrectionType);
- errorCorrectionType.nPortIndex = kPortIndexOutput;
-
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamVideoErrorCorrection,
- &errorCorrectionType, sizeof(errorCorrectionType));
- if (err != OK) {
- ALOGW("Error correction param query is not supported");
- return OK; // Optional feature. Ignore this failure
- }
-
- errorCorrectionType.bEnableHEC = OMX_FALSE;
- errorCorrectionType.bEnableResync = OMX_TRUE;
- errorCorrectionType.nResynchMarkerSpacing = 256;
- errorCorrectionType.bEnableDataPartitioning = OMX_FALSE;
- errorCorrectionType.bEnableRVLC = OMX_FALSE;
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamVideoErrorCorrection,
- &errorCorrectionType, sizeof(errorCorrectionType));
- if (err != OK) {
- ALOGW("Error correction param configuration is not supported");
- }
-
- // Optional feature. Ignore the failure.
- return OK;
-}
-
-status_t OMXCodec::setupBitRate(int32_t bitRate) {
- OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
- InitOMXParams(&bitrateType);
- bitrateType.nPortIndex = kPortIndexOutput;
-
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamVideoBitrate,
- &bitrateType, sizeof(bitrateType));
- CHECK_EQ(err, (status_t)OK);
-
- bitrateType.eControlRate = OMX_Video_ControlRateVariable;
- bitrateType.nTargetBitrate = bitRate;
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamVideoBitrate,
- &bitrateType, sizeof(bitrateType));
- CHECK_EQ(err, (status_t)OK);
- return OK;
-}
-
-status_t OMXCodec::getVideoProfileLevel(
- const sp<MetaData>& meta,
- const CodecProfileLevel& defaultProfileLevel,
- CodecProfileLevel &profileLevel) {
- CODEC_LOGV("Default profile: %u, level #x%x",
- defaultProfileLevel.mProfile, defaultProfileLevel.mLevel);
-
- // Are the default profile and level overwriten?
- int32_t profile, level;
- if (!meta->findInt32(kKeyVideoProfile, &profile)) {
- profile = defaultProfileLevel.mProfile;
- }
- if (!meta->findInt32(kKeyVideoLevel, &level)) {
- level = defaultProfileLevel.mLevel;
- }
- CODEC_LOGV("Target profile: %d, level: %d", profile, level);
-
- // Are the target profile and level supported by the encoder?
- OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
- InitOMXParams(¶m);
- param.nPortIndex = kPortIndexOutput;
- for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamVideoProfileLevelQuerySupported,
- ¶m, sizeof(param));
-
- if (err != OK) break;
-
- int32_t supportedProfile = static_cast<int32_t>(param.eProfile);
- int32_t supportedLevel = static_cast<int32_t>(param.eLevel);
- CODEC_LOGV("Supported profile: %d, level %d",
- supportedProfile, supportedLevel);
-
- if (profile == supportedProfile &&
- level <= supportedLevel) {
- // We can further check whether the level is a valid
- // value; but we will leave that to the omx encoder component
- // via OMX_SetParameter call.
- profileLevel.mProfile = profile;
- profileLevel.mLevel = level;
- return OK;
- }
- }
-
- CODEC_LOGE("Target profile (%d) and level (%d) is not supported",
- profile, level);
- return BAD_VALUE;
-}
-
-status_t OMXCodec::setupH263EncoderParameters(const sp<MetaData>& meta) {
- int32_t iFramesInterval, frameRate, bitRate;
- bool success = meta->findInt32(kKeyBitRate, &bitRate);
- success = success && meta->findInt32(kKeyFrameRate, &frameRate);
- success = success && meta->findInt32(kKeyIFramesInterval, &iFramesInterval);
- CHECK(success);
- OMX_VIDEO_PARAM_H263TYPE h263type;
- InitOMXParams(&h263type);
- h263type.nPortIndex = kPortIndexOutput;
-
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamVideoH263, &h263type, sizeof(h263type));
- CHECK_EQ(err, (status_t)OK);
-
- h263type.nAllowedPictureTypes =
- OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
-
- h263type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate);
- if (h263type.nPFrames == 0) {
- h263type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
- }
- h263type.nBFrames = 0;
-
- // Check profile and level parameters
- CodecProfileLevel defaultProfileLevel, profileLevel;
- defaultProfileLevel.mProfile = h263type.eProfile;
- defaultProfileLevel.mLevel = h263type.eLevel;
- err = getVideoProfileLevel(meta, defaultProfileLevel, profileLevel);
- if (err != OK) return err;
- h263type.eProfile = static_cast<OMX_VIDEO_H263PROFILETYPE>(profileLevel.mProfile);
- h263type.eLevel = static_cast<OMX_VIDEO_H263LEVELTYPE>(profileLevel.mLevel);
-
- h263type.bPLUSPTYPEAllowed = OMX_FALSE;
- h263type.bForceRoundingTypeToZero = OMX_FALSE;
- h263type.nPictureHeaderRepetition = 0;
- h263type.nGOBHeaderInterval = 0;
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamVideoH263, &h263type, sizeof(h263type));
- CHECK_EQ(err, (status_t)OK);
-
- CHECK_EQ(setupBitRate(bitRate), (status_t)OK);
- CHECK_EQ(setupErrorCorrectionParameters(), (status_t)OK);
-
- return OK;
-}
-
-status_t OMXCodec::setupMPEG4EncoderParameters(const sp<MetaData>& meta) {
- int32_t iFramesInterval, frameRate, bitRate;
- bool success = meta->findInt32(kKeyBitRate, &bitRate);
- success = success && meta->findInt32(kKeyFrameRate, &frameRate);
- success = success && meta->findInt32(kKeyIFramesInterval, &iFramesInterval);
- CHECK(success);
- OMX_VIDEO_PARAM_MPEG4TYPE mpeg4type;
- InitOMXParams(&mpeg4type);
- mpeg4type.nPortIndex = kPortIndexOutput;
-
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
- CHECK_EQ(err, (status_t)OK);
-
- mpeg4type.nSliceHeaderSpacing = 0;
- mpeg4type.bSVH = OMX_FALSE;
- mpeg4type.bGov = OMX_FALSE;
-
- mpeg4type.nAllowedPictureTypes =
- OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
-
- mpeg4type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate);
- if (mpeg4type.nPFrames == 0) {
- mpeg4type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
- }
- mpeg4type.nBFrames = 0;
- mpeg4type.nIDCVLCThreshold = 0;
- mpeg4type.bACPred = OMX_TRUE;
- mpeg4type.nMaxPacketSize = 256;
- mpeg4type.nTimeIncRes = 1000;
- mpeg4type.nHeaderExtension = 0;
- mpeg4type.bReversibleVLC = OMX_FALSE;
-
- // Check profile and level parameters
- CodecProfileLevel defaultProfileLevel, profileLevel;
- defaultProfileLevel.mProfile = mpeg4type.eProfile;
- defaultProfileLevel.mLevel = mpeg4type.eLevel;
- err = getVideoProfileLevel(meta, defaultProfileLevel, profileLevel);
- if (err != OK) return err;
- mpeg4type.eProfile = static_cast<OMX_VIDEO_MPEG4PROFILETYPE>(profileLevel.mProfile);
- mpeg4type.eLevel = static_cast<OMX_VIDEO_MPEG4LEVELTYPE>(profileLevel.mLevel);
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
- CHECK_EQ(err, (status_t)OK);
-
- CHECK_EQ(setupBitRate(bitRate), (status_t)OK);
- CHECK_EQ(setupErrorCorrectionParameters(), (status_t)OK);
-
- return OK;
-}
-
-status_t OMXCodec::setupAVCEncoderParameters(const sp<MetaData>& meta) {
- int32_t iFramesInterval, frameRate, bitRate;
- bool success = meta->findInt32(kKeyBitRate, &bitRate);
- success = success && meta->findInt32(kKeyFrameRate, &frameRate);
- success = success && meta->findInt32(kKeyIFramesInterval, &iFramesInterval);
- CHECK(success);
-
- OMX_VIDEO_PARAM_AVCTYPE h264type;
- InitOMXParams(&h264type);
- h264type.nPortIndex = kPortIndexOutput;
-
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
- CHECK_EQ(err, (status_t)OK);
-
- h264type.nAllowedPictureTypes =
- OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
-
- // Check profile and level parameters
- CodecProfileLevel defaultProfileLevel, profileLevel;
- defaultProfileLevel.mProfile = h264type.eProfile;
- defaultProfileLevel.mLevel = h264type.eLevel;
- err = getVideoProfileLevel(meta, defaultProfileLevel, profileLevel);
- if (err != OK) return err;
- h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profileLevel.mProfile);
- h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(profileLevel.mLevel);
-
- // XXX
- if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) {
- ALOGW("Use baseline profile instead of %d for AVC recording",
- h264type.eProfile);
- h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
- }
-
- if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) {
- h264type.nSliceHeaderSpacing = 0;
- h264type.bUseHadamard = OMX_TRUE;
- h264type.nRefFrames = 1;
- h264type.nBFrames = 0;
- h264type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate);
- if (h264type.nPFrames == 0) {
- h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
- }
- h264type.nRefIdx10ActiveMinus1 = 0;
- h264type.nRefIdx11ActiveMinus1 = 0;
- h264type.bEntropyCodingCABAC = OMX_FALSE;
- h264type.bWeightedPPrediction = OMX_FALSE;
- h264type.bconstIpred = OMX_FALSE;
- h264type.bDirect8x8Inference = OMX_FALSE;
- h264type.bDirectSpatialTemporal = OMX_FALSE;
- h264type.nCabacInitIdc = 0;
- }
-
- if (h264type.nBFrames != 0) {
- h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB;
- }
-
- h264type.bEnableUEP = OMX_FALSE;
- h264type.bEnableFMO = OMX_FALSE;
- h264type.bEnableASO = OMX_FALSE;
- h264type.bEnableRS = OMX_FALSE;
- h264type.bFrameMBsOnly = OMX_TRUE;
- h264type.bMBAFF = OMX_FALSE;
- h264type.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable;
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
- CHECK_EQ(err, (status_t)OK);
-
- CHECK_EQ(setupBitRate(bitRate), (status_t)OK);
-
- return OK;
-}
-
-status_t OMXCodec::setVideoOutputFormat(
- const char *mime, const sp<MetaData>& meta) {
-
- int32_t width, height;
- bool success = meta->findInt32(kKeyWidth, &width);
- success = success && meta->findInt32(kKeyHeight, &height);
- CHECK(success);
-
- CODEC_LOGV("setVideoOutputFormat width=%d, height=%d", width, height);
-
- OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
- if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
- compressionFormat = OMX_VIDEO_CodingAVC;
- } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
- compressionFormat = OMX_VIDEO_CodingMPEG4;
- } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
- compressionFormat = OMX_VIDEO_CodingHEVC;
- } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
- compressionFormat = OMX_VIDEO_CodingH263;
- } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_VP8, mime)) {
- compressionFormat = OMX_VIDEO_CodingVP8;
- } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_VP9, mime)) {
- compressionFormat = OMX_VIDEO_CodingVP9;
- } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG2, mime)) {
- compressionFormat = OMX_VIDEO_CodingMPEG2;
- } else {
- ALOGE("Not a supported video mime type: %s", mime);
- CHECK(!"Should not be here. Not a supported video mime type.");
- }
-
- status_t err = setVideoPortFormatType(
- kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
-
- if (err != OK) {
- return err;
- }
-
-#if 1
- {
- OMX_VIDEO_PARAM_PORTFORMATTYPE format;
- InitOMXParams(&format);
- format.nPortIndex = kPortIndexOutput;
- format.nIndex = 0;
-
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamVideoPortFormat,
- &format, sizeof(format));
- CHECK_EQ(err, (status_t)OK);
- CHECK_EQ((int)format.eCompressionFormat, (int)OMX_VIDEO_CodingUnused);
-
- int32_t colorFormat;
- if (meta->findInt32(kKeyColorFormat, &colorFormat)
- && colorFormat != OMX_COLOR_FormatUnused
- && colorFormat != format.eColorFormat) {
-
- while (OMX_ErrorNoMore != err) {
- format.nIndex++;
- err = mOMX->getParameter(
- mNode, OMX_IndexParamVideoPortFormat,
- &format, sizeof(format));
- if (format.eColorFormat == colorFormat) {
- break;
- }
- }
- if (format.eColorFormat != colorFormat) {
- CODEC_LOGE("Color format %d is not supported", colorFormat);
- return ERROR_UNSUPPORTED;
- }
- }
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamVideoPortFormat,
- &format, sizeof(format));
-
- if (err != OK) {
- return err;
- }
- }
-#endif
-
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
- def.nPortIndex = kPortIndexInput;
-
- OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
-
- err = mOMX->getParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
-
- CHECK_EQ(err, (status_t)OK);
-
-#if 1
- // XXX Need a (much) better heuristic to compute input buffer sizes.
- const size_t X = 64 * 1024;
- if (def.nBufferSize < X) {
- def.nBufferSize = X;
- }
-#endif
-
- CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainVideo);
-
- video_def->nFrameWidth = width;
- video_def->nFrameHeight = height;
-
- video_def->eCompressionFormat = compressionFormat;
- video_def->eColorFormat = OMX_COLOR_FormatUnused;
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
-
- if (err != OK) {
- return err;
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- InitOMXParams(&def);
- def.nPortIndex = kPortIndexOutput;
-
- err = mOMX->getParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
- CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainVideo);
-
-#if 0
- def.nBufferSize =
- (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
-#endif
-
- video_def->nFrameWidth = width;
- video_def->nFrameHeight = height;
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
-
- return err;
-}
-
-OMXCodec::OMXCodec(
- const sp<IOMX> &omx, IOMX::node_id node,
- uint32_t quirks, uint32_t flags,
- bool isEncoder,
- const char *mime,
- const char *componentName,
- const sp<MediaSource> &source,
- const sp<ANativeWindow> &nativeWindow)
- : mOMX(omx),
- mOMXLivesLocally(omx->livesLocally(node, getpid())),
- mNode(node),
- mQuirks(quirks),
- mFlags(flags),
- mIsEncoder(isEncoder),
- mIsVideo(!strncasecmp("video/", mime, 6)),
- mMIME(strdup(mime)),
- mComponentName(strdup(componentName)),
- mSource(source),
- mCodecSpecificDataIndex(0),
- mState(LOADED),
- mInitialBufferSubmit(true),
- mSignalledEOS(false),
- mNoMoreOutputData(false),
- mOutputPortSettingsHaveChanged(false),
- mSeekTimeUs(-1),
- mSeekMode(ReadOptions::SEEK_CLOSEST_SYNC),
- mTargetTimeUs(-1),
- mOutputPortSettingsChangedPending(false),
- mSkipCutBuffer(NULL),
- mLeftOverBuffer(NULL),
- mPaused(false),
- mNativeWindow(
- (!strncmp(componentName, "OMX.google.", 11))
- ? NULL : nativeWindow) {
- mPortStatus[kPortIndexInput] = ENABLED;
- mPortStatus[kPortIndexOutput] = ENABLED;
-
- setComponentRole();
-}
-
-// static
-void OMXCodec::setComponentRole(
- const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
- const char *mime) {
- struct MimeToRole {
- const char *mime;
- const char *decoderRole;
- const char *encoderRole;
- };
-
- static const MimeToRole kMimeToRole[] = {
- { MEDIA_MIMETYPE_AUDIO_MPEG,
- "audio_decoder.mp3", "audio_encoder.mp3" },
- { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
- "audio_decoder.mp1", "audio_encoder.mp1" },
- { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
- "audio_decoder.mp2", "audio_encoder.mp2" },
- { MEDIA_MIMETYPE_AUDIO_AMR_NB,
- "audio_decoder.amrnb", "audio_encoder.amrnb" },
- { MEDIA_MIMETYPE_AUDIO_AMR_WB,
- "audio_decoder.amrwb", "audio_encoder.amrwb" },
- { MEDIA_MIMETYPE_AUDIO_AAC,
- "audio_decoder.aac", "audio_encoder.aac" },
- { MEDIA_MIMETYPE_AUDIO_VORBIS,
- "audio_decoder.vorbis", "audio_encoder.vorbis" },
- { MEDIA_MIMETYPE_AUDIO_OPUS,
- "audio_decoder.opus", "audio_encoder.opus" },
- { MEDIA_MIMETYPE_AUDIO_G711_MLAW,
- "audio_decoder.g711mlaw", "audio_encoder.g711mlaw" },
- { MEDIA_MIMETYPE_AUDIO_G711_ALAW,
- "audio_decoder.g711alaw", "audio_encoder.g711alaw" },
- { MEDIA_MIMETYPE_VIDEO_AVC,
- "video_decoder.avc", "video_encoder.avc" },
- { MEDIA_MIMETYPE_VIDEO_HEVC,
- "video_decoder.hevc", "video_encoder.hevc" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4,
- "video_decoder.mpeg4", "video_encoder.mpeg4" },
- { MEDIA_MIMETYPE_VIDEO_H263,
- "video_decoder.h263", "video_encoder.h263" },
- { MEDIA_MIMETYPE_VIDEO_VP8,
- "video_decoder.vp8", "video_encoder.vp8" },
- { MEDIA_MIMETYPE_VIDEO_VP9,
- "video_decoder.vp9", "video_encoder.vp9" },
- { MEDIA_MIMETYPE_AUDIO_RAW,
- "audio_decoder.raw", "audio_encoder.raw" },
- { MEDIA_MIMETYPE_AUDIO_FLAC,
- "audio_decoder.flac", "audio_encoder.flac" },
- { MEDIA_MIMETYPE_AUDIO_MSGSM,
- "audio_decoder.gsm", "audio_encoder.gsm" },
- { MEDIA_MIMETYPE_VIDEO_MPEG2,
- "video_decoder.mpeg2", "video_encoder.mpeg2" },
- { MEDIA_MIMETYPE_AUDIO_AC3,
- "audio_decoder.ac3", "audio_encoder.ac3" },
- };
-
- static const size_t kNumMimeToRole =
- sizeof(kMimeToRole) / sizeof(kMimeToRole[0]);
-
- size_t i;
- for (i = 0; i < kNumMimeToRole; ++i) {
- if (!strcasecmp(mime, kMimeToRole[i].mime)) {
- break;
- }
- }
-
- if (i == kNumMimeToRole) {
- return;
- }
-
- const char *role =
- isEncoder ? kMimeToRole[i].encoderRole
- : kMimeToRole[i].decoderRole;
-
- if (role != NULL) {
- OMX_PARAM_COMPONENTROLETYPE roleParams;
- InitOMXParams(&roleParams);
-
- strncpy((char *)roleParams.cRole,
- role, OMX_MAX_STRINGNAME_SIZE - 1);
-
- roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
-
- status_t err = omx->setParameter(
- node, OMX_IndexParamStandardComponentRole,
- &roleParams, sizeof(roleParams));
-
- if (err != OK) {
- ALOGW("Failed to set standard component role '%s'.", role);
- }
- }
-}
-
-void OMXCodec::setComponentRole() {
- setComponentRole(mOMX, mNode, mIsEncoder, mMIME);
-}
-
-OMXCodec::~OMXCodec() {
- mSource.clear();
-
- CHECK(mState == LOADED || mState == ERROR || mState == LOADED_TO_IDLE);
-
- status_t err = mOMX->freeNode(mNode);
- CHECK_EQ(err, (status_t)OK);
-
- mNode = 0;
- setState(DEAD);
-
- clearCodecSpecificData();
-
- free(mComponentName);
- mComponentName = NULL;
-
- free(mMIME);
- mMIME = NULL;
-}
-
-status_t OMXCodec::init() {
- // mLock is held.
-
- CHECK_EQ((int)mState, (int)LOADED);
-
- status_t err;
- if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
- err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
- CHECK_EQ(err, (status_t)OK);
- setState(LOADED_TO_IDLE);
- }
-
- err = allocateBuffers();
- if (err != (status_t)OK) {
- return err;
- }
-
- if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
- err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
- CHECK_EQ(err, (status_t)OK);
-
- setState(LOADED_TO_IDLE);
- }
-
- while (mState != EXECUTING && mState != ERROR) {
- mAsyncCompletion.wait(mLock);
- }
-
- return mState == ERROR ? UNKNOWN_ERROR : OK;
-}
-
-// static
-bool OMXCodec::isIntermediateState(State state) {
- return state == LOADED_TO_IDLE
- || state == IDLE_TO_EXECUTING
- || state == EXECUTING_TO_IDLE
- || state == IDLE_TO_LOADED
- || state == RECONFIGURING;
-}
-
-status_t OMXCodec::allocateBuffers() {
- status_t err = allocateBuffersOnPort(kPortIndexInput);
-
- if (err != OK) {
- return err;
- }
-
- return allocateBuffersOnPort(kPortIndexOutput);
-}
-
-status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
- if (mNativeWindow != NULL && portIndex == kPortIndexOutput) {
- return allocateOutputBuffersFromNativeWindow();
- }
-
- if ((mFlags & kEnableGrallocUsageProtected) && portIndex == kPortIndexOutput) {
- ALOGE("protected output buffers must be stent to an ANativeWindow");
- return PERMISSION_DENIED;
- }
-
- status_t err = OK;
- if ((mFlags & kStoreMetaDataInVideoBuffers)
- && portIndex == kPortIndexInput) {
- err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE);
- if (err != OK) {
- ALOGE("Storing meta data in video buffers is not supported");
- return err;
- }
- }
-
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
- def.nPortIndex = portIndex;
-
- err = mOMX->getParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
-
- if (err != OK) {
- return err;
- }
-
- CODEC_LOGV("allocating %u buffers of size %u on %s port",
- def.nBufferCountActual, def.nBufferSize,
- portIndex == kPortIndexInput ? "input" : "output");
-
- if (def.nBufferSize != 0 && def.nBufferCountActual > SIZE_MAX / def.nBufferSize) {
- return BAD_VALUE;
- }
- size_t totalSize = def.nBufferCountActual * def.nBufferSize;
- mDealer[portIndex] = new MemoryDealer(totalSize, "OMXCodec");
-
- for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
- sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
- CHECK(mem.get() != NULL);
-
- BufferInfo info;
- info.mData = NULL;
- info.mSize = def.nBufferSize;
-
- IOMX::buffer_id buffer;
- if (portIndex == kPortIndexInput
- && ((mQuirks & kRequiresAllocateBufferOnInputPorts)
- || (mFlags & kUseSecureInputBuffers))) {
- if (mOMXLivesLocally) {
- mem.clear();
-
- err = mOMX->allocateBuffer(
- mNode, portIndex, def.nBufferSize, &buffer,
- &info.mData);
- } else {
- err = mOMX->allocateBufferWithBackup(
- mNode, portIndex, mem, &buffer, mem->size());
- }
- } else if (portIndex == kPortIndexOutput
- && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
- if (mOMXLivesLocally) {
- mem.clear();
-
- err = mOMX->allocateBuffer(
- mNode, portIndex, def.nBufferSize, &buffer,
- &info.mData);
- } else {
- err = mOMX->allocateBufferWithBackup(
- mNode, portIndex, mem, &buffer, mem->size());
- }
- } else {
- err = mOMX->useBuffer(mNode, portIndex, mem, &buffer, mem->size());
- }
-
- if (err != OK) {
- ALOGE("allocate_buffer_with_backup failed");
- return err;
- }
-
- if (mem != NULL) {
- info.mData = mem->pointer();
- }
-
- info.mBuffer = buffer;
- info.mStatus = OWNED_BY_US;
- info.mMem = mem;
- info.mMediaBuffer = NULL;
-
- if (portIndex == kPortIndexOutput) {
- // Fail deferred MediaBuffer creation until FILL_BUFFER_DONE;
- // this legacy mode is no longer supported.
- LOG_ALWAYS_FATAL_IF((mOMXLivesLocally
- && (mQuirks & kRequiresAllocateBufferOnOutputPorts)
- && (mQuirks & kDefersOutputBufferAllocation)),
- "allocateBuffersOnPort cannot defer buffer allocation");
-
- info.mMediaBuffer = new MediaBuffer(info.mData, info.mSize);
- info.mMediaBuffer->setObserver(this);
- }
-
- mPortBuffers[portIndex].push(info);
-
- CODEC_LOGV("allocated buffer %u on %s port", buffer,
- portIndex == kPortIndexInput ? "input" : "output");
- }
-
- if (portIndex == kPortIndexOutput) {
-
- sp<MetaData> meta = mSource->getFormat();
- int32_t delay = 0;
- if (!meta->findInt32(kKeyEncoderDelay, &delay)) {
- delay = 0;
- }
- int32_t padding = 0;
- if (!meta->findInt32(kKeyEncoderPadding, &padding)) {
- padding = 0;
- }
- int32_t numchannels = 0;
- if (delay + padding) {
- if (mOutputFormat->findInt32(kKeyChannelCount, &numchannels)) {
- size_t frameSize = numchannels * sizeof(int16_t);
- if (mSkipCutBuffer != NULL) {
- size_t prevbuffersize = mSkipCutBuffer->size();
- if (prevbuffersize != 0) {
- ALOGW("Replacing SkipCutBuffer holding %zu bytes", prevbuffersize);
- }
- }
- mSkipCutBuffer = new SkipCutBuffer(delay * frameSize, padding * frameSize);
- }
- }
- }
-
- // dumpPortStatus(portIndex);
-
- if (portIndex == kPortIndexInput && (mFlags & kUseSecureInputBuffers)) {
- Vector<MediaBuffer *> buffers;
- for (size_t i = 0; i < def.nBufferCountActual; ++i) {
- const BufferInfo &info = mPortBuffers[kPortIndexInput].itemAt(i);
-
- MediaBuffer *mbuf = new MediaBuffer(info.mData, info.mSize);
- buffers.push(mbuf);
- }
-
- status_t err = mSource->setBuffers(buffers);
-
- if (err != OK) {
- for (size_t i = 0; i < def.nBufferCountActual; ++i) {
- buffers.editItemAt(i)->release();
- }
- buffers.clear();
-
- CODEC_LOGE(
- "Codec requested to use secure input buffers but "
- "upstream source didn't support that.");
-
- return err;
- }
- }
-
- return OK;
-}
-
-status_t OMXCodec::allocateOutputBuffersFromNativeWindow() {
- // Get the number of buffers needed.
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
- def.nPortIndex = kPortIndexOutput;
-
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- if (err != OK) {
- CODEC_LOGE("getParameter failed: %d", err);
- return err;
- }
-
- sp<MetaData> meta = mSource->getFormat();
-
- int32_t rotationDegrees;
- if (!meta->findInt32(kKeyRotation, &rotationDegrees)) {
- rotationDegrees = 0;
- }
-
- // Set up the native window.
- OMX_U32 usage = 0;
- err = mOMX->getGraphicBufferUsage(mNode, kPortIndexOutput, &usage);
- if (err != 0) {
- ALOGW("querying usage flags from OMX IL component failed: %d", err);
- // XXX: Currently this error is logged, but not fatal.
- usage = 0;
- }
-
- if (mFlags & kEnableGrallocUsageProtected) {
- usage |= GRALLOC_USAGE_PROTECTED;
- }
-
- err = setNativeWindowSizeFormatAndUsage(
- mNativeWindow.get(),
- def.format.video.nFrameWidth,
- def.format.video.nFrameHeight,
- def.format.video.eColorFormat,
- rotationDegrees,
- usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
- if (err != 0) {
- return err;
- }
-
- int minUndequeuedBufs = 0;
- err = mNativeWindow->query(mNativeWindow.get(),
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
- if (err != 0) {
- ALOGE("NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
- // FIXME: assume that surface is controlled by app (native window
- // returns the number for the case when surface is not controlled by app)
- // FIXME2: This means that minUndeqeueudBufs can be 1 larger than reported
- // For now, try to allocate 1 more buffer, but don't fail if unsuccessful
-
- // Use conservative allocation while also trying to reduce starvation
- //
- // 1. allocate at least nBufferCountMin + minUndequeuedBuffers - that is the
- // minimum needed for the consumer to be able to work
- // 2. try to allocate two (2) additional buffers to reduce starvation from
- // the consumer
- // plus an extra buffer to account for incorrect minUndequeuedBufs
- CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d+1",
- def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs);
-
- for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) {
- OMX_U32 newBufferCount =
- def.nBufferCountMin + minUndequeuedBufs + extraBuffers;
- def.nBufferCountActual = newBufferCount;
- err = mOMX->setParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
-
- if (err == OK) {
- minUndequeuedBufs += extraBuffers;
- break;
- }
-
- CODEC_LOGW("setting nBufferCountActual to %u failed: %d",
- newBufferCount, err);
- /* exit condition */
- if (extraBuffers == 0) {
- return err;
- }
- }
- CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d+1",
- def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs);
-
- err = native_window_set_buffer_count(
- mNativeWindow.get(), def.nBufferCountActual);
- if (err != 0) {
- ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err),
- -err);
- return err;
- }
-
- CODEC_LOGV("allocating %u buffers from a native window of size %u on "
- "output port", def.nBufferCountActual, def.nBufferSize);
-
- // Dequeue buffers and send them to OMX
- for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {
- ANativeWindowBuffer* buf;
- err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf);
- if (err != 0) {
- ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
- break;
- }
-
- sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(buf, false));
- BufferInfo info;
- info.mData = NULL;
- info.mSize = def.nBufferSize;
- info.mStatus = OWNED_BY_US;
- info.mMem = NULL;
- info.mMediaBuffer = new MediaBuffer(graphicBuffer);
- info.mMediaBuffer->setObserver(this);
- mPortBuffers[kPortIndexOutput].push(info);
-
- IOMX::buffer_id bufferId;
- err = mOMX->useGraphicBuffer(mNode, kPortIndexOutput, graphicBuffer,
- &bufferId);
- if (err != 0) {
- CODEC_LOGE("registering GraphicBuffer with OMX IL component "
- "failed: %d", err);
- break;
- }
-
- mPortBuffers[kPortIndexOutput].editItemAt(i).mBuffer = bufferId;
-
- CODEC_LOGV("registered graphic buffer with ID %u (pointer = %p)",
- bufferId, graphicBuffer.get());
- }
-
- OMX_U32 cancelStart;
- OMX_U32 cancelEnd;
- if (err != 0) {
- // If an error occurred while dequeuing we need to cancel any buffers
- // that were dequeued.
- cancelStart = 0;
- cancelEnd = mPortBuffers[kPortIndexOutput].size();
- } else {
- // Return the last two buffers to the native window.
- cancelStart = def.nBufferCountActual - minUndequeuedBufs;
- cancelEnd = def.nBufferCountActual;
- }
-
- for (OMX_U32 i = cancelStart; i < cancelEnd; i++) {
- BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(i);
- cancelBufferToNativeWindow(info);
- }
-
- return err;
-}
-
-status_t OMXCodec::cancelBufferToNativeWindow(BufferInfo *info) {
- CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);
- CODEC_LOGV("Calling cancelBuffer on buffer %u", info->mBuffer);
- int err = mNativeWindow->cancelBuffer(
- mNativeWindow.get(), info->mMediaBuffer->graphicBuffer().get(), -1);
- if (err != 0) {
- CODEC_LOGE("cancelBuffer failed w/ error 0x%08x", err);
-
- setState(ERROR);
- return err;
- }
- info->mStatus = OWNED_BY_NATIVE_WINDOW;
- return OK;
-}
-
-OMXCodec::BufferInfo* OMXCodec::dequeueBufferFromNativeWindow() {
- // Dequeue the next buffer from the native window.
- ANativeWindowBuffer* buf;
- int err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf);
- if (err != 0) {
- CODEC_LOGE("dequeueBuffer failed w/ error 0x%08x", err);
-
- setState(ERROR);
- return 0;
- }
-
- // Determine which buffer we just dequeued.
- Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
- BufferInfo *bufInfo = 0;
- for (size_t i = 0; i < buffers->size(); i++) {
- sp<GraphicBuffer> graphicBuffer = buffers->itemAt(i).
- mMediaBuffer->graphicBuffer();
- if (graphicBuffer->handle == buf->handle) {
- bufInfo = &buffers->editItemAt(i);
- break;
- }
- }
-
- if (bufInfo == 0) {
- CODEC_LOGE("dequeued unrecognized buffer: %p", buf);
-
- setState(ERROR);
- return 0;
- }
-
- // The native window no longer owns the buffer.
- CHECK_EQ((int)bufInfo->mStatus, (int)OWNED_BY_NATIVE_WINDOW);
- bufInfo->mStatus = OWNED_BY_US;
-
- return bufInfo;
-}
-
-int64_t OMXCodec::getDecodingTimeUs() {
- CHECK(mIsEncoder && mIsVideo);
-
- if (mDecodingTimeList.empty()) {
- CHECK(mSignalledEOS || mNoMoreOutputData);
- // No corresponding input frame available.
- // This could happen when EOS is reached.
- return 0;
- }
-
- List<int64_t>::iterator it = mDecodingTimeList.begin();
- int64_t timeUs = *it;
- mDecodingTimeList.erase(it);
- return timeUs;
-}
-
-void OMXCodec::on_message(const omx_message &msg) {
- if (mState == ERROR) {
- /*
- * only drop EVENT messages, EBD and FBD are still
- * processed for bookkeeping purposes
- */
- if (msg.type == omx_message::EVENT) {
- ALOGW("Dropping OMX EVENT message - we're in ERROR state.");
- return;
- }
- }
-
- switch (msg.type) {
- case omx_message::EVENT:
- {
- onEvent(
- msg.u.event_data.event, msg.u.event_data.data1,
- msg.u.event_data.data2);
-
- break;
- }
-
- case omx_message::EMPTY_BUFFER_DONE:
- {
- IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
-
- CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %u)", buffer);
-
- Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
- size_t i = 0;
- while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
- ++i;
- }
-
- CHECK(i < buffers->size());
- if ((*buffers)[i].mStatus != OWNED_BY_COMPONENT) {
- ALOGW("We already own input buffer %u, yet received "
- "an EMPTY_BUFFER_DONE.", buffer);
- }
-
- BufferInfo* info = &buffers->editItemAt(i);
- info->mStatus = OWNED_BY_US;
-
- // Buffer could not be released until empty buffer done is called.
- if (info->mMediaBuffer != NULL) {
- info->mMediaBuffer->release();
- info->mMediaBuffer = NULL;
- }
-
- if (mPortStatus[kPortIndexInput] == DISABLING) {
- CODEC_LOGV("Port is disabled, freeing buffer %u", buffer);
-
- status_t err = freeBuffer(kPortIndexInput, i);
- CHECK_EQ(err, (status_t)OK);
- } else if (mState != ERROR
- && mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
- CHECK_EQ((int)mPortStatus[kPortIndexInput], (int)ENABLED);
-
- if (mFlags & kUseSecureInputBuffers) {
- drainAnyInputBuffer();
- } else {
- drainInputBuffer(&buffers->editItemAt(i));
- }
- }
- break;
- }
-
- case omx_message::FILL_BUFFER_DONE:
- {
- IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
- OMX_U32 flags = msg.u.extended_buffer_data.flags;
-
- CODEC_LOGV("FILL_BUFFER_DONE(buffer: %u, size: %u, flags: 0x%08x, timestamp: %lld us (%.2f secs))",
- buffer,
- msg.u.extended_buffer_data.range_length,
- flags,
- msg.u.extended_buffer_data.timestamp,
- msg.u.extended_buffer_data.timestamp / 1E6);
-
- Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
- size_t i = 0;
- while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
- ++i;
- }
-
- CHECK(i < buffers->size());
- BufferInfo *info = &buffers->editItemAt(i);
-
- if (info->mStatus != OWNED_BY_COMPONENT) {
- ALOGW("We already own output buffer %u, yet received "
- "a FILL_BUFFER_DONE.", buffer);
- }
-
- info->mStatus = OWNED_BY_US;
-
- if (mPortStatus[kPortIndexOutput] == DISABLING) {
- CODEC_LOGV("Port is disabled, freeing buffer %u", buffer);
-
- status_t err = freeBuffer(kPortIndexOutput, i);
- CHECK_EQ(err, (status_t)OK);
-
-#if 0
- } else if (mPortStatus[kPortIndexOutput] == ENABLED
- && (flags & OMX_BUFFERFLAG_EOS)) {
- CODEC_LOGV("No more output data.");
- mNoMoreOutputData = true;
- mBufferFilled.signal();
-#endif
- } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
- CHECK_EQ((int)mPortStatus[kPortIndexOutput], (int)ENABLED);
-
- MediaBuffer *buffer = info->mMediaBuffer;
- bool isGraphicBuffer = buffer->graphicBuffer() != NULL;
-
- if (!isGraphicBuffer
- && msg.u.extended_buffer_data.range_offset
- + msg.u.extended_buffer_data.range_length
- > buffer->size()) {
- CODEC_LOGE(
- "Codec lied about its buffer size requirements, "
- "sending a buffer larger than the originally "
- "advertised size in FILL_BUFFER_DONE!");
- }
- buffer->set_range(
- msg.u.extended_buffer_data.range_offset,
- msg.u.extended_buffer_data.range_length);
-
- buffer->meta_data()->clear();
-
- buffer->meta_data()->setInt64(
- kKeyTime, msg.u.extended_buffer_data.timestamp);
-
- if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
- buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
- }
- bool isCodecSpecific = false;
- if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_CODECCONFIG) {
- buffer->meta_data()->setInt32(kKeyIsCodecConfig, true);
- isCodecSpecific = true;
- }
-
- if (isGraphicBuffer || mQuirks & kOutputBuffersAreUnreadable) {
- buffer->meta_data()->setInt32(kKeyIsUnreadable, true);
- }
-
- buffer->meta_data()->setInt32(
- kKeyBufferID,
- msg.u.extended_buffer_data.buffer);
-
- if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_EOS) {
- CODEC_LOGV("No more output data.");
- mNoMoreOutputData = true;
- }
-
- if (mIsEncoder && mIsVideo) {
- int64_t decodingTimeUs = isCodecSpecific? 0: getDecodingTimeUs();
- buffer->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs);
- }
-
- if (mTargetTimeUs >= 0) {
- CHECK(msg.u.extended_buffer_data.timestamp <= mTargetTimeUs);
-
- if (msg.u.extended_buffer_data.timestamp < mTargetTimeUs) {
- CODEC_LOGV(
- "skipping output buffer at timestamp %lld us",
- msg.u.extended_buffer_data.timestamp);
-
- fillOutputBuffer(info);
- break;
- }
-
- CODEC_LOGV(
- "returning output buffer at target timestamp "
- "%lld us",
- msg.u.extended_buffer_data.timestamp);
-
- mTargetTimeUs = -1;
- }
-
- mFilledBuffers.push_back(i);
- mBufferFilled.signal();
- if (mIsEncoder) {
- sched_yield();
- }
- }
-
- break;
- }
-
- default:
- {
- CHECK(!"should not be here.");
- break;
- }
- }
-}
-
-// Has the format changed in any way that the client would have to be aware of?
-static bool formatHasNotablyChanged(
- const sp<MetaData> &from, const sp<MetaData> &to) {
- if (from.get() == NULL && to.get() == NULL) {
- return false;
- }
-
- if ((from.get() == NULL && to.get() != NULL)
- || (from.get() != NULL && to.get() == NULL)) {
- return true;
- }
-
- const char *mime_from, *mime_to;
- CHECK(from->findCString(kKeyMIMEType, &mime_from));
- CHECK(to->findCString(kKeyMIMEType, &mime_to));
-
- if (strcasecmp(mime_from, mime_to)) {
- return true;
- }
-
- if (!strcasecmp(mime_from, MEDIA_MIMETYPE_VIDEO_RAW)) {
- int32_t colorFormat_from, colorFormat_to;
- CHECK(from->findInt32(kKeyColorFormat, &colorFormat_from));
- CHECK(to->findInt32(kKeyColorFormat, &colorFormat_to));
-
- if (colorFormat_from != colorFormat_to) {
- return true;
- }
-
- int32_t width_from, width_to;
- CHECK(from->findInt32(kKeyWidth, &width_from));
- CHECK(to->findInt32(kKeyWidth, &width_to));
-
- if (width_from != width_to) {
- return true;
- }
-
- int32_t height_from, height_to;
- CHECK(from->findInt32(kKeyHeight, &height_from));
- CHECK(to->findInt32(kKeyHeight, &height_to));
-
- if (height_from != height_to) {
- return true;
- }
-
- int32_t left_from, top_from, right_from, bottom_from;
- CHECK(from->findRect(
- kKeyCropRect,
- &left_from, &top_from, &right_from, &bottom_from));
-
- int32_t left_to, top_to, right_to, bottom_to;
- CHECK(to->findRect(
- kKeyCropRect,
- &left_to, &top_to, &right_to, &bottom_to));
-
- if (left_to != left_from || top_to != top_from
- || right_to != right_from || bottom_to != bottom_from) {
- return true;
- }
- } else if (!strcasecmp(mime_from, MEDIA_MIMETYPE_AUDIO_RAW)) {
- int32_t numChannels_from, numChannels_to;
- CHECK(from->findInt32(kKeyChannelCount, &numChannels_from));
- CHECK(to->findInt32(kKeyChannelCount, &numChannels_to));
-
- if (numChannels_from != numChannels_to) {
- return true;
- }
-
- int32_t sampleRate_from, sampleRate_to;
- CHECK(from->findInt32(kKeySampleRate, &sampleRate_from));
- CHECK(to->findInt32(kKeySampleRate, &sampleRate_to));
-
- if (sampleRate_from != sampleRate_to) {
- return true;
- }
- }
-
- return false;
-}
-
-void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
- switch (event) {
- case OMX_EventCmdComplete:
- {
- onCmdComplete((OMX_COMMANDTYPE)data1, data2);
- break;
- }
-
- case OMX_EventError:
- {
- CODEC_LOGE("OMX_EventError(0x%08x, %u)", data1, data2);
-
- setState(ERROR);
- break;
- }
-
- case OMX_EventPortSettingsChanged:
- {
- CODEC_LOGV("OMX_EventPortSettingsChanged(port=%u, data2=0x%08x)",
- data1, data2);
-
- if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
- onPortSettingsChanged(data1);
- } else if (data1 == kPortIndexOutput &&
- (data2 == OMX_IndexConfigCommonOutputCrop ||
- data2 == OMX_IndexConfigCommonScale)) {
-
- sp<MetaData> oldOutputFormat = mOutputFormat;
- initOutputFormat(mSource->getFormat());
-
- if (data2 == OMX_IndexConfigCommonOutputCrop &&
- formatHasNotablyChanged(oldOutputFormat, mOutputFormat)) {
- mOutputPortSettingsHaveChanged = true;
-
- } else if (data2 == OMX_IndexConfigCommonScale) {
- OMX_CONFIG_SCALEFACTORTYPE scale;
- InitOMXParams(&scale);
- scale.nPortIndex = kPortIndexOutput;
-
- // Change display dimension only when necessary.
- if (OK == mOMX->getConfig(
- mNode,
- OMX_IndexConfigCommonScale,
- &scale, sizeof(scale))) {
- int32_t left, top, right, bottom;
- CHECK(mOutputFormat->findRect(kKeyCropRect,
- &left, &top,
- &right, &bottom));
-
- // The scale is in 16.16 format.
- // scale 1.0 = 0x010000. When there is no
- // need to change the display, skip it.
- ALOGV("Get OMX_IndexConfigScale: 0x%x/0x%x",
- scale.xWidth, scale.xHeight);
-
- if (scale.xWidth != 0x010000) {
- mOutputFormat->setInt32(kKeyDisplayWidth,
- ((right - left + 1) * scale.xWidth) >> 16);
- mOutputPortSettingsHaveChanged = true;
- }
-
- if (scale.xHeight != 0x010000) {
- mOutputFormat->setInt32(kKeyDisplayHeight,
- ((bottom - top + 1) * scale.xHeight) >> 16);
- mOutputPortSettingsHaveChanged = true;
- }
- }
- }
- }
- break;
- }
-
-#if 0
- case OMX_EventBufferFlag:
- {
- CODEC_LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
-
- if (data1 == kPortIndexOutput) {
- mNoMoreOutputData = true;
- }
- break;
- }
-#endif
-
- default:
- {
- CODEC_LOGV("EVENT(%d, %u, %u)", event, data1, data2);
- break;
- }
- }
-}
-
-void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
- switch (cmd) {
- case OMX_CommandStateSet:
- {
- onStateChange((OMX_STATETYPE)data);
- break;
- }
-
- case OMX_CommandPortDisable:
- {
- OMX_U32 portIndex = data;
- CODEC_LOGV("PORT_DISABLED(%u)", portIndex);
-
- CHECK(mState == EXECUTING || mState == RECONFIGURING);
- CHECK_EQ((int)mPortStatus[portIndex], (int)DISABLING);
- CHECK_EQ(mPortBuffers[portIndex].size(), 0u);
-
- mPortStatus[portIndex] = DISABLED;
-
- if (mState == RECONFIGURING) {
- CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput);
-
- sp<MetaData> oldOutputFormat = mOutputFormat;
- initOutputFormat(mSource->getFormat());
-
- // Don't notify clients if the output port settings change
- // wasn't of importance to them, i.e. it may be that just the
- // number of buffers has changed and nothing else.
- bool formatChanged = formatHasNotablyChanged(oldOutputFormat, mOutputFormat);
- if (!mOutputPortSettingsHaveChanged) {
- mOutputPortSettingsHaveChanged = formatChanged;
- }
-
- status_t err = enablePortAsync(portIndex);
- if (err != OK) {
- CODEC_LOGE("enablePortAsync(%u) failed (err = %d)", portIndex, err);
- setState(ERROR);
- } else {
- err = allocateBuffersOnPort(portIndex);
- if (err != OK) {
- CODEC_LOGE("allocateBuffersOnPort (%s) failed "
- "(err = %d)",
- portIndex == kPortIndexInput
- ? "input" : "output",
- err);
-
- setState(ERROR);
- }
- }
- }
- break;
- }
-
- case OMX_CommandPortEnable:
- {
- OMX_U32 portIndex = data;
- CODEC_LOGV("PORT_ENABLED(%u)", portIndex);
-
- CHECK(mState == EXECUTING || mState == RECONFIGURING);
- CHECK_EQ((int)mPortStatus[portIndex], (int)ENABLING);
-
- mPortStatus[portIndex] = ENABLED;
-
- if (mState == RECONFIGURING) {
- CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput);
-
- setState(EXECUTING);
-
- fillOutputBuffers();
- }
- break;
- }
-
- case OMX_CommandFlush:
- {
- OMX_U32 portIndex = data;
-
- CODEC_LOGV("FLUSH_DONE(%u)", portIndex);
-
- CHECK_EQ((int)mPortStatus[portIndex], (int)SHUTTING_DOWN);
- mPortStatus[portIndex] = ENABLED;
-
- CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
- mPortBuffers[portIndex].size());
-
- if (mSkipCutBuffer != NULL && mPortStatus[kPortIndexOutput] == ENABLED) {
- mSkipCutBuffer->clear();
- }
-
- if (mState == RECONFIGURING) {
- CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput);
-
- disablePortAsync(portIndex);
- } else if (mState == EXECUTING_TO_IDLE) {
- if (mPortStatus[kPortIndexInput] == ENABLED
- && mPortStatus[kPortIndexOutput] == ENABLED) {
- CODEC_LOGV("Finished flushing both ports, now completing "
- "transition from EXECUTING to IDLE.");
-
- mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
- mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
-
- status_t err =
- mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
- CHECK_EQ(err, (status_t)OK);
- }
- } else {
- // We're flushing both ports in preparation for seeking.
-
- if (mPortStatus[kPortIndexInput] == ENABLED
- && mPortStatus[kPortIndexOutput] == ENABLED) {
- CODEC_LOGV("Finished flushing both ports, now continuing from"
- " seek-time.");
-
- // We implicitly resume pulling on our upstream source.
- mPaused = false;
-
- drainInputBuffers();
- fillOutputBuffers();
- }
-
- if (mOutputPortSettingsChangedPending) {
- CODEC_LOGV(
- "Honoring deferred output port settings change.");
-
- mOutputPortSettingsChangedPending = false;
- onPortSettingsChanged(kPortIndexOutput);
- }
- }
-
- break;
- }
-
- default:
- {
- CODEC_LOGV("CMD_COMPLETE(%d, %u)", cmd, data);
- break;
- }
- }
-}
-
-void OMXCodec::onStateChange(OMX_STATETYPE newState) {
- CODEC_LOGV("onStateChange %d", newState);
-
- switch (newState) {
- case OMX_StateIdle:
- {
- CODEC_LOGV("Now Idle.");
- if (mState == LOADED_TO_IDLE) {
- status_t err = mOMX->sendCommand(
- mNode, OMX_CommandStateSet, OMX_StateExecuting);
-
- CHECK_EQ(err, (status_t)OK);
-
- setState(IDLE_TO_EXECUTING);
- } else {
- CHECK_EQ((int)mState, (int)EXECUTING_TO_IDLE);
-
- if (countBuffersWeOwn(mPortBuffers[kPortIndexInput]) !=
- mPortBuffers[kPortIndexInput].size()) {
- ALOGE("Codec did not return all input buffers "
- "(received %zu / %zu)",
- countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
- mPortBuffers[kPortIndexInput].size());
- TRESPASS();
- }
-
- if (countBuffersWeOwn(mPortBuffers[kPortIndexOutput]) !=
- mPortBuffers[kPortIndexOutput].size()) {
- ALOGE("Codec did not return all output buffers "
- "(received %zu / %zu)",
- countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
- mPortBuffers[kPortIndexOutput].size());
- TRESPASS();
- }
-
- status_t err = mOMX->sendCommand(
- mNode, OMX_CommandStateSet, OMX_StateLoaded);
-
- CHECK_EQ(err, (status_t)OK);
-
- err = freeBuffersOnPort(kPortIndexInput);
- CHECK_EQ(err, (status_t)OK);
-
- err = freeBuffersOnPort(kPortIndexOutput);
- CHECK_EQ(err, (status_t)OK);
-
- mPortStatus[kPortIndexInput] = ENABLED;
- mPortStatus[kPortIndexOutput] = ENABLED;
-
- if ((mFlags & kEnableGrallocUsageProtected) &&
- mNativeWindow != NULL) {
- // We push enough 1x1 blank buffers to ensure that one of
- // them has made it to the display. This allows the OMX
- // component teardown to zero out any protected buffers
- // without the risk of scanning out one of those buffers.
- pushBlankBuffersToNativeWindow(mNativeWindow.get());
- }
-
- setState(IDLE_TO_LOADED);
- }
- break;
- }
-
- case OMX_StateExecuting:
- {
- CHECK_EQ((int)mState, (int)IDLE_TO_EXECUTING);
-
- CODEC_LOGV("Now Executing.");
-
- mOutputPortSettingsChangedPending = false;
-
- setState(EXECUTING);
-
- // Buffers will be submitted to the component in the first
- // call to OMXCodec::read as mInitialBufferSubmit is true at
- // this point. This ensures that this on_message call returns,
- // releases the lock and ::init can notice the state change and
- // itself return.
- break;
- }
-
- case OMX_StateLoaded:
- {
- CHECK_EQ((int)mState, (int)IDLE_TO_LOADED);
-
- CODEC_LOGV("Now Loaded.");
-
- setState(LOADED);
- break;
- }
-
- case OMX_StateInvalid:
- {
- setState(ERROR);
- break;
- }
-
- default:
- {
- CHECK(!"should not be here.");
- break;
- }
- }
-}
-
-// static
-size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
- size_t n = 0;
- for (size_t i = 0; i < buffers.size(); ++i) {
- if (buffers[i].mStatus != OWNED_BY_COMPONENT) {
- ++n;
- }
- }
-
- return n;
-}
-
-status_t OMXCodec::freeBuffersOnPort(
- OMX_U32 portIndex, bool onlyThoseWeOwn) {
- Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
-
- status_t stickyErr = OK;
-
- for (size_t i = buffers->size(); i-- > 0;) {
- BufferInfo *info = &buffers->editItemAt(i);
-
- if (onlyThoseWeOwn && info->mStatus == OWNED_BY_COMPONENT) {
- continue;
- }
-
- CHECK(info->mStatus == OWNED_BY_US
- || info->mStatus == OWNED_BY_NATIVE_WINDOW);
-
- CODEC_LOGV("freeing buffer %u on port %u", info->mBuffer, portIndex);
-
- status_t err = freeBuffer(portIndex, i);
-
- if (err != OK) {
- stickyErr = err;
- }
-
- }
-
- CHECK(onlyThoseWeOwn || buffers->isEmpty());
-
- return stickyErr;
-}
-
-status_t OMXCodec::freeBuffer(OMX_U32 portIndex, size_t bufIndex) {
- Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
-
- BufferInfo *info = &buffers->editItemAt(bufIndex);
-
- status_t err = mOMX->freeBuffer(mNode, portIndex, info->mBuffer);
-
- if (err == OK && info->mMediaBuffer != NULL) {
- CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput);
- info->mMediaBuffer->setObserver(NULL);
-
- // Make sure nobody but us owns this buffer at this point.
- CHECK_EQ(info->mMediaBuffer->refcount(), 0);
-
- // Cancel the buffer if it belongs to an ANativeWindow.
- sp<GraphicBuffer> graphicBuffer = info->mMediaBuffer->graphicBuffer();
- if (info->mStatus == OWNED_BY_US && graphicBuffer != 0) {
- err = cancelBufferToNativeWindow(info);
- }
-
- info->mMediaBuffer->release();
- info->mMediaBuffer = NULL;
- }
-
- if (err == OK) {
- buffers->removeAt(bufIndex);
- }
-
- return err;
-}
-
-void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
- CODEC_LOGV("PORT_SETTINGS_CHANGED(%u)", portIndex);
-
- CHECK(mState == EXECUTING || mState == EXECUTING_TO_IDLE);
- CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput);
- CHECK(!mOutputPortSettingsChangedPending);
-
- if (mPortStatus[kPortIndexOutput] != ENABLED) {
- CODEC_LOGV("Deferring output port settings change.");
- mOutputPortSettingsChangedPending = true;
- return;
- }
-
- setState(RECONFIGURING);
-
- if (mQuirks & kNeedsFlushBeforeDisable) {
- if (!flushPortAsync(portIndex)) {
- onCmdComplete(OMX_CommandFlush, portIndex);
- }
- } else {
- disablePortAsync(portIndex);
- }
-}
-
-bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
- CHECK(mState == EXECUTING || mState == RECONFIGURING
- || mState == EXECUTING_TO_IDLE);
-
- CODEC_LOGV("flushPortAsync(%u): we own %zu out of %zu buffers already.",
- portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
- mPortBuffers[portIndex].size());
-
- CHECK_EQ((int)mPortStatus[portIndex], (int)ENABLED);
- mPortStatus[portIndex] = SHUTTING_DOWN;
-
- if ((mQuirks & kRequiresFlushCompleteEmulation)
- && countBuffersWeOwn(mPortBuffers[portIndex])
- == mPortBuffers[portIndex].size()) {
- // No flush is necessary and this component fails to send a
- // flush-complete event in this case.
-
- return false;
- }
-
- status_t err =
- mOMX->sendCommand(mNode, OMX_CommandFlush, portIndex);
- CHECK_EQ(err, (status_t)OK);
-
- return true;
-}
-
-void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
- CHECK(mState == EXECUTING || mState == RECONFIGURING);
-
- CHECK_EQ((int)mPortStatus[portIndex], (int)ENABLED);
- mPortStatus[portIndex] = DISABLING;
-
- CODEC_LOGV("sending OMX_CommandPortDisable(%u)", portIndex);
- status_t err =
- mOMX->sendCommand(mNode, OMX_CommandPortDisable, portIndex);
- CHECK_EQ(err, (status_t)OK);
-
- freeBuffersOnPort(portIndex, true);
-}
-
-status_t OMXCodec::enablePortAsync(OMX_U32 portIndex) {
- CHECK(mState == EXECUTING || mState == RECONFIGURING);
-
- CHECK_EQ((int)mPortStatus[portIndex], (int)DISABLED);
- mPortStatus[portIndex] = ENABLING;
-
- CODEC_LOGV("sending OMX_CommandPortEnable(%u)", portIndex);
- return mOMX->sendCommand(mNode, OMX_CommandPortEnable, portIndex);
-}
-
-void OMXCodec::fillOutputBuffers() {
- CHECK_EQ((int)mState, (int)EXECUTING);
-
- // This is a workaround for some decoders not properly reporting
- // end-of-output-stream. If we own all input buffers and also own
- // all output buffers and we already signalled end-of-input-stream,
- // the end-of-output-stream is implied.
- if (mSignalledEOS
- && countBuffersWeOwn(mPortBuffers[kPortIndexInput])
- == mPortBuffers[kPortIndexInput].size()
- && countBuffersWeOwn(mPortBuffers[kPortIndexOutput])
- == mPortBuffers[kPortIndexOutput].size()) {
- mNoMoreOutputData = true;
- mBufferFilled.signal();
-
- return;
- }
-
- Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
- for (size_t i = 0; i < buffers->size(); ++i) {
- BufferInfo *info = &buffers->editItemAt(i);
- if (info->mStatus == OWNED_BY_US) {
- fillOutputBuffer(&buffers->editItemAt(i));
- }
- }
-}
-
-void OMXCodec::drainInputBuffers() {
- CHECK(mState == EXECUTING || mState == RECONFIGURING);
-
- if (mFlags & kUseSecureInputBuffers) {
- Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
- for (size_t i = 0; i < buffers->size(); ++i) {
- if (!drainAnyInputBuffer()
- || (mFlags & kOnlySubmitOneInputBufferAtOneTime)) {
- break;
- }
- }
- } else {
- Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
- for (size_t i = 0; i < buffers->size(); ++i) {
- BufferInfo *info = &buffers->editItemAt(i);
-
- if (info->mStatus != OWNED_BY_US) {
- continue;
- }
-
- if (!drainInputBuffer(info)) {
- break;
- }
-
- if (mFlags & kOnlySubmitOneInputBufferAtOneTime) {
- break;
- }
- }
- }
-}
-
-bool OMXCodec::drainAnyInputBuffer() {
- return drainInputBuffer((BufferInfo *)NULL);
-}
-
-OMXCodec::BufferInfo *OMXCodec::findInputBufferByDataPointer(void *ptr) {
- Vector<BufferInfo> *infos = &mPortBuffers[kPortIndexInput];
- for (size_t i = 0; i < infos->size(); ++i) {
- BufferInfo *info = &infos->editItemAt(i);
-
- if (info->mData == ptr) {
- CODEC_LOGV(
- "input buffer data ptr = %p, buffer_id = %u",
- ptr,
- info->mBuffer);
-
- return info;
- }
- }
-
- TRESPASS();
-}
-
-OMXCodec::BufferInfo *OMXCodec::findEmptyInputBuffer() {
- Vector<BufferInfo> *infos = &mPortBuffers[kPortIndexInput];
- for (size_t i = 0; i < infos->size(); ++i) {
- BufferInfo *info = &infos->editItemAt(i);
-
- if (info->mStatus == OWNED_BY_US) {
- return info;
- }
- }
-
- TRESPASS();
-}
-
-bool OMXCodec::drainInputBuffer(BufferInfo *info) {
- if (info != NULL) {
- CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);
- }
-
- if (mSignalledEOS) {
- return false;
- }
-
- if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
- CHECK(!(mFlags & kUseSecureInputBuffers));
-
- const CodecSpecificData *specific =
- mCodecSpecificData[mCodecSpecificDataIndex];
-
- size_t size = specific->mSize;
-
- if ((!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME) ||
- !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mMIME))
- && !(mQuirks & kWantsNALFragments)) {
- static const uint8_t kNALStartCode[4] =
- { 0x00, 0x00, 0x00, 0x01 };
-
- CHECK(info->mSize >= specific->mSize + 4);
-
- size += 4;
-
- memcpy(info->mData, kNALStartCode, 4);
- memcpy((uint8_t *)info->mData + 4,
- specific->mData, specific->mSize);
- } else {
- CHECK(info->mSize >= specific->mSize);
- memcpy(info->mData, specific->mData, specific->mSize);
- }
-
- mNoMoreOutputData = false;
-
- CODEC_LOGV("calling emptyBuffer with codec specific data");
-
- status_t err = mOMX->emptyBuffer(
- mNode, info->mBuffer, 0, size,
- OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
- 0);
- CHECK_EQ(err, (status_t)OK);
-
- info->mStatus = OWNED_BY_COMPONENT;
-
- ++mCodecSpecificDataIndex;
- return true;
- }
-
- if (mPaused) {
- return false;
- }
-
- status_t err;
-
- bool signalEOS = false;
- int64_t timestampUs = 0;
-
- size_t offset = 0;
- int32_t n = 0;
-
-
- for (;;) {
- MediaBuffer *srcBuffer;
- if (mSeekTimeUs >= 0) {
- if (mLeftOverBuffer) {
- mLeftOverBuffer->release();
- mLeftOverBuffer = NULL;
- }
-
- MediaSource::ReadOptions options;
- options.setSeekTo(mSeekTimeUs, mSeekMode);
-
- mSeekTimeUs = -1;
- mSeekMode = ReadOptions::SEEK_CLOSEST_SYNC;
- mBufferFilled.signal();
-
- err = mSource->read(&srcBuffer, &options);
-
- if (err == OK) {
- int64_t targetTimeUs;
- if (srcBuffer->meta_data()->findInt64(
- kKeyTargetTime, &targetTimeUs)
- && targetTimeUs >= 0) {
- CODEC_LOGV("targetTimeUs = %lld us", (long long)targetTimeUs);
- mTargetTimeUs = targetTimeUs;
- } else {
- mTargetTimeUs = -1;
- }
- }
- } else if (mLeftOverBuffer) {
- srcBuffer = mLeftOverBuffer;
- mLeftOverBuffer = NULL;
-
- err = OK;
- } else {
- err = mSource->read(&srcBuffer);
- }
-
- if (err != OK) {
- signalEOS = true;
- mFinalStatus = err;
- mSignalledEOS = true;
- mBufferFilled.signal();
- break;
- }
-
- if (mFlags & kUseSecureInputBuffers) {
- info = findInputBufferByDataPointer(srcBuffer->data());
- CHECK(info != NULL);
- }
-
- size_t remainingBytes = info->mSize - offset;
-
- if (srcBuffer->range_length() > remainingBytes) {
- if (offset == 0) {
- CODEC_LOGE(
- "Codec's input buffers are too small to accomodate "
- "buffer read from source (info->mSize = %zu, srcLength = %zu)",
- info->mSize, srcBuffer->range_length());
-
- srcBuffer->release();
- srcBuffer = NULL;
-
- setState(ERROR);
- return false;
- }
-
- mLeftOverBuffer = srcBuffer;
- break;
- }
-
- bool releaseBuffer = true;
- if (mFlags & kStoreMetaDataInVideoBuffers) {
- releaseBuffer = false;
- info->mMediaBuffer = srcBuffer;
- }
-
- if (mFlags & kUseSecureInputBuffers) {
- // Data in "info" is already provided at this time.
-
- releaseBuffer = false;
-
- CHECK(info->mMediaBuffer == NULL);
- info->mMediaBuffer = srcBuffer;
- } else {
- CHECK(srcBuffer->data() != NULL) ;
- memcpy((uint8_t *)info->mData + offset,
- (const uint8_t *)srcBuffer->data()
- + srcBuffer->range_offset(),
- srcBuffer->range_length());
- }
-
- int64_t lastBufferTimeUs;
- CHECK(srcBuffer->meta_data()->findInt64(kKeyTime, &lastBufferTimeUs));
- CHECK(lastBufferTimeUs >= 0);
- if (mIsEncoder && mIsVideo) {
- mDecodingTimeList.push_back(lastBufferTimeUs);
- }
-
- if (offset == 0) {
- timestampUs = lastBufferTimeUs;
- }
-
- offset += srcBuffer->range_length();
-
- if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_VORBIS, mMIME)) {
- CHECK(!(mQuirks & kSupportsMultipleFramesPerInputBuffer));
- CHECK_GE(info->mSize, offset + sizeof(int32_t));
-
- int32_t numPageSamples;
- if (!srcBuffer->meta_data()->findInt32(
- kKeyValidSamples, &numPageSamples)) {
- numPageSamples = -1;
- }
-
- memcpy((uint8_t *)info->mData + offset,
- &numPageSamples,
- sizeof(numPageSamples));
-
- offset += sizeof(numPageSamples);
- }
-
- if (releaseBuffer) {
- srcBuffer->release();
- srcBuffer = NULL;
- }
-
- ++n;
-
- if (!(mQuirks & kSupportsMultipleFramesPerInputBuffer)) {
- break;
- }
-
- int64_t coalescedDurationUs = lastBufferTimeUs - timestampUs;
-
- if (coalescedDurationUs > 250000ll) {
- // Don't coalesce more than 250ms worth of encoded data at once.
- break;
- }
- }
-
- if (n > 1) {
- ALOGV("coalesced %d frames into one input buffer", n);
- }
-
- OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
-
- if (signalEOS) {
- flags |= OMX_BUFFERFLAG_EOS;
- } else {
- mNoMoreOutputData = false;
- }
-
- if (info == NULL) {
- CHECK(mFlags & kUseSecureInputBuffers);
- CHECK(signalEOS);
-
- // This is fishy, there's still a MediaBuffer corresponding to this
- // info available to the source at this point even though we're going
- // to use it to signal EOS to the codec.
- info = findEmptyInputBuffer();
- }
-
- CODEC_LOGV("Calling emptyBuffer on buffer %u (length %zu), "
- "timestamp %lld us (%.2f secs)",
- info->mBuffer, offset,
- (long long)timestampUs, timestampUs / 1E6);
-
- err = mOMX->emptyBuffer(
- mNode, info->mBuffer, 0, offset,
- flags, timestampUs);
-
- if (err != OK) {
- setState(ERROR);
- return false;
- }
-
- info->mStatus = OWNED_BY_COMPONENT;
-
- return true;
-}
-
-void OMXCodec::fillOutputBuffer(BufferInfo *info) {
- CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);
-
- if (mNoMoreOutputData) {
- CODEC_LOGV("There is no more output data available, not "
- "calling fillOutputBuffer");
- return;
- }
-
- CODEC_LOGV("Calling fillBuffer on buffer %u", info->mBuffer);
- status_t err = mOMX->fillBuffer(mNode, info->mBuffer);
-
- if (err != OK) {
- CODEC_LOGE("fillBuffer failed w/ error 0x%08x", err);
-
- setState(ERROR);
- return;
- }
-
- info->mStatus = OWNED_BY_COMPONENT;
-}
-
-bool OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
- Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
- for (size_t i = 0; i < buffers->size(); ++i) {
- if ((*buffers)[i].mBuffer == buffer) {
- return drainInputBuffer(&buffers->editItemAt(i));
- }
- }
-
- CHECK(!"should not be here.");
-
- return false;
-}
-
-void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
- Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
- for (size_t i = 0; i < buffers->size(); ++i) {
- if ((*buffers)[i].mBuffer == buffer) {
- fillOutputBuffer(&buffers->editItemAt(i));
- return;
- }
- }
-
- CHECK(!"should not be here.");
-}
-
-void OMXCodec::setState(State newState) {
- mState = newState;
- mAsyncCompletion.signal();
-
- // This may cause some spurious wakeups but is necessary to
- // unblock the reader if we enter ERROR state.
- mBufferFilled.signal();
-}
-
-status_t OMXCodec::waitForBufferFilled_l() {
-
- if (mIsEncoder) {
- // For timelapse video recording, the timelapse video recording may
- // not send an input frame for a _long_ time. Do not use timeout
- // for video encoding.
- return mBufferFilled.wait(mLock);
- }
- status_t err = mBufferFilled.waitRelative(mLock, kBufferFilledEventTimeOutNs);
- if (err != OK) {
- CODEC_LOGE("Timed out waiting for output buffers: %zu/%zu",
- countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
- countBuffersWeOwn(mPortBuffers[kPortIndexOutput]));
- }
- return err;
-}
-
-void OMXCodec::setRawAudioFormat(
- OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
-
- // port definition
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
- def.nPortIndex = portIndex;
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
- def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
- CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamPortDefinition,
- &def, sizeof(def)), (status_t)OK);
-
- // pcm param
- OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
- InitOMXParams(&pcmParams);
- pcmParams.nPortIndex = portIndex;
-
- err = mOMX->getParameter(
- mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
-
- CHECK_EQ(err, (status_t)OK);
-
- pcmParams.nChannels = numChannels;
- pcmParams.eNumData = OMX_NumericalDataSigned;
- pcmParams.bInterleaved = OMX_TRUE;
- pcmParams.nBitPerSample = 16;
- pcmParams.nSamplingRate = sampleRate;
- pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
-
- CHECK_EQ(getOMXChannelMapping(
- numChannels, pcmParams.eChannelMapping), (status_t)OK);
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
-
- CHECK_EQ(err, (status_t)OK);
-}
-
-static OMX_AUDIO_AMRBANDMODETYPE pickModeFromBitRate(bool isAMRWB, int32_t bps) {
- if (isAMRWB) {
- if (bps <= 6600) {
- return OMX_AUDIO_AMRBandModeWB0;
- } else if (bps <= 8850) {
- return OMX_AUDIO_AMRBandModeWB1;
- } else if (bps <= 12650) {
- return OMX_AUDIO_AMRBandModeWB2;
- } else if (bps <= 14250) {
- return OMX_AUDIO_AMRBandModeWB3;
- } else if (bps <= 15850) {
- return OMX_AUDIO_AMRBandModeWB4;
- } else if (bps <= 18250) {
- return OMX_AUDIO_AMRBandModeWB5;
- } else if (bps <= 19850) {
- return OMX_AUDIO_AMRBandModeWB6;
- } else if (bps <= 23050) {
- return OMX_AUDIO_AMRBandModeWB7;
- }
-
- // 23850 bps
- return OMX_AUDIO_AMRBandModeWB8;
- } else { // AMRNB
- if (bps <= 4750) {
- return OMX_AUDIO_AMRBandModeNB0;
- } else if (bps <= 5150) {
- return OMX_AUDIO_AMRBandModeNB1;
- } else if (bps <= 5900) {
- return OMX_AUDIO_AMRBandModeNB2;
- } else if (bps <= 6700) {
- return OMX_AUDIO_AMRBandModeNB3;
- } else if (bps <= 7400) {
- return OMX_AUDIO_AMRBandModeNB4;
- } else if (bps <= 7950) {
- return OMX_AUDIO_AMRBandModeNB5;
- } else if (bps <= 10200) {
- return OMX_AUDIO_AMRBandModeNB6;
- }
-
- // 12200 bps
- return OMX_AUDIO_AMRBandModeNB7;
- }
-}
-
-void OMXCodec::setAMRFormat(bool isWAMR, int32_t bitRate) {
- OMX_U32 portIndex = mIsEncoder ? kPortIndexOutput : kPortIndexInput;
-
- OMX_AUDIO_PARAM_AMRTYPE def;
- InitOMXParams(&def);
- def.nPortIndex = portIndex;
-
- status_t err =
- mOMX->getParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
-
- CHECK_EQ(err, (status_t)OK);
-
- def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
-
- def.eAMRBandMode = pickModeFromBitRate(isWAMR, bitRate);
- err = mOMX->setParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
-
- ////////////////////////
-
- if (mIsEncoder) {
- sp<MetaData> format = mSource->getFormat();
- int32_t sampleRate;
- int32_t numChannels;
- CHECK(format->findInt32(kKeySampleRate, &sampleRate));
- CHECK(format->findInt32(kKeyChannelCount, &numChannels));
-
- setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
- }
-}
-
-status_t OMXCodec::setAACFormat(
- int32_t numChannels, int32_t sampleRate, int32_t bitRate, int32_t aacProfile, bool isADTS) {
- if (numChannels > 2) {
- ALOGW("Number of channels: (%d) \n", numChannels);
- }
-
- if (mIsEncoder) {
- if (isADTS) {
- return -EINVAL;
- }
-
- //////////////// input port ////////////////////
- setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
-
- //////////////// output port ////////////////////
- // format
- OMX_AUDIO_PARAM_PORTFORMATTYPE format;
- InitOMXParams(&format);
- format.nPortIndex = kPortIndexOutput;
- format.nIndex = 0;
- status_t err = OMX_ErrorNone;
- while (OMX_ErrorNone == err) {
- CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioPortFormat,
- &format, sizeof(format)), (status_t)OK);
- if (format.eEncoding == OMX_AUDIO_CodingAAC) {
- break;
- }
- format.nIndex++;
- }
- CHECK_EQ((status_t)OK, err);
- CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamAudioPortFormat,
- &format, sizeof(format)), (status_t)OK);
-
- // port definition
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
- def.nPortIndex = kPortIndexOutput;
- CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamPortDefinition,
- &def, sizeof(def)), (status_t)OK);
- def.format.audio.bFlagErrorConcealment = OMX_TRUE;
- def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
- CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamPortDefinition,
- &def, sizeof(def)), (status_t)OK);
-
- // profile
- OMX_AUDIO_PARAM_AACPROFILETYPE profile;
- InitOMXParams(&profile);
- profile.nPortIndex = kPortIndexOutput;
- CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioAac,
- &profile, sizeof(profile)), (status_t)OK);
- profile.nChannels = numChannels;
- profile.eChannelMode = (numChannels == 1?
- OMX_AUDIO_ChannelModeMono: OMX_AUDIO_ChannelModeStereo);
- profile.nSampleRate = sampleRate;
- profile.nBitRate = bitRate;
- profile.nAudioBandWidth = 0;
- profile.nFrameLength = 0;
- profile.nAACtools = OMX_AUDIO_AACToolAll;
- profile.nAACERtools = OMX_AUDIO_AACERNone;
- profile.eAACProfile = (OMX_AUDIO_AACPROFILETYPE) aacProfile;
- profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
- err = mOMX->setParameter(mNode, OMX_IndexParamAudioAac,
- &profile, sizeof(profile));
-
- if (err != OK) {
- CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed "
- "(err = %d)",
- err);
- return err;
- }
- } else {
- OMX_AUDIO_PARAM_AACPROFILETYPE profile;
- InitOMXParams(&profile);
- profile.nPortIndex = kPortIndexInput;
-
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
- CHECK_EQ(err, (status_t)OK);
-
- profile.nChannels = numChannels;
- profile.nSampleRate = sampleRate;
-
- profile.eAACStreamFormat =
- isADTS
- ? OMX_AUDIO_AACStreamFormatMP4ADTS
- : OMX_AUDIO_AACStreamFormatMP4FF;
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
-
- if (err != OK) {
- CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed "
- "(err = %d)",
- err);
- return err;
- }
- }
-
- return OK;
-}
-
-status_t OMXCodec::setAC3Format(int32_t numChannels, int32_t sampleRate) {
- OMX_AUDIO_PARAM_ANDROID_AC3TYPE def;
- InitOMXParams(&def);
- def.nPortIndex = kPortIndexInput;
-
- status_t err = mOMX->getParameter(
- mNode,
- (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3,
- &def,
- sizeof(def));
-
- if (err != OK) {
- return err;
- }
-
- def.nChannels = numChannels;
- def.nSampleRate = sampleRate;
-
- return mOMX->setParameter(
- mNode,
- (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3,
- &def,
- sizeof(def));
-}
-
-void OMXCodec::setG711Format(int32_t sampleRate, int32_t numChannels) {
- CHECK(!mIsEncoder);
- setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
-}
-
-void OMXCodec::setImageOutputFormat(
- OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
- CODEC_LOGV("setImageOutputFormat(%u, %u)", width, height);
-
-#if 0
- OMX_INDEXTYPE index;
- status_t err = mOMX->get_extension_index(
- mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
- CHECK_EQ(err, (status_t)OK);
-
- err = mOMX->set_config(mNode, index, &format, sizeof(format));
- CHECK_EQ(err, (status_t)OK);
-#endif
-
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
- def.nPortIndex = kPortIndexOutput;
-
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
-
- CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainImage);
-
- OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
-
- CHECK_EQ((int)imageDef->eCompressionFormat, (int)OMX_IMAGE_CodingUnused);
- imageDef->eColorFormat = format;
- imageDef->nFrameWidth = width;
- imageDef->nFrameHeight = height;
-
- switch (format) {
- case OMX_COLOR_FormatYUV420PackedPlanar:
- case OMX_COLOR_FormatYUV411Planar:
- {
- def.nBufferSize = (width * height * 3) / 2;
- break;
- }
-
- case OMX_COLOR_FormatCbYCrY:
- {
- def.nBufferSize = width * height * 2;
- break;
- }
-
- case OMX_COLOR_Format32bitARGB8888:
- {
- def.nBufferSize = width * height * 4;
- break;
- }
-
- case OMX_COLOR_Format16bitARGB4444:
- case OMX_COLOR_Format16bitARGB1555:
- case OMX_COLOR_Format16bitRGB565:
- case OMX_COLOR_Format16bitBGR565:
- {
- def.nBufferSize = width * height * 2;
- break;
- }
-
- default:
- CHECK(!"Should not be here. Unknown color format.");
- break;
- }
-
- def.nBufferCountActual = def.nBufferCountMin;
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
-}
-
-void OMXCodec::setJPEGInputFormat(
- OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
- def.nPortIndex = kPortIndexInput;
-
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
-
- CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainImage);
- OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
-
- CHECK_EQ((int)imageDef->eCompressionFormat, (int)OMX_IMAGE_CodingJPEG);
- imageDef->nFrameWidth = width;
- imageDef->nFrameHeight = height;
-
- def.nBufferSize = compressedSize;
- def.nBufferCountActual = def.nBufferCountMin;
-
- err = mOMX->setParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
-}
-
-void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
- CodecSpecificData *specific =
- (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
-
- specific->mSize = size;
- memcpy(specific->mData, data, size);
-
- mCodecSpecificData.push(specific);
-}
-
-void OMXCodec::clearCodecSpecificData() {
- for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
- free(mCodecSpecificData.editItemAt(i));
- }
- mCodecSpecificData.clear();
- mCodecSpecificDataIndex = 0;
-}
-
-status_t OMXCodec::start(MetaData *meta) {
- Mutex::Autolock autoLock(mLock);
-
- if (mState != LOADED) {
- CODEC_LOGE("called start in the unexpected state: %d", mState);
- return UNKNOWN_ERROR;
- }
-
- sp<MetaData> params = new MetaData;
- if (mQuirks & kWantsNALFragments) {
- params->setInt32(kKeyWantsNALFragments, true);
- }
- if (meta) {
- int64_t startTimeUs = 0;
- int64_t timeUs;
- if (meta->findInt64(kKeyTime, &timeUs)) {
- startTimeUs = timeUs;
- }
- params->setInt64(kKeyTime, startTimeUs);
- }
-
- mCodecSpecificDataIndex = 0;
- mInitialBufferSubmit = true;
- mSignalledEOS = false;
- mNoMoreOutputData = false;
- mOutputPortSettingsHaveChanged = false;
- mSeekTimeUs = -1;
- mSeekMode = ReadOptions::SEEK_CLOSEST_SYNC;
- mTargetTimeUs = -1;
- mFilledBuffers.clear();
- mPaused = false;
-
- status_t err;
- if (mIsEncoder) {
- // Calling init() before starting its source so that we can configure,
- // if supported, the source to use exactly the same number of input
- // buffers as requested by the encoder.
- if ((err = init()) != OK) {
- CODEC_LOGE("init failed: %d", err);
- return err;
- }
-
- params->setInt32(kKeyNumBuffers, mPortBuffers[kPortIndexInput].size());
- err = mSource->start(params.get());
- if (err != OK) {
- CODEC_LOGE("source failed to start: %d", err);
- stopOmxComponent_l();
- }
- return err;
- }
-
- // Decoder case
- if ((err = mSource->start(params.get())) != OK) {
- CODEC_LOGE("source failed to start: %d", err);
- return err;
- }
- return init();
-}
-
-status_t OMXCodec::stop() {
- CODEC_LOGV("stop mState=%d", mState);
- Mutex::Autolock autoLock(mLock);
- status_t err = stopOmxComponent_l();
- mSource->stop();
-
- CODEC_LOGV("stopped in state %d", mState);
- return err;
-}
-
-status_t OMXCodec::stopOmxComponent_l() {
- CODEC_LOGV("stopOmxComponent_l mState=%d", mState);
-
- while (isIntermediateState(mState)) {
- mAsyncCompletion.wait(mLock);
- }
-
- bool isError = false;
- switch (mState) {
- case LOADED:
- break;
-
- case ERROR:
- {
- if (mPortStatus[kPortIndexOutput] == ENABLING) {
- // Codec is in a wedged state (technical term)
- // We've seen an output port settings change from the codec,
- // We've disabled the output port, then freed the output
- // buffers, initiated re-enabling the output port but
- // failed to reallocate the output buffers.
- // There doesn't seem to be a way to orderly transition
- // from executing->idle and idle->loaded now that the
- // output port hasn't been reenabled yet...
- // Simply free as many resources as we can and pretend
- // that we're in LOADED state so that the destructor
- // will free the component instance without asserting.
- freeBuffersOnPort(kPortIndexInput, true /* onlyThoseWeOwn */);
- freeBuffersOnPort(kPortIndexOutput, true /* onlyThoseWeOwn */);
- setState(LOADED);
- break;
- } else {
- OMX_STATETYPE state = OMX_StateInvalid;
- status_t err = mOMX->getState(mNode, &state);
- CHECK_EQ(err, (status_t)OK);
-
- if (state != OMX_StateExecuting) {
- break;
- }
- // else fall through to the idling code
- }
-
- isError = true;
- }
-
- case EXECUTING:
- {
- setState(EXECUTING_TO_IDLE);
-
- if (mQuirks & kRequiresFlushBeforeShutdown) {
- CODEC_LOGV("This component requires a flush before transitioning "
- "from EXECUTING to IDLE...");
-
- bool emulateInputFlushCompletion =
- !flushPortAsync(kPortIndexInput);
-
- bool emulateOutputFlushCompletion =
- !flushPortAsync(kPortIndexOutput);
-
- if (emulateInputFlushCompletion) {
- onCmdComplete(OMX_CommandFlush, kPortIndexInput);
- }
-
- if (emulateOutputFlushCompletion) {
- onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
- }
- } else {
- mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
- mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
-
- status_t err =
- mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
- CHECK_EQ(err, (status_t)OK);
- }
-
- while (mState != LOADED && mState != ERROR) {
- mAsyncCompletion.wait(mLock);
- }
-
- if (isError) {
- // We were in the ERROR state coming in, so restore that now
- // that we've idled the OMX component.
- setState(ERROR);
- }
-
- break;
- }
-
- default:
- {
- CHECK(!"should not be here.");
- break;
- }
- }
-
- if (mLeftOverBuffer) {
- mLeftOverBuffer->release();
- mLeftOverBuffer = NULL;
- }
-
- return OK;
-}
-
-sp<MetaData> OMXCodec::getFormat() {
- Mutex::Autolock autoLock(mLock);
-
- return mOutputFormat;
-}
-
-status_t OMXCodec::read(
- MediaBuffer **buffer, const ReadOptions *options) {
- status_t err = OK;
- *buffer = NULL;
-
- Mutex::Autolock autoLock(mLock);
-
- if (mState != EXECUTING && mState != RECONFIGURING) {
- return UNKNOWN_ERROR;
- }
-
- bool seeking = false;
- int64_t seekTimeUs;
- ReadOptions::SeekMode seekMode;
- if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
- seeking = true;
- }
-
- if (mInitialBufferSubmit) {
- mInitialBufferSubmit = false;
-
- if (seeking) {
- CHECK(seekTimeUs >= 0);
- mSeekTimeUs = seekTimeUs;
- mSeekMode = seekMode;
-
- // There's no reason to trigger the code below, there's
- // nothing to flush yet.
- seeking = false;
- mPaused = false;
- }
-
- drainInputBuffers();
-
- if (mState == EXECUTING) {
- // Otherwise mState == RECONFIGURING and this code will trigger
- // after the output port is reenabled.
- fillOutputBuffers();
- }
- }
-
- if (seeking) {
- while (mState == RECONFIGURING) {
- if ((err = waitForBufferFilled_l()) != OK) {
- return err;
- }
- }
-
- if (mState != EXECUTING) {
- return UNKNOWN_ERROR;
- }
-
- CODEC_LOGV("seeking to %" PRId64 " us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
-
- mSignalledEOS = false;
-
- CHECK(seekTimeUs >= 0);
- mSeekTimeUs = seekTimeUs;
- mSeekMode = seekMode;
-
- mFilledBuffers.clear();
-
- CHECK_EQ((int)mState, (int)EXECUTING);
-
- bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
- bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
-
- if (emulateInputFlushCompletion) {
- onCmdComplete(OMX_CommandFlush, kPortIndexInput);
- }
-
- if (emulateOutputFlushCompletion) {
- onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
- }
-
- while (mSeekTimeUs >= 0) {
- if ((err = waitForBufferFilled_l()) != OK) {
- return err;
- }
- }
- }
-
- while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
- if ((err = waitForBufferFilled_l()) != OK) {
- return err;
- }
- }
-
- if (mState == ERROR) {
- return UNKNOWN_ERROR;
- }
-
- if (mFilledBuffers.empty()) {
- return mSignalledEOS ? mFinalStatus : ERROR_END_OF_STREAM;
- }
-
- if (mOutputPortSettingsHaveChanged) {
- mOutputPortSettingsHaveChanged = false;
-
- return INFO_FORMAT_CHANGED;
- }
-
- size_t index = *mFilledBuffers.begin();
- mFilledBuffers.erase(mFilledBuffers.begin());
-
- BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
- CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);
- info->mStatus = OWNED_BY_CLIENT;
-
- info->mMediaBuffer->add_ref();
- if (mSkipCutBuffer != NULL) {
- mSkipCutBuffer->submit(info->mMediaBuffer);
- }
- *buffer = info->mMediaBuffer;
-
- return OK;
-}
-
-void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
- Mutex::Autolock autoLock(mLock);
-
- Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
- for (size_t i = 0; i < buffers->size(); ++i) {
- BufferInfo *info = &buffers->editItemAt(i);
-
- if (info->mMediaBuffer == buffer) {
- CHECK_EQ((int)mPortStatus[kPortIndexOutput], (int)ENABLED);
- CHECK_EQ((int)info->mStatus, (int)OWNED_BY_CLIENT);
-
- info->mStatus = OWNED_BY_US;
-
- if (buffer->graphicBuffer() == 0) {
- fillOutputBuffer(info);
- } else {
- sp<MetaData> metaData = info->mMediaBuffer->meta_data();
- int32_t rendered = 0;
- if (!metaData->findInt32(kKeyRendered, &rendered)) {
- rendered = 0;
- }
- if (!rendered) {
- status_t err = cancelBufferToNativeWindow(info);
- if (err < 0) {
- return;
- }
- }
-
- info->mStatus = OWNED_BY_NATIVE_WINDOW;
-
- // Dequeue the next buffer from the native window.
- BufferInfo *nextBufInfo = dequeueBufferFromNativeWindow();
- if (nextBufInfo == 0) {
- return;
- }
-
- // Give the buffer to the OMX node to fill.
- fillOutputBuffer(nextBufInfo);
- }
- return;
- }
- }
-
- CHECK(!"should not be here.");
-}
-
-void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
- def.nPortIndex = portIndex;
-
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
-
- printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
-
- CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
- || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
-
- printf(" nBufferCountActual = %" PRIu32 "\n", def.nBufferCountActual);
- printf(" nBufferCountMin = %" PRIu32 "\n", def.nBufferCountMin);
- printf(" nBufferSize = %" PRIu32 "\n", def.nBufferSize);
-
- switch (def.eDomain) {
- case OMX_PortDomainImage:
- {
- const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
-
- printf("\n");
- printf(" // Image\n");
- printf(" nFrameWidth = %" PRIu32 "\n", imageDef->nFrameWidth);
- printf(" nFrameHeight = %" PRIu32 "\n", imageDef->nFrameHeight);
- printf(" nStride = %" PRIu32 "\n", imageDef->nStride);
-
- printf(" eCompressionFormat = %s\n",
- asString(imageDef->eCompressionFormat));
-
- printf(" eColorFormat = %s\n",
- asString(imageDef->eColorFormat));
-
- break;
- }
-
- case OMX_PortDomainVideo:
- {
- OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
-
- printf("\n");
- printf(" // Video\n");
- printf(" nFrameWidth = %" PRIu32 "\n", videoDef->nFrameWidth);
- printf(" nFrameHeight = %" PRIu32 "\n", videoDef->nFrameHeight);
- printf(" nStride = %" PRIu32 "\n", videoDef->nStride);
-
- printf(" eCompressionFormat = %s\n",
- asString(videoDef->eCompressionFormat));
-
- printf(" eColorFormat = %s\n",
- asString(videoDef->eColorFormat));
-
- break;
- }
-
- case OMX_PortDomainAudio:
- {
- OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
-
- printf("\n");
- printf(" // Audio\n");
- printf(" eEncoding = %s\n",
- asString(audioDef->eEncoding));
-
- if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
- OMX_AUDIO_PARAM_PCMMODETYPE params;
- InitOMXParams(¶ms);
- params.nPortIndex = portIndex;
-
- err = mOMX->getParameter(
- mNode, OMX_IndexParamAudioPcm, ¶ms, sizeof(params));
- CHECK_EQ(err, (status_t)OK);
-
- printf(" nSamplingRate = %" PRIu32 "\n", params.nSamplingRate);
- printf(" nChannels = %" PRIu32 "\n", params.nChannels);
- printf(" bInterleaved = %d\n", params.bInterleaved);
- printf(" nBitPerSample = %" PRIu32 "\n", params.nBitPerSample);
-
- printf(" eNumData = %s\n",
- params.eNumData == OMX_NumericalDataSigned
- ? "signed" : "unsigned");
-
- printf(" ePCMMode = %s\n", asString(params.ePCMMode));
- } else if (audioDef->eEncoding == OMX_AUDIO_CodingAMR) {
- OMX_AUDIO_PARAM_AMRTYPE amr;
- InitOMXParams(&amr);
- amr.nPortIndex = portIndex;
-
- err = mOMX->getParameter(
- mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
- CHECK_EQ(err, (status_t)OK);
-
- printf(" nChannels = %" PRIu32 "\n", amr.nChannels);
- printf(" eAMRBandMode = %s\n",
- asString(amr.eAMRBandMode));
- printf(" eAMRFrameFormat = %s\n",
- asString(amr.eAMRFrameFormat));
- }
-
- break;
- }
-
- default:
- {
- printf(" // Unknown\n");
- break;
- }
- }
-
- printf("}\n");
-}
-
-status_t OMXCodec::initNativeWindow() {
- // Enable use of a GraphicBuffer as the output for this node. This must
- // happen before getting the IndexParamPortDefinition parameter because it
- // will affect the pixel format that the node reports.
- status_t err = mOMX->enableGraphicBuffers(mNode, kPortIndexOutput, OMX_TRUE);
- if (err != 0) {
- return err;
- }
-
- return OK;
-}
-
-void OMXCodec::initNativeWindowCrop() {
- int32_t left, top, right, bottom;
-
- CHECK(mOutputFormat->findRect(
- kKeyCropRect,
- &left, &top, &right, &bottom));
-
- android_native_rect_t crop;
- crop.left = left;
- crop.top = top;
- crop.right = right + 1;
- crop.bottom = bottom + 1;
-
- // We'll ignore any errors here, if the surface is
- // already invalid, we'll know soon enough.
- native_window_set_crop(mNativeWindow.get(), &crop);
-}
-
-void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
- mOutputFormat = new MetaData;
- mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
- if (mIsEncoder) {
- int32_t timeScale;
- if (inputFormat->findInt32(kKeyTimeScale, &timeScale)) {
- mOutputFormat->setInt32(kKeyTimeScale, timeScale);
- }
- }
-
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
- def.nPortIndex = kPortIndexOutput;
-
- status_t err = mOMX->getParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
-
- switch (def.eDomain) {
- case OMX_PortDomainImage:
- {
- OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
- CHECK_EQ((int)imageDef->eCompressionFormat,
- (int)OMX_IMAGE_CodingUnused);
-
- mOutputFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
- mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
- mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
- mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
- break;
- }
-
- case OMX_PortDomainAudio:
- {
- OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
-
- if (audio_def->eEncoding == OMX_AUDIO_CodingPCM) {
- OMX_AUDIO_PARAM_PCMMODETYPE params;
- InitOMXParams(¶ms);
- params.nPortIndex = kPortIndexOutput;
-
- err = mOMX->getParameter(
- mNode, OMX_IndexParamAudioPcm, ¶ms, sizeof(params));
- CHECK_EQ(err, (status_t)OK);
-
- CHECK_EQ((int)params.eNumData, (int)OMX_NumericalDataSigned);
- CHECK_EQ(params.nBitPerSample, 16u);
- CHECK_EQ((int)params.ePCMMode, (int)OMX_AUDIO_PCMModeLinear);
-
- int32_t numChannels, sampleRate;
- inputFormat->findInt32(kKeyChannelCount, &numChannels);
- inputFormat->findInt32(kKeySampleRate, &sampleRate);
-
- if ((OMX_U32)numChannels != params.nChannels) {
- ALOGV("Codec outputs a different number of channels than "
- "the input stream contains (contains %d channels, "
- "codec outputs %u channels).",
- numChannels, params.nChannels);
- }
-
- if (sampleRate != (int32_t)params.nSamplingRate) {
- ALOGV("Codec outputs at different sampling rate than "
- "what the input stream contains (contains data at "
- "%d Hz, codec outputs %u Hz)",
- sampleRate, params.nSamplingRate);
- }
-
- mOutputFormat->setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-
- // Use the codec-advertised number of channels, as some
- // codecs appear to output stereo even if the input data is
- // mono. If we know the codec lies about this information,
- // use the actual number of channels instead.
- mOutputFormat->setInt32(
- kKeyChannelCount,
- (mQuirks & kDecoderLiesAboutNumberOfChannels)
- ? numChannels : params.nChannels);
-
- mOutputFormat->setInt32(kKeySampleRate, params.nSamplingRate);
- } else if (audio_def->eEncoding == OMX_AUDIO_CodingAMR) {
- OMX_AUDIO_PARAM_AMRTYPE amr;
- InitOMXParams(&amr);
- amr.nPortIndex = kPortIndexOutput;
-
- err = mOMX->getParameter(
- mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
- CHECK_EQ(err, (status_t)OK);
-
- CHECK_EQ(amr.nChannels, 1u);
- mOutputFormat->setInt32(kKeyChannelCount, 1);
-
- if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeNB0
- && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeNB7) {
- mOutputFormat->setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
- mOutputFormat->setInt32(kKeySampleRate, 8000);
- } else if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeWB0
- && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeWB8) {
- mOutputFormat->setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
- mOutputFormat->setInt32(kKeySampleRate, 16000);
- } else {
- CHECK(!"Unknown AMR band mode.");
- }
- } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
- mOutputFormat->setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
- int32_t numChannels, sampleRate, bitRate;
- inputFormat->findInt32(kKeyChannelCount, &numChannels);
- inputFormat->findInt32(kKeySampleRate, &sampleRate);
- inputFormat->findInt32(kKeyBitRate, &bitRate);
- mOutputFormat->setInt32(kKeyChannelCount, numChannels);
- mOutputFormat->setInt32(kKeySampleRate, sampleRate);
- mOutputFormat->setInt32(kKeyBitRate, bitRate);
- } else if (audio_def->eEncoding ==
- (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidAC3) {
- mOutputFormat->setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3);
- int32_t numChannels, sampleRate, bitRate;
- inputFormat->findInt32(kKeyChannelCount, &numChannels);
- inputFormat->findInt32(kKeySampleRate, &sampleRate);
- inputFormat->findInt32(kKeyBitRate, &bitRate);
- mOutputFormat->setInt32(kKeyChannelCount, numChannels);
- mOutputFormat->setInt32(kKeySampleRate, sampleRate);
- mOutputFormat->setInt32(kKeyBitRate, bitRate);
- } else {
- CHECK(!"Should not be here. Unknown audio encoding.");
- }
- break;
- }
-
- case OMX_PortDomainVideo:
- {
- OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
-
- if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
- mOutputFormat->setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
- } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
- mOutputFormat->setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
- } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
- mOutputFormat->setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
- } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
- mOutputFormat->setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
- } else {
- CHECK(!"Unknown compression format.");
- }
-
- mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
- mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
- mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
-
- if (!mIsEncoder) {
- OMX_CONFIG_RECTTYPE rect;
- InitOMXParams(&rect);
- rect.nPortIndex = kPortIndexOutput;
- status_t err =
- mOMX->getConfig(
- mNode, OMX_IndexConfigCommonOutputCrop,
- &rect, sizeof(rect));
-
- CODEC_LOGI("video dimensions are %u x %u",
- video_def->nFrameWidth, video_def->nFrameHeight);
-
- if (err == OK) {
- CHECK_GE(rect.nLeft, 0);
- CHECK_GE(rect.nTop, 0);
- CHECK_GE(rect.nWidth, 0u);
- CHECK_GE(rect.nHeight, 0u);
- CHECK_LE(rect.nLeft + rect.nWidth - 1, video_def->nFrameWidth);
- CHECK_LE(rect.nTop + rect.nHeight - 1, video_def->nFrameHeight);
-
- mOutputFormat->setRect(
- kKeyCropRect,
- rect.nLeft,
- rect.nTop,
- rect.nLeft + rect.nWidth - 1,
- rect.nTop + rect.nHeight - 1);
-
- CODEC_LOGI("Crop rect is %u x %u @ (%d, %d)",
- rect.nWidth, rect.nHeight, rect.nLeft, rect.nTop);
- } else {
- mOutputFormat->setRect(
- kKeyCropRect,
- 0, 0,
- video_def->nFrameWidth - 1,
- video_def->nFrameHeight - 1);
- }
-
- if (mNativeWindow != NULL) {
- initNativeWindowCrop();
- }
- }
- break;
- }
-
- default:
- {
- CHECK(!"should not be here, neither audio nor video.");
- break;
- }
- }
-
- // If the input format contains rotation information, flag the output
- // format accordingly.
-
- int32_t rotationDegrees;
- if (mSource->getFormat()->findInt32(kKeyRotation, &rotationDegrees)) {
- mOutputFormat->setInt32(kKeyRotation, rotationDegrees);
- }
-}
-
-status_t OMXCodec::pause() {
- Mutex::Autolock autoLock(mLock);
-
- mPaused = true;
-
- return OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-status_t QueryCodecs(
- const sp<IOMX> &omx,
- const char *mime, bool queryDecoders, bool hwCodecOnly,
- Vector<CodecCapabilities> *results) {
- Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs;
- results->clear();
-
- OMXCodec::findMatchingCodecs(mime,
- !queryDecoders /*createEncoder*/,
- NULL /*matchComponentName*/,
- hwCodecOnly ? OMXCodec::kHardwareCodecsOnly : 0 /*flags*/,
- &matchingCodecs);
-
- for (size_t c = 0; c < matchingCodecs.size(); c++) {
- const char *componentName = matchingCodecs.itemAt(c).mName.string();
-
- results->push();
- CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
-
- status_t err =
- QueryCodec(omx, componentName, mime, !queryDecoders, caps);
-
- if (err != OK) {
- results->removeAt(results->size() - 1);
- }
- }
-
- return OK;
-}
-
-status_t QueryCodec(
- const sp<IOMX> &omx,
- const char *componentName, const char *mime,
- bool isEncoder,
- CodecCapabilities *caps) {
- bool isVideo = !strncasecmp(mime, "video/", 6);
-
- sp<OMXCodecObserver> observer = new OMXCodecObserver;
- IOMX::node_id node;
- status_t err = omx->allocateNode(componentName, observer, &node);
-
- if (err != OK) {
- return err;
- }
-
- OMXCodec::setComponentRole(omx, node, isEncoder, mime);
-
- caps->mFlags = 0;
- caps->mComponentName = componentName;
-
- // NOTE: OMX does not provide a way to query AAC profile support
- if (isVideo) {
- OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
- InitOMXParams(¶m);
-
- param.nPortIndex = !isEncoder ? 0 : 1;
-
- for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
- err = omx->getParameter(
- node, OMX_IndexParamVideoProfileLevelQuerySupported,
- ¶m, sizeof(param));
-
- if (err != OK) {
- break;
- }
-
- CodecProfileLevel profileLevel;
- profileLevel.mProfile = param.eProfile;
- profileLevel.mLevel = param.eLevel;
-
- caps->mProfileLevels.push(profileLevel);
- }
-
- // Color format query
- // return colors in the order reported by the OMX component
- // prefix "flexible" standard ones with the flexible equivalent
- OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
- InitOMXParams(&portFormat);
- portFormat.nPortIndex = !isEncoder ? 1 : 0;
- for (portFormat.nIndex = 0;; ++portFormat.nIndex) {
- err = omx->getParameter(
- node, OMX_IndexParamVideoPortFormat,
- &portFormat, sizeof(portFormat));
- if (err != OK) {
- break;
- }
-
- OMX_U32 flexibleEquivalent;
- if (ACodec::isFlexibleColorFormat(
- omx, node, portFormat.eColorFormat, false /* usingNativeWindow */,
- &flexibleEquivalent)) {
- bool marked = false;
- for (size_t i = 0; i < caps->mColorFormats.size(); i++) {
- if (caps->mColorFormats.itemAt(i) == flexibleEquivalent) {
- marked = true;
- break;
- }
- }
- if (!marked) {
- caps->mColorFormats.push(flexibleEquivalent);
- }
- }
- caps->mColorFormats.push(portFormat.eColorFormat);
- }
- }
-
- if (isVideo && !isEncoder) {
- if (omx->storeMetaDataInBuffers(
- node, 1 /* port index */, OMX_TRUE) == OK ||
- omx->prepareForAdaptivePlayback(
- node, 1 /* port index */, OMX_TRUE,
- 1280 /* width */, 720 /* height */) == OK) {
- caps->mFlags |= CodecCapabilities::kFlagSupportsAdaptivePlayback;
- }
- }
-
- CHECK_EQ(omx->freeNode(node), (status_t)OK);
-
- return OK;
-}
-
-status_t QueryCodecs(
- const sp<IOMX> &omx,
- const char *mimeType, bool queryDecoders,
- Vector<CodecCapabilities> *results) {
- return QueryCodecs(omx, mimeType, queryDecoders, false /*hwCodecOnly*/, results);
-}
-
-// These are supposed be equivalent to the logic in
-// "audio_channel_out_mask_from_count".
-status_t getOMXChannelMapping(size_t numChannels, OMX_AUDIO_CHANNELTYPE map[]) {
- switch (numChannels) {
- case 1:
- map[0] = OMX_AUDIO_ChannelCF;
- break;
- case 2:
- map[0] = OMX_AUDIO_ChannelLF;
- map[1] = OMX_AUDIO_ChannelRF;
- break;
- case 3:
- map[0] = OMX_AUDIO_ChannelLF;
- map[1] = OMX_AUDIO_ChannelRF;
- map[2] = OMX_AUDIO_ChannelCF;
- break;
- case 4:
- map[0] = OMX_AUDIO_ChannelLF;
- map[1] = OMX_AUDIO_ChannelRF;
- map[2] = OMX_AUDIO_ChannelLR;
- map[3] = OMX_AUDIO_ChannelRR;
- break;
- case 5:
- map[0] = OMX_AUDIO_ChannelLF;
- map[1] = OMX_AUDIO_ChannelRF;
- map[2] = OMX_AUDIO_ChannelCF;
- map[3] = OMX_AUDIO_ChannelLR;
- map[4] = OMX_AUDIO_ChannelRR;
- break;
- case 6:
- map[0] = OMX_AUDIO_ChannelLF;
- map[1] = OMX_AUDIO_ChannelRF;
- map[2] = OMX_AUDIO_ChannelCF;
- map[3] = OMX_AUDIO_ChannelLFE;
- map[4] = OMX_AUDIO_ChannelLR;
- map[5] = OMX_AUDIO_ChannelRR;
- break;
- case 7:
- map[0] = OMX_AUDIO_ChannelLF;
- map[1] = OMX_AUDIO_ChannelRF;
- map[2] = OMX_AUDIO_ChannelCF;
- map[3] = OMX_AUDIO_ChannelLFE;
- map[4] = OMX_AUDIO_ChannelLR;
- map[5] = OMX_AUDIO_ChannelRR;
- map[6] = OMX_AUDIO_ChannelCS;
- break;
- case 8:
- map[0] = OMX_AUDIO_ChannelLF;
- map[1] = OMX_AUDIO_ChannelRF;
- map[2] = OMX_AUDIO_ChannelCF;
- map[3] = OMX_AUDIO_ChannelLFE;
- map[4] = OMX_AUDIO_ChannelLR;
- map[5] = OMX_AUDIO_ChannelRR;
- map[6] = OMX_AUDIO_ChannelLS;
- map[7] = OMX_AUDIO_ChannelRS;
- break;
- default:
- return -EINVAL;
- }
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 578171f..9162f80 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -179,6 +179,9 @@
protected:
virtual int64_t getTimeUsOfGranule(uint64_t granulePos) const {
+ if (granulePos > INT64_MAX / 1000000ll) {
+ return INT64_MAX;
+ }
return granulePos * 1000000ll / mVi.rate;
}
@@ -771,8 +774,13 @@
return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
}
- mCurrentPageSamples =
- mCurrentPage.mGranulePosition - mPrevGranulePosition;
+ // Prevent a harmless unsigned integer overflow by clamping to 0
+ if (mCurrentPage.mGranulePosition >= mPrevGranulePosition) {
+ mCurrentPageSamples =
+ mCurrentPage.mGranulePosition - mPrevGranulePosition;
+ } else {
+ mCurrentPageSamples = 0;
+ }
mFirstPacketInPage = true;
mPrevGranulePosition = mCurrentPage.mGranulePosition;
@@ -917,6 +925,9 @@
if (granulePos > mCodecDelay) {
pcmSamplePosition = granulePos - mCodecDelay;
}
+ if (pcmSamplePosition > INT64_MAX / 1000000ll) {
+ return INT64_MAX;
+ }
return pcmSamplePosition * 1000000ll / kOpusSampleRate;
}
@@ -954,7 +965,7 @@
mMeta->setInt32(kKeyChannelCount, mChannelCount);
mMeta->setInt64(kKeyOpusSeekPreRoll /* ns */, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
mMeta->setInt64(kKeyOpusCodecDelay /* ns */,
- mCodecDelay /* sample/s */ * 1000000000 / kOpusSampleRate);
+ mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate);
return OK;
}
@@ -1254,17 +1265,17 @@
return;
}
- descLen = U32_AT(&flac[8 + typeLen]);
+ if (flacSize < 32 || flacSize - 32 < typeLen) {
+ return;
+ }
- if (flacSize < 32 ||
- flacSize - 32 < typeLen ||
- flacSize - 32 - typeLen < descLen) {
+ descLen = U32_AT(&flac[8 + typeLen]);
+ if (flacSize - 32 - typeLen < descLen) {
return;
}
dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
-
// we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
if (flacSize - 32 - typeLen - descLen < dataLen) {
return;
@@ -1314,7 +1325,7 @@
return mInitCheck != OK ? 0 : 1;
}
-sp<MediaSource> OggExtractor::getTrack(size_t index) {
+sp<IMediaSource> OggExtractor::getTrack(size_t index) {
if (index >= 1) {
return NULL;
}
diff --git a/media/libstagefright/ProcessInfo.cpp b/media/libstagefright/ProcessInfo.cpp
index b4172b3..353f108 100644
--- a/media/libstagefright/ProcessInfo.cpp
+++ b/media/libstagefright/ProcessInfo.cpp
@@ -32,19 +32,23 @@
sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);
size_t length = 1;
- int32_t states;
- status_t err = service->getProcessStatesFromPids(length, &pid, &states);
+ int32_t state;
+ static const int32_t INVALID_ADJ = -10000;
+ static const int32_t NATIVE_ADJ = -1000;
+ int32_t score = INVALID_ADJ;
+ status_t err = service->getProcessStatesAndOomScoresFromPids(length, &pid, &state, &score);
if (err != OK) {
- ALOGE("getProcessStatesFromPids failed");
+ ALOGE("getProcessStatesAndOomScoresFromPids failed");
return false;
}
- ALOGV("pid %d states %d", pid, states);
- if (states < 0) {
+ ALOGV("pid %d state %d score %d", pid, state, score);
+ if (score <= NATIVE_ADJ) {
+ ALOGE("pid %d invalid OOM adjustments value %d", pid, score);
return false;
}
- // Use process state as the priority. Lower the value, higher the priority.
- *priority = states;
+ // Use OOM adjustments value as the priority. Lower the value, higher the priority.
+ *priority = score;
return true;
}
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index 2748349..7bf3437 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -84,6 +84,11 @@
CHECK(sampleIndex < mStopChunkSampleIndex);
+ if (mSamplesPerChunk == 0) {
+ ALOGE("b/22802344");
+ return ERROR_MALFORMED;
+ }
+
uint32_t chunk =
(sampleIndex - mFirstChunkSampleIndex) / mSamplesPerChunk
+ mFirstChunk;
@@ -166,6 +171,13 @@
if (mSampleToChunkIndex + 1 < mTable->mNumSampleToChunkOffsets) {
mStopChunk = entry[1].startChunk;
+ if (mStopChunk < mFirstChunk ||
+ (mStopChunk - mFirstChunk) > UINT32_MAX / mSamplesPerChunk ||
+ ((mStopChunk - mFirstChunk) * mSamplesPerChunk >
+ UINT32_MAX - mFirstChunkSampleIndex)) {
+
+ return ERROR_OUT_OF_RANGE;
+ }
mStopChunkSampleIndex =
mFirstChunkSampleIndex
+ (mStopChunk - mFirstChunk) * mSamplesPerChunk;
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 97dff43..39459e2 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -194,11 +194,11 @@
mNumChunkOffsets = U32_AT(&header[4]);
if (mChunkOffsetType == kChunkOffsetType32) {
- if (data_size < 8 + mNumChunkOffsets * 4) {
+ if ((data_size - 8) / 4 < mNumChunkOffsets) {
return ERROR_MALFORMED;
}
} else {
- if (data_size < 8 + mNumChunkOffsets * 8) {
+ if ((data_size - 8) / 8 < mNumChunkOffsets) {
return ERROR_MALFORMED;
}
}
@@ -231,7 +231,7 @@
mNumSampleToChunkOffsets = U32_AT(&header[4]);
- if (data_size < 8 + mNumSampleToChunkOffsets * 12) {
+ if ((data_size - 8) / 12 < mNumSampleToChunkOffsets) {
return ERROR_MALFORMED;
}
@@ -245,13 +245,21 @@
for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
uint8_t buffer[12];
+
+ if ((off64_t)(SIZE_MAX - 8 - (i * 12)) < mSampleToChunkOffset) {
+ return ERROR_MALFORMED;
+ }
+
if (mDataSource->readAt(
mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
!= (ssize_t)sizeof(buffer)) {
return ERROR_IO;
}
-
- CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec.
+ // chunk index is 1 based in the spec.
+ if (U32_AT(buffer) < 1) {
+ ALOGE("b/23534160");
+ return ERROR_OUT_OF_RANGE;
+ }
// We want the chunk index to be 0-based.
mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
@@ -386,7 +394,7 @@
size_t numEntries = U32_AT(&header[4]);
- if (data_size != (numEntries + 1) * 8) {
+ if (((SIZE_MAX / 8) - 1 < numEntries) || (data_size != (numEntries + 1) * 8)) {
return ERROR_MALFORMED;
}
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
new file mode 100644
index 0000000..1b44a00
--- /dev/null
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -0,0 +1,362 @@
+/*
+ * 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.
+ */
+
+#include <gui/Surface.h>
+
+#include <media/ICrypto.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/SimpleDecodingSource.h>
+#include <media/stagefright/Utils.h>
+
+using namespace android;
+
+const int64_t kTimeoutWaitForOutputUs = 500000; // 0.5 seconds
+const int64_t kTimeoutWaitForInputUs = 5000; // 5 milliseconds
+
+//static
+sp<SimpleDecodingSource> SimpleDecodingSource::Create(
+ const sp<IMediaSource> &source, uint32_t flags, const sp<ANativeWindow> &nativeWindow,
+ const char *desiredCodec) {
+ sp<Surface> surface = static_cast<Surface*>(nativeWindow.get());
+ const char *mime = NULL;
+ sp<MetaData> meta = source->getFormat();
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ sp<AMessage> format = new AMessage;
+ convertMetaDataToMessage(source->getFormat(), &format);
+
+ Vector<AString> matchingCodecs;
+ MediaCodecList::findMatchingCodecs(
+ mime, false /* encoder */, flags, &matchingCodecs);
+
+ sp<ALooper> looper = new ALooper;
+ looper->setName("stagefright");
+ looper->start();
+
+ sp<MediaCodec> codec;
+
+ for (size_t i = 0; i < matchingCodecs.size(); ++i) {
+ const AString &componentName = matchingCodecs[i];
+ if (desiredCodec != NULL && componentName.compare(desiredCodec)) {
+ continue;
+ }
+
+ ALOGV("Attempting to allocate codec '%s'", componentName.c_str());
+
+ codec = MediaCodec::CreateByComponentName(looper, componentName);
+ if (codec != NULL) {
+ ALOGI("Successfully allocated codec '%s'", componentName.c_str());
+
+ status_t err = codec->configure(format, surface, NULL /* crypto */, 0 /* flags */);
+ if (err == OK) {
+ err = codec->getOutputFormat(&format);
+ }
+ if (err == OK) {
+ return new SimpleDecodingSource(codec, source, looper, surface != NULL, format);
+ }
+
+ ALOGD("Failed to configure codec '%s'", componentName.c_str());
+ codec->release();
+ codec = NULL;
+ }
+ }
+
+ looper->stop();
+ ALOGE("No matching decoder! (mime: %s)", mime);
+ return NULL;
+}
+
+SimpleDecodingSource::SimpleDecodingSource(
+ const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
+ bool usingSurface, const sp<AMessage> &format)
+ : mCodec(codec),
+ mSource(source),
+ mLooper(looper),
+ mUsingSurface(usingSurface),
+ mProtectedState(format) {
+ mCodec->getName(&mComponentName);
+}
+
+SimpleDecodingSource::~SimpleDecodingSource() {
+ mCodec->release();
+ mLooper->stop();
+}
+
+status_t SimpleDecodingSource::start(MetaData *params) {
+ (void)params;
+ Mutexed<ProtectedState>::Locked me(mProtectedState);
+ if (me->mState != INIT) {
+ return -EINVAL;
+ }
+ status_t res = mCodec->start();
+ if (res == OK) {
+ res = mSource->start();
+ }
+
+ if (res == OK) {
+ me->mState = STARTED;
+ me->mQueuedInputEOS = false;
+ me->mGotOutputEOS = false;
+ } else {
+ me->mState = ERROR;
+ }
+
+ return res;
+}
+
+status_t SimpleDecodingSource::stop() {
+ Mutexed<ProtectedState>::Locked me(mProtectedState);
+ if (me->mState != STARTED) {
+ return -EINVAL;
+ }
+
+ // wait for any pending reads to complete
+ me->mState = STOPPING;
+ while (me->mReading) {
+ me.waitForCondition(me->mReadCondition);
+ }
+
+ status_t res1 = mCodec->stop();
+ if (res1 != OK) {
+ mCodec->release();
+ }
+ status_t res2 = mSource->stop();
+ if (res1 == OK && res2 == OK) {
+ me->mState = STOPPED;
+ } else {
+ me->mState = ERROR;
+ }
+ return res1 != OK ? res1 : res2;
+}
+
+sp<MetaData> SimpleDecodingSource::getFormat() {
+ Mutexed<ProtectedState>::Locked me(mProtectedState);
+ if (me->mState == STARTED || me->mState == INIT) {
+ sp<MetaData> meta = new MetaData();
+ convertMessageToMetaData(me->mFormat, meta);
+ return meta;
+ }
+ return NULL;
+}
+
+SimpleDecodingSource::ProtectedState::ProtectedState(const sp<AMessage> &format)
+ : mReading(false),
+ mFormat(format),
+ mState(INIT),
+ mQueuedInputEOS(false),
+ mGotOutputEOS(false) {
+}
+
+status_t SimpleDecodingSource::read(
+ MediaBuffer **buffer, const ReadOptions *options) {
+ *buffer = NULL;
+
+ Mutexed<ProtectedState>::Locked me(mProtectedState);
+ if (me->mState != STARTED) {
+ return ERROR_END_OF_STREAM;
+ }
+ me->mReading = true;
+
+ status_t res = doRead(me, buffer, options);
+
+ me.lock();
+ me->mReading = false;
+ if (me->mState != STARTED) {
+ me->mReadCondition.signal();
+ }
+
+ return res;
+}
+
+status_t SimpleDecodingSource::doRead(
+ Mutexed<ProtectedState>::Locked &me, MediaBuffer **buffer, const ReadOptions *options) {
+ // |me| is always locked on entry, but is allowed to be unlocked on exit
+ CHECK_EQ(me->mState, STARTED);
+
+ size_t out_ix, in_ix, out_offset, out_size;
+ int64_t out_pts;
+ uint32_t out_flags;
+ status_t res;
+
+ // flush codec on seek
+ IMediaSource::ReadOptions::SeekMode mode;
+ if (options != NULL && options->getSeekTo(&out_pts, &mode)) {
+ me->mQueuedInputEOS = false;
+ me->mGotOutputEOS = false;
+ mCodec->flush();
+ }
+
+ if (me->mGotOutputEOS) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ for (int retries = 0; ++retries; ) {
+ // If we fill all available input buffers, we should expect that
+ // the codec produces at least one output buffer. Also, the codec
+ // should produce an output buffer in at most 1 seconds. Retry a
+ // few times nonetheless.
+ while (!me->mQueuedInputEOS) {
+ // allow some time to get input buffer after flush
+ res = mCodec->dequeueInputBuffer(&in_ix, kTimeoutWaitForInputUs);
+ if (res == -EAGAIN) {
+ // no available input buffers
+ break;
+ }
+
+ sp<ABuffer> in_buffer;
+ if (res == OK) {
+ res = mCodec->getInputBuffer(in_ix, &in_buffer);
+ }
+
+ if (res != OK || in_buffer == NULL) {
+ ALOGW("[%s] could not get input buffer #%zu",
+ mComponentName.c_str(), in_ix);
+ me->mState = ERROR;
+ return UNKNOWN_ERROR;
+ }
+
+ MediaBuffer *in_buf;
+ while (true) {
+ in_buf = NULL;
+ me.unlock();
+ res = mSource->read(&in_buf, options);
+ me.lock();
+ if (res != OK || me->mState != STARTED) {
+ if (in_buf != NULL) {
+ in_buf->release();
+ in_buf = NULL;
+ }
+
+ // queue EOS
+ me->mQueuedInputEOS = true;
+ if (mCodec->queueInputBuffer(
+ in_ix, 0 /* offset */, 0 /* size */,
+ 0 /* pts */, MediaCodec::BUFFER_FLAG_EOS) != OK) {
+ ALOGI("[%s] failed to queue input EOS", mComponentName.c_str());
+ me->mState = ERROR;
+ return UNKNOWN_ERROR;
+ }
+
+ // don't stop on EOS, but report error or EOS on stop
+ if (res != ERROR_END_OF_STREAM) {
+ me->mState = ERROR;
+ return res;
+ }
+ if (me->mState != STARTED) {
+ return ERROR_END_OF_STREAM;
+ }
+ break;
+ }
+ if (in_buf == NULL) { // should not happen
+ continue;
+ } else if (in_buf->range_length() != 0) {
+ break;
+ }
+ in_buf->release();
+ }
+
+ if (in_buf != NULL) {
+ int64_t timestampUs = 0;
+ CHECK(in_buf->meta_data()->findInt64(kKeyTime, ×tampUs));
+ if (in_buf->range_length() > in_buffer->capacity()) {
+ ALOGW("'%s' received %zu input bytes for buffer of size %zu",
+ mComponentName.c_str(),
+ in_buf->range_length(), in_buffer->capacity());
+ }
+ memcpy(in_buffer->base(), (uint8_t *)in_buf->data() + in_buf->range_offset(),
+ min(in_buf->range_length(), in_buffer->capacity()));
+
+ res = mCodec->queueInputBuffer(
+ in_ix, 0 /* offset */, in_buf->range_length(),
+ timestampUs, 0 /* flags */);
+ if (res != OK) {
+ ALOGI("[%s] failed to queue input buffer #%zu", mComponentName.c_str(), in_ix);
+ me->mState = ERROR;
+ }
+ in_buf->release();
+ }
+ }
+
+ me.unlock();
+ res = mCodec->dequeueOutputBuffer(
+ &out_ix, &out_offset, &out_size, &out_pts,
+ &out_flags, kTimeoutWaitForOutputUs /* timeoutUs */);
+ me.lock();
+ // abort read on stop
+ if (me->mState != STARTED) {
+ if (res == OK) {
+ mCodec->releaseOutputBuffer(out_ix);
+ }
+ return ERROR_END_OF_STREAM;
+ }
+
+ if (res == -EAGAIN) {
+ ALOGD("[%s] did not produce an output buffer. retry count: %d",
+ mComponentName.c_str(), retries);
+ continue;
+ } else if (res == INFO_FORMAT_CHANGED) {
+ if (mCodec->getOutputFormat(&me->mFormat) != OK) {
+ me->mState = ERROR;
+ res = UNKNOWN_ERROR;
+ }
+ return res;
+ } else if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
+ ALOGV("output buffers changed");
+ continue;
+ } else if (res != OK) {
+ me->mState = ERROR;
+ return res;
+ }
+
+ sp<ABuffer> out_buffer;
+ res = mCodec->getOutputBuffer(out_ix, &out_buffer);
+ if (res != OK) {
+ ALOGW("[%s] could not get output buffer #%zu",
+ mComponentName.c_str(), out_ix);
+ me->mState = ERROR;
+ return UNKNOWN_ERROR;
+ }
+ if (out_flags & MediaCodec::BUFFER_FLAG_EOS) {
+ me->mGotOutputEOS = true;
+ // return EOS immediately if last buffer is empty
+ if (out_size == 0) {
+ mCodec->releaseOutputBuffer(out_ix);
+ return ERROR_END_OF_STREAM;
+ }
+ }
+
+ if (mUsingSurface && out_size > 0) {
+ *buffer = new MediaBuffer(0);
+ mCodec->renderOutputBufferAndRelease(out_ix);
+ } else {
+ *buffer = new MediaBuffer(out_size);
+ CHECK_LE(out_buffer->size(), (*buffer)->size());
+ memcpy((*buffer)->data(), out_buffer->data(), out_buffer->size());
+ (*buffer)->meta_data()->setInt64(kKeyTime, out_pts);
+ mCodec->releaseOutputBuffer(out_ix);
+ }
+ return OK;
+ }
+
+ return TIMED_OUT;
+}
diff --git a/media/libstagefright/SkipCutBuffer.cpp b/media/libstagefright/SkipCutBuffer.cpp
index 1da1e5e..d30be88 100644
--- a/media/libstagefright/SkipCutBuffer.cpp
+++ b/media/libstagefright/SkipCutBuffer.cpp
@@ -24,21 +24,32 @@
namespace android {
-SkipCutBuffer::SkipCutBuffer(int32_t skip, int32_t cut) {
+SkipCutBuffer::SkipCutBuffer(size_t skip, size_t cut, size_t num16BitChannels) {
- if (skip < 0 || cut < 0 || cut > 64 * 1024) {
- ALOGW("out of range skip/cut: %d/%d, using passthrough instead", skip, cut);
- skip = 0;
- cut = 0;
+ mWriteHead = 0;
+ mReadHead = 0;
+ mCapacity = 0;
+ mCutBuffer = NULL;
+
+ if (num16BitChannels == 0 || num16BitChannels > INT32_MAX / 2) {
+ ALOGW("# channels out of range: %zu, using passthrough instead", num16BitChannels);
+ return;
}
+ size_t frameSize = num16BitChannels * 2;
+ if (skip > INT32_MAX / frameSize || cut > INT32_MAX / frameSize
+ || cut * frameSize > INT32_MAX - 4096) {
+ ALOGW("out of range skip/cut: %zu/%zu, using passthrough instead",
+ skip, cut);
+ return;
+ }
+ skip *= frameSize;
+ cut *= frameSize;
mFrontPadding = mSkip = skip;
mBackPadding = cut;
- mWriteHead = 0;
- mReadHead = 0;
mCapacity = cut + 4096;
- mCutBuffer = new char[mCapacity];
- ALOGV("skipcutbuffer %d %d %d", skip, cut, mCapacity);
+ mCutBuffer = new (std::nothrow) char[mCapacity];
+ ALOGV("skipcutbuffer %zu %zu %d", skip, cut, mCapacity);
}
SkipCutBuffer::~SkipCutBuffer() {
@@ -46,6 +57,11 @@
}
void SkipCutBuffer::submit(MediaBuffer *buffer) {
+ if (mCutBuffer == NULL) {
+ // passthrough mode
+ return;
+ }
+
int32_t offset = buffer->range_offset();
int32_t buflen = buffer->range_length();
@@ -73,6 +89,11 @@
}
void SkipCutBuffer::submit(const sp<ABuffer>& buffer) {
+ if (mCutBuffer == NULL) {
+ // passthrough mode
+ return;
+ }
+
int32_t offset = buffer->offset();
int32_t buflen = buffer->size();
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index e37e909..45fb785 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -35,11 +35,12 @@
#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/Utils.h>
#include <CharacterEncodingDetector.h>
@@ -55,13 +56,11 @@
ALOGV("StagefrightMetadataRetriever()");
DataSource::RegisterDefaultSniffers();
- CHECK_EQ(mClient.connect(), (status_t)OK);
}
StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
ALOGV("~StagefrightMetadataRetriever()");
clearMetadata();
- mClient.disconnect();
}
status_t StagefrightMetadataRetriever::setDataSource(
@@ -137,9 +136,9 @@
}
static VideoFrame *extractVideoFrame(
- const char *componentName,
+ const AString &componentName,
const sp<MetaData> &trackMeta,
- const sp<MediaSource> &source,
+ const sp<IMediaSource> &source,
int64_t frameTimeUs,
int seekMode) {
@@ -147,6 +146,7 @@
sp<AMessage> videoFormat;
if (convertMetaDataToMessage(trackMeta, &videoFormat) != OK) {
+ ALOGE("b/23680780");
ALOGW("Failed to convert meta data to message");
return NULL;
}
@@ -161,7 +161,7 @@
looper, componentName, &err);
if (decoder.get() == NULL || err != OK) {
- ALOGW("Failed to instantiate decoder [%s]", componentName);
+ ALOGW("Failed to instantiate decoder [%s]", componentName.c_str());
return NULL;
}
@@ -458,7 +458,7 @@
sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
i, MediaExtractor::kIncludeExtensiveMetaData);
- sp<MediaSource> source = mExtractor->getTrack(i);
+ sp<IMediaSource> source = mExtractor->getTrack(i);
if (source.get() == NULL) {
ALOGV("unable to instantiate video track.");
@@ -476,23 +476,22 @@
const char *mime;
CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
- Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs;
- OMXCodec::findMatchingCodecs(
+ Vector<AString> matchingCodecs;
+ MediaCodecList::findMatchingCodecs(
mime,
false, /* encoder */
- NULL, /* matchComponentName */
- OMXCodec::kPreferSoftwareCodecs,
+ MediaCodecList::kPreferSoftwareCodecs,
&matchingCodecs);
for (size_t i = 0; i < matchingCodecs.size(); ++i) {
- const char *componentName = matchingCodecs[i].mName.string();
+ const AString &componentName = matchingCodecs[i];
VideoFrame *frame =
extractVideoFrame(componentName, trackMeta, source, timeUs, option);
if (frame != NULL) {
return frame;
}
- ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName);
+ ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName.c_str());
}
return NULL;
@@ -661,9 +660,12 @@
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
const char *lang;
- trackMeta->findCString(kKeyMediaLanguage, &lang);
- timedTextLang.append(String8(lang));
- timedTextLang.append(String8(":"));
+ if (trackMeta->findCString(kKeyMediaLanguage, &lang)) {
+ timedTextLang.append(String8(lang));
+ timedTextLang.append(String8(":"));
+ } else {
+ ALOGE("No language found for timed text");
+ }
}
}
}
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index e8abf48..e4bf67a 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -308,9 +308,9 @@
// First time seeing the buffer? Added it to the SMS slot
if (item.mGraphicBuffer != NULL) {
- mSlots[item.mBuf].mGraphicBuffer = item.mGraphicBuffer;
+ mSlots[item.mSlot].mGraphicBuffer = item.mGraphicBuffer;
}
- mSlots[item.mBuf].mFrameNumber = item.mFrameNumber;
+ mSlots[item.mSlot].mFrameNumber = item.mFrameNumber;
// check for the timing of this buffer
if (mNumFramesReceived == 0 && !mUseAbsoluteTimestamps) {
@@ -320,7 +320,7 @@
if (item.mTimestamp < mStartTimeNs) {
// This frame predates start of record, discard
mConsumer->releaseBuffer(
- item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY,
+ item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY,
EGL_NO_SYNC_KHR, Fence::NO_FENCE);
continue;
}
@@ -346,13 +346,13 @@
return ERROR_END_OF_STREAM;
}
- mCurrentSlot = item.mBuf;
+ mCurrentSlot = item.mSlot;
// First time seeing the buffer? Added it to the SMS slot
if (item.mGraphicBuffer != NULL) {
- mSlots[item.mBuf].mGraphicBuffer = item.mGraphicBuffer;
+ mSlots[item.mSlot].mGraphicBuffer = item.mGraphicBuffer;
}
- mSlots[item.mBuf].mFrameNumber = item.mFrameNumber;
+ mSlots[item.mSlot].mFrameNumber = item.mFrameNumber;
mCurrentBuffers.push_back(mSlots[mCurrentSlot].mGraphicBuffer);
int64_t prevTimeStamp = mCurrentTimestamp;
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index 6b62e43..9940822 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -55,11 +55,17 @@
return err;
}
+ int consumerUsage = 0;
+ err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage);
+ if (err != NO_ERROR) {
+ ALOGW("failed to get consumer usage bits. ignoring");
+ err = NO_ERROR;
+ }
+
// Make sure to check whether either Stagefright or the video decoder
// requested protected buffers.
if (usage & GRALLOC_USAGE_PROTECTED) {
- // Verify that the ANativeWindow sends images directly to
- // SurfaceFlinger.
+ // Check if the ANativeWindow sends images directly to SurfaceFlinger.
int queuesToNativeWindow = 0;
err = nativeWindow->query(
nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &queuesToNativeWindow);
@@ -67,19 +73,14 @@
ALOGE("error authenticating native window: %s (%d)", strerror(-err), -err);
return err;
}
- if (queuesToNativeWindow != 1) {
+
+ // Check if the ANativeWindow uses hardware protected buffers.
+ if (queuesToNativeWindow != 1 && !(consumerUsage & GRALLOC_USAGE_PROTECTED)) {
ALOGE("native window could not be authenticated");
return PERMISSION_DENIED;
}
}
- int consumerUsage = 0;
- err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage);
- if (err != NO_ERROR) {
- ALOGW("failed to get consumer usage bits. ignoring");
- err = NO_ERROR;
- }
-
int finalUsage = usage | consumerUsage;
ALOGV("gralloc usage: %#x(producer) + %#x(consumer) = %#x", usage, consumerUsage, finalUsage);
err = native_window_set_usage(nativeWindow, finalUsage);
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
deleted file mode 100644
index 7d15220..0000000
--- a/media/libstagefright/TimedEventQueue.cpp
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef __STRICT_ANSI__
-#define __STDINT_LIMITS
-#define __STDC_LIMIT_MACROS
-
-#include <inttypes.h>
-#include <stdint.h>
-#include <sys/prctl.h>
-#include <sys/time.h>
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "TimedEventQueue"
-#include <utils/Log.h>
-#include <utils/threads.h>
-
-#include "include/TimedEventQueue.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <binder/IServiceManager.h>
-#include <powermanager/PowerManager.h>
-#include <binder/IPCThreadState.h>
-#include <utils/CallStack.h>
-
-namespace android {
-
-static int64_t kWakelockMinDelay = 100000ll; // 100ms
-
-TimedEventQueue::TimedEventQueue()
- : mNextEventID(1),
- mRunning(false),
- mStopped(false),
- mDeathRecipient(new PMDeathRecipient(this)),
- mWakeLockCount(0) {
-}
-
-TimedEventQueue::~TimedEventQueue() {
- stop();
- if (mPowerManager != 0) {
- sp<IBinder> binder = IInterface::asBinder(mPowerManager);
- binder->unlinkToDeath(mDeathRecipient);
- }
-}
-
-void TimedEventQueue::start() {
- if (mRunning) {
- return;
- }
-
- mStopped = false;
-
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-
- pthread_create(&mThread, &attr, ThreadWrapper, this);
-
- pthread_attr_destroy(&attr);
-
- mRunning = true;
-}
-
-void TimedEventQueue::stop(bool flush) {
- if (!mRunning) {
- return;
- }
-
- if (flush) {
- postEventToBack(new StopEvent);
- } else {
- postTimedEvent(new StopEvent, INT64_MIN);
- }
-
- void *dummy;
- pthread_join(mThread, &dummy);
-
- // some events may be left in the queue if we did not flush and the wake lock
- // must be released.
- releaseWakeLock_l(true /*force*/);
- mQueue.clear();
-
- mRunning = false;
-}
-
-TimedEventQueue::event_id TimedEventQueue::postEvent(const sp<Event> &event) {
- // Reserve an earlier timeslot an INT64_MIN to be able to post
- // the StopEvent to the absolute head of the queue.
- return postTimedEvent(event, INT64_MIN + 1);
-}
-
-TimedEventQueue::event_id TimedEventQueue::postEventToBack(
- const sp<Event> &event) {
- return postTimedEvent(event, INT64_MAX);
-}
-
-TimedEventQueue::event_id TimedEventQueue::postEventWithDelay(
- const sp<Event> &event, int64_t delay_us) {
- CHECK(delay_us >= 0);
- return postTimedEvent(event, ALooper::GetNowUs() + delay_us);
-}
-
-TimedEventQueue::event_id TimedEventQueue::postTimedEvent(
- const sp<Event> &event, int64_t realtime_us) {
- Mutex::Autolock autoLock(mLock);
-
- event->setEventID(mNextEventID++);
-
- List<QueueItem>::iterator it = mQueue.begin();
- while (it != mQueue.end() && realtime_us >= (*it).realtime_us) {
- ++it;
- }
-
- QueueItem item;
- item.event = event;
- item.realtime_us = realtime_us;
- item.has_wakelock = false;
-
- if (it == mQueue.begin()) {
- mQueueHeadChangedCondition.signal();
- }
-
- if (realtime_us > ALooper::GetNowUs() + kWakelockMinDelay) {
- acquireWakeLock_l();
- item.has_wakelock = true;
- }
- mQueue.insert(it, item);
-
- mQueueNotEmptyCondition.signal();
-
- return event->eventID();
-}
-
-static bool MatchesEventID(
- void *cookie, const sp<TimedEventQueue::Event> &event) {
- TimedEventQueue::event_id *id =
- static_cast<TimedEventQueue::event_id *>(cookie);
-
- if (event->eventID() != *id) {
- return false;
- }
-
- *id = 0;
-
- return true;
-}
-
-bool TimedEventQueue::cancelEvent(event_id id) {
- if (id == 0) {
- return false;
- }
-
- cancelEvents(&MatchesEventID, &id, true /* stopAfterFirstMatch */);
-
- // if MatchesEventID found a match, it will have set id to 0
- // (which is not a valid event_id).
-
- return id == 0;
-}
-
-void TimedEventQueue::cancelEvents(
- bool (*predicate)(void *cookie, const sp<Event> &event),
- void *cookie,
- bool stopAfterFirstMatch) {
- Mutex::Autolock autoLock(mLock);
-
- List<QueueItem>::iterator it = mQueue.begin();
- while (it != mQueue.end()) {
- if (!(*predicate)(cookie, (*it).event)) {
- ++it;
- continue;
- }
-
- if (it == mQueue.begin()) {
- mQueueHeadChangedCondition.signal();
- }
-
- ALOGV("cancelling event %d", (*it).event->eventID());
-
- (*it).event->setEventID(0);
- if ((*it).has_wakelock) {
- releaseWakeLock_l();
- }
- it = mQueue.erase(it);
- if (stopAfterFirstMatch) {
- return;
- }
- }
-}
-
-// static
-void *TimedEventQueue::ThreadWrapper(void *me) {
-
- androidSetThreadPriority(0, ANDROID_PRIORITY_FOREGROUND);
-
- static_cast<TimedEventQueue *>(me)->threadEntry();
-
- return NULL;
-}
-
-void TimedEventQueue::threadEntry() {
- prctl(PR_SET_NAME, (unsigned long)"TimedEventQueue", 0, 0, 0);
-
- for (;;) {
- int64_t now_us = 0;
- sp<Event> event;
- bool wakeLocked = false;
-
- {
- Mutex::Autolock autoLock(mLock);
-
- if (mStopped) {
- break;
- }
-
- while (mQueue.empty()) {
- mQueueNotEmptyCondition.wait(mLock);
- }
-
- event_id eventID = 0;
- for (;;) {
- if (mQueue.empty()) {
- // The only event in the queue could have been cancelled
- // while we were waiting for its scheduled time.
- break;
- }
-
- List<QueueItem>::iterator it = mQueue.begin();
- eventID = (*it).event->eventID();
-
- now_us = ALooper::GetNowUs();
- int64_t when_us = (*it).realtime_us;
-
- int64_t delay_us;
- if (when_us < 0 || when_us == INT64_MAX) {
- delay_us = 0;
- } else {
- delay_us = when_us - now_us;
- }
-
- if (delay_us <= 0) {
- break;
- }
-
- static int64_t kMaxTimeoutUs = 10000000ll; // 10 secs
- bool timeoutCapped = false;
- if (delay_us > kMaxTimeoutUs) {
- ALOGW("delay_us exceeds max timeout: %" PRId64 " us", delay_us);
-
- // We'll never block for more than 10 secs, instead
- // we will split up the full timeout into chunks of
- // 10 secs at a time. This will also avoid overflow
- // when converting from us to ns.
- delay_us = kMaxTimeoutUs;
- timeoutCapped = true;
- }
-
- status_t err = mQueueHeadChangedCondition.waitRelative(
- mLock, delay_us * 1000ll);
-
- if (!timeoutCapped && err == -ETIMEDOUT) {
- // We finally hit the time this event is supposed to
- // trigger.
- now_us = ALooper::GetNowUs();
- break;
- }
- }
-
- // The event w/ this id may have been cancelled while we're
- // waiting for its trigger-time, in that case
- // removeEventFromQueue_l will return NULL.
- // Otherwise, the QueueItem will be removed
- // from the queue and the referenced event returned.
- event = removeEventFromQueue_l(eventID, &wakeLocked);
- }
-
- if (event != NULL) {
- // Fire event with the lock NOT held.
- event->fire(this, now_us);
- if (wakeLocked) {
- Mutex::Autolock autoLock(mLock);
- releaseWakeLock_l();
- }
- }
- }
-}
-
-sp<TimedEventQueue::Event> TimedEventQueue::removeEventFromQueue_l(
- event_id id, bool *wakeLocked) {
- for (List<QueueItem>::iterator it = mQueue.begin();
- it != mQueue.end(); ++it) {
- if ((*it).event->eventID() == id) {
- sp<Event> event = (*it).event;
- event->setEventID(0);
- *wakeLocked = (*it).has_wakelock;
- mQueue.erase(it);
- return event;
- }
- }
-
- ALOGW("Event %d was not found in the queue, already cancelled?", id);
-
- return NULL;
-}
-
-void TimedEventQueue::acquireWakeLock_l()
-{
- if (mWakeLockCount == 0) {
- CHECK(mWakeLockToken == 0);
- if (mPowerManager == 0) {
- // use checkService() to avoid blocking if power service is not up yet
- sp<IBinder> binder =
- defaultServiceManager()->checkService(String16("power"));
- if (binder == 0) {
- ALOGW("cannot connect to the power manager service");
- } else {
- mPowerManager = interface_cast<IPowerManager>(binder);
- binder->linkToDeath(mDeathRecipient);
- }
- }
- if (mPowerManager != 0) {
- sp<IBinder> binder = new BBinder();
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
- binder,
- String16("TimedEventQueue"),
- String16("media")); // not oneway
- IPCThreadState::self()->restoreCallingIdentity(token);
- if (status == NO_ERROR) {
- mWakeLockToken = binder;
- mWakeLockCount++;
- }
- }
- } else {
- mWakeLockCount++;
- }
-}
-
-void TimedEventQueue::releaseWakeLock_l(bool force)
-{
- if (mWakeLockCount == 0) {
- return;
- }
- if (force) {
- // Force wakelock release below by setting reference count to 1.
- mWakeLockCount = 1;
- }
- if (--mWakeLockCount == 0) {
- CHECK(mWakeLockToken != 0);
- if (mPowerManager != 0) {
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- mPowerManager->releaseWakeLock(mWakeLockToken, 0); // not oneway
- IPCThreadState::self()->restoreCallingIdentity(token);
- }
- mWakeLockToken.clear();
- }
-}
-
-void TimedEventQueue::clearPowerManager()
-{
- Mutex::Autolock _l(mLock);
- releaseWakeLock_l(true /*force*/);
- mPowerManager.clear();
-}
-
-void TimedEventQueue::PMDeathRecipient::binderDied(
- const wp<IBinder>& /* who */) {
- mQueue->clearPowerManager();
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 17f0201..dcc29fe 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -18,8 +18,11 @@
#define LOG_TAG "Utils"
#include <utils/Log.h>
#include <ctype.h>
+#include <stdio.h>
+#include <sys/stat.h>
#include "include/ESDS.h"
+#include "include/HevcUtils.h"
#include <arpa/inet.h>
#include <cutils/properties.h>
@@ -89,10 +92,18 @@
status_t convertMetaDataToMessage(
const sp<MetaData> &meta, sp<AMessage> *format) {
+
format->clear();
+ if (meta == NULL) {
+ ALOGE("convertMetaDataToMessage: NULL input");
+ return BAD_VALUE;
+ }
+
const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
+ if (!meta->findCString(kKeyMIMEType, &mime)) {
+ return BAD_VALUE;
+ }
sp<AMessage> msg = new AMessage;
msg->setString("mime", mime);
@@ -114,8 +125,10 @@
if (!strncasecmp("video/", mime, 6)) {
int32_t width, height;
- CHECK(meta->findInt32(kKeyWidth, &width));
- CHECK(meta->findInt32(kKeyHeight, &height));
+ if (!meta->findInt32(kKeyWidth, &width)
+ || !meta->findInt32(kKeyHeight, &height)) {
+ return BAD_VALUE;
+ }
msg->setInt32("width", width);
msg->setInt32("height", height);
@@ -147,8 +160,10 @@
}
} else if (!strncasecmp("audio/", mime, 6)) {
int32_t numChannels, sampleRate;
- CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
- CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+ if (!meta->findInt32(kKeyChannelCount, &numChannels)
+ || !meta->findInt32(kKeySampleRate, &sampleRate)) {
+ return BAD_VALUE;
+ }
msg->setInt32("channel-count", numChannels);
msg->setInt32("sample-rate", sampleRate);
@@ -371,7 +386,9 @@
} else if (meta->findData(kKeyESDS, &type, &data, &size)) {
ESDS esds((const char *)data, size);
- CHECK_EQ(esds.InitCheck(), (status_t)OK);
+ if (esds.InitCheck() != (status_t)OK) {
+ return BAD_VALUE;
+ }
const void *codec_specific_data;
size_t codec_specific_data_size;
@@ -453,6 +470,13 @@
msg->setBuffer("csd-2", buffer);
}
+ // TODO expose "crypto-key"/kKeyCryptoKey through public api
+ if (meta->findData(kKeyCryptoKey, &type, &data, &size)) {
+ sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
+ msg->setBuffer("crypto-key", buffer);
+ memcpy(buffer->data(), data, size);
+ }
+
*format = msg;
return OK;
@@ -567,6 +591,41 @@
}
+static size_t reassembleHVCC(const sp<ABuffer> &csd0, uint8_t *hvcc, size_t hvccSize, size_t nalSizeLength) {
+ HevcParameterSets paramSets;
+ uint8_t* data = csd0->data();
+ if (csd0->size() < 4) {
+ ALOGE("csd0 too small");
+ return 0;
+ }
+ if (memcmp(data, "\x00\x00\x00\x01", 4) != 0) {
+ ALOGE("csd0 doesn't start with a start code");
+ return 0;
+ }
+ size_t prevNalOffset = 4;
+ status_t err = OK;
+ for (size_t i = 1; i < csd0->size() - 4; ++i) {
+ if (memcmp(&data[i], "\x00\x00\x00\x01", 4) != 0) {
+ continue;
+ }
+ err = paramSets.addNalUnit(&data[prevNalOffset], i - prevNalOffset);
+ if (err != OK) {
+ return 0;
+ }
+ prevNalOffset = i + 4;
+ }
+ err = paramSets.addNalUnit(&data[prevNalOffset], csd0->size() - prevNalOffset);
+ if (err != OK) {
+ return 0;
+ }
+ size_t size = hvccSize;
+ err = paramSets.makeHvcc(hvcc, &size, nalSizeLength);
+ if (err != OK) {
+ return 0;
+ }
+ return size;
+}
+
void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
AString mime;
if (msg->findString("mime", &mime)) {
@@ -685,6 +744,10 @@
// for transporting the CSD to muxers.
reassembleESDS(csd0, esds);
meta->setData(kKeyESDS, kKeyESDS, esds, sizeof(esds));
+ } else if (mime == MEDIA_MIMETYPE_VIDEO_HEVC) {
+ uint8_t hvcc[1024]; // that oughta be enough, right?
+ size_t outsize = reassembleHVCC(csd0, hvcc, 1024, 4);
+ meta->setData(kKeyHVCC, kKeyHVCC, hvcc, outsize);
}
}
@@ -1007,5 +1070,37 @@
*sync = settings;
}
+AString nameForFd(int fd) {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ AString result;
+ snprintf(buffer, SIZE, "/proc/%d/fd/%d", getpid(), fd);
+ struct stat s;
+ if (lstat(buffer, &s) == 0) {
+ if ((s.st_mode & S_IFMT) == S_IFLNK) {
+ char linkto[256];
+ int len = readlink(buffer, linkto, sizeof(linkto));
+ if(len > 0) {
+ if(len > 255) {
+ linkto[252] = '.';
+ linkto[253] = '.';
+ linkto[254] = '.';
+ linkto[255] = 0;
+ } else {
+ linkto[len] = 0;
+ }
+ result.append(linkto);
+ }
+ } else {
+ result.append("unexpected type for ");
+ result.append(buffer);
+ }
+ } else {
+ result.append("couldn't open ");
+ result.append(buffer);
+ }
+ return result;
+}
+
} // namespace android
diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp
index 8a0fcac..58f2c60 100644
--- a/media/libstagefright/VBRISeeker.cpp
+++ b/media/libstagefright/VBRISeeker.cpp
@@ -149,7 +149,7 @@
}
bool VBRISeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) {
- if (mDurationUs < 0) {
+ if (mDurationUs < 0 || mSegments.size() == 0) {
return false;
}
diff --git a/media/libstagefright/VideoFrameScheduler.cpp b/media/libstagefright/VideoFrameScheduler.cpp
index 5fe9bf9..5564926 100644
--- a/media/libstagefright/VideoFrameScheduler.cpp
+++ b/media/libstagefright/VideoFrameScheduler.cpp
@@ -460,14 +460,16 @@
mTimeCorrection -= mVsyncPeriod / 2;
renderTime -= mVsyncPeriod / 2;
nextVsyncTime -= mVsyncPeriod;
- --vsyncsForLastFrame;
+ if (vsyncsForLastFrame > 0)
+ --vsyncsForLastFrame;
} else if (mTimeCorrection < -correctionLimit &&
(vsyncsPerFrameAreNearlyConstant || vsyncsForLastFrame == minVsyncsPerFrame)) {
// add a VSYNC
mTimeCorrection += mVsyncPeriod / 2;
renderTime += mVsyncPeriod / 2;
nextVsyncTime += mVsyncPeriod;
- ++vsyncsForLastFrame;
+ if (vsyncsForLastFrame < ULONG_MAX)
+ ++vsyncsForLastFrame;
}
ATRACE_INT("FRAME_VSYNCS", vsyncsForLastFrame);
}
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 335ac84..680c0c6 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -116,7 +116,7 @@
return mInitCheck == OK ? 1 : 0;
}
-sp<MediaSource> WAVExtractor::getTrack(size_t index) {
+sp<IMediaSource> WAVExtractor::getTrack(size_t index) {
if (mInitCheck != OK || index > 0) {
return NULL;
}
@@ -193,15 +193,17 @@
}
mNumChannels = U16_LE_AT(&formatSpec[2]);
+
+ if (mNumChannels < 1 || mNumChannels > 8) {
+ ALOGE("Unsupported number of channels (%d)", mNumChannels);
+ return ERROR_UNSUPPORTED;
+ }
+
if (mWaveFormat != WAVE_FORMAT_EXTENSIBLE) {
if (mNumChannels != 1 && mNumChannels != 2) {
ALOGW("More than 2 channels (%d) in non-WAVE_EXT, unknown channel mask",
mNumChannels);
}
- } else {
- if (mNumChannels < 1 && mNumChannels > 8) {
- return ERROR_UNSUPPORTED;
- }
}
mSampleRate = U32_LE_AT(&formatSpec[4]);
@@ -311,9 +313,17 @@
1000000LL * (mDataSize / 65 * 320) / 8000;
} else {
size_t bytesPerSample = mBitsPerSample >> 3;
+
+ if (!bytesPerSample || !mNumChannels)
+ return ERROR_MALFORMED;
+
+ size_t num_samples = mDataSize / (mNumChannels * bytesPerSample);
+
+ if (!mSampleRate)
+ return ERROR_MALFORMED;
+
durationUs =
- 1000000LL * (mDataSize / (mNumChannels * bytesPerSample))
- / mSampleRate;
+ 1000000LL * num_samples / mSampleRate;
}
mTrackMeta->setInt64(kKeyDuration, durationUs);
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index bc48272..d1b2f54 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -95,7 +95,7 @@
return (mImpl != NULL) ? mImpl->countTracks() : 0;
}
-sp<MediaSource> WVMExtractor::getTrack(size_t index) {
+sp<IMediaSource> WVMExtractor::getTrack(size_t index) {
if (mImpl == NULL) {
return NULL;
}
diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk
index afb00aa..84ea708 100644
--- a/media/libstagefright/codecs/aacdec/Android.mk
+++ b/media/libstagefright/codecs/aacdec/Android.mk
@@ -19,6 +19,8 @@
LOCAL_CFLAGS :=
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
LOCAL_STATIC_LIBRARIES := libFraunhoferAAC
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index bebb9dc..9e596ff 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -30,7 +30,7 @@
namespace android {
-AACEncoder::AACEncoder(const sp<MediaSource> &source, const sp<MetaData> &meta)
+AACEncoder::AACEncoder(const sp<IMediaSource> &source, const sp<MetaData> &meta)
: mSource(source),
mMeta(meta),
mStarted(false),
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index 58ec3ba..266f01b 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -1,6 +1,5 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-include frameworks/av/media/libstagefright/codecs/common/Config.mk
AAC_LIBRARY = fraunhofer
@@ -35,24 +34,28 @@
src/transform.c \
src/memalign.c
-ifeq ($(VOTT), v5)
-LOCAL_SRC_FILES += \
- src/asm/ARMV5E/AutoCorrelation_v5.s \
- src/asm/ARMV5E/band_nrg_v5.s \
- src/asm/ARMV5E/CalcWindowEnergy_v5.s \
- src/asm/ARMV5E/PrePostMDCT_v5.s \
- src/asm/ARMV5E/R4R8First_v5.s \
- src/asm/ARMV5E/Radix4FFT_v5.s
-endif
+ifneq ($(ARCH_ARM_HAVE_NEON),true)
+ LOCAL_SRC_FILES_arm := \
+ src/asm/ARMV5E/AutoCorrelation_v5.s \
+ src/asm/ARMV5E/band_nrg_v5.s \
+ src/asm/ARMV5E/CalcWindowEnergy_v5.s \
+ src/asm/ARMV5E/PrePostMDCT_v5.s \
+ src/asm/ARMV5E/R4R8First_v5.s \
+ src/asm/ARMV5E/Radix4FFT_v5.s
-ifeq ($(VOTT), v7)
-LOCAL_SRC_FILES += \
- src/asm/ARMV5E/AutoCorrelation_v5.s \
- src/asm/ARMV5E/band_nrg_v5.s \
- src/asm/ARMV5E/CalcWindowEnergy_v5.s \
- src/asm/ARMV7/PrePostMDCT_v7.s \
- src/asm/ARMV7/R4R8First_v7.s \
- src/asm/ARMV7/Radix4FFT_v7.s
+ LOCAL_CFLAGS_arm := -DARMV5E -DARM_INASM -DARMV5_INASM
+ LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/src/asm/ARMV5E
+else
+ LOCAL_SRC_FILES_arm := \
+ src/asm/ARMV5E/AutoCorrelation_v5.s \
+ src/asm/ARMV5E/band_nrg_v5.s \
+ src/asm/ARMV5E/CalcWindowEnergy_v5.s \
+ src/asm/ARMV7/PrePostMDCT_v7.s \
+ src/asm/ARMV7/R4R8First_v7.s \
+ src/asm/ARMV7/Radix4FFT_v7.s
+ LOCAL_CFLAGS_arm := -DARMV5E -DARMV7Neon -DARM_INASM -DARMV5_INASM -DARMV6_INASM
+ LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/src/asm/ARMV5E
+ LOCAL_C_INCLUDES_arm += $(LOCAL_PATH)/src/asm/ARMV7
endif
LOCAL_MODULE := libstagefright_aacenc
@@ -71,18 +74,9 @@
$(LOCAL_PATH)/inc \
$(LOCAL_PATH)/basic_op
-ifeq ($(VOTT), v5)
-LOCAL_CFLAGS += -DARMV5E -DARM_INASM -DARMV5_INASM
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E
-endif
-
-ifeq ($(VOTT), v7)
-LOCAL_CFLAGS += -DARMV5E -DARMV7Neon -DARM_INASM -DARMV5_INASM -DARMV6_INASM
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV7
-endif
-
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
include $(BUILD_STATIC_LIBRARY)
@@ -109,6 +103,8 @@
LOCAL_CFLAGS :=
LOCAL_CFLAGS += -Werror
+ LOCAL_CLANG := true
+ LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
LOCAL_STATIC_LIBRARIES := libFraunhoferAAC
@@ -133,6 +129,8 @@
LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
LOCAL_CFLAGS += -Werror
+ LOCAL_CLANG := true
+ LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
LOCAL_STATIC_LIBRARIES := \
libstagefright_aacenc
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index 35aa883..96e2f87 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -20,9 +20,11 @@
#include "SoftAACEncoder2.h"
#include <OMX_AudioExt.h>
+#include <OMX_IndexExt.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/hexdump.h>
+#include <utils/misc.h>
namespace android {
@@ -35,6 +37,14 @@
params->nVersion.s.nStep = 0;
}
+static const OMX_U32 kSupportedProfiles[] = {
+ OMX_AUDIO_AACObjectLC,
+ OMX_AUDIO_AACObjectHE,
+ OMX_AUDIO_AACObjectHE_PS,
+ OMX_AUDIO_AACObjectLD,
+ OMX_AUDIO_AACObjectELD,
+};
+
SoftAACEncoder2::SoftAACEncoder2(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
@@ -117,7 +127,7 @@
OMX_ERRORTYPE SoftAACEncoder2::internalGetParameter(
OMX_INDEXTYPE index, OMX_PTR params) {
- switch (index) {
+ switch ((OMX_U32) index) {
case OMX_IndexParamAudioPortFormat:
{
OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
@@ -220,6 +230,25 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamAudioProfileQuerySupported:
+ {
+ OMX_AUDIO_PARAM_ANDROID_PROFILETYPE *profileParams =
+ (OMX_AUDIO_PARAM_ANDROID_PROFILETYPE *)params;
+
+ if (profileParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (profileParams->nProfileIndex >= NELEM(kSupportedProfiles)) {
+ return OMX_ErrorNoMore;
+ }
+
+ profileParams->eProfile =
+ kSupportedProfiles[profileParams->nProfileIndex];
+
+ return OMX_ErrorNone;
+ }
+
default:
return SimpleSoftOMXComponent::internalGetParameter(index, params);
}
diff --git a/media/libstagefright/codecs/amrnb/common/Android.mk b/media/libstagefright/codecs/amrnb/common/Android.mk
index 5e632a6..15220a4 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.mk
+++ b/media/libstagefright/codecs/amrnb/common/Android.mk
@@ -7,7 +7,6 @@
src/bitno_tab.cpp \
src/bitreorder_tab.cpp \
src/bits2prm.cpp \
- src/bytesused.cpp \
src/c2_9pf_tab.cpp \
src/copy.cpp \
src/div_32.cpp \
@@ -38,7 +37,6 @@
src/mult_r.cpp \
src/norm_l.cpp \
src/norm_s.cpp \
- src/overflow_tbl.cpp \
src/ph_disp_tab.cpp \
src/pow2.cpp \
src/pow2_tbl.cpp \
@@ -70,6 +68,9 @@
-D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF=
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+#addressing b/25409744
+#LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
LOCAL_MODULE := libstagefright_amrnb_common
diff --git a/media/libstagefright/codecs/amrnb/common/include/basic_op_c_equivalent.h b/media/libstagefright/codecs/amrnb/common/include/basic_op_c_equivalent.h
index c4e4d4f..8f0867a 100644
--- a/media/libstagefright/codecs/amrnb/common/include/basic_op_c_equivalent.h
+++ b/media/libstagefright/codecs/amrnb/common/include/basic_op_c_equivalent.h
@@ -115,6 +115,7 @@
Returns:
L_sum = 32-bit sum of L_var1 and L_var2 (Word32)
*/
+ __attribute__((no_sanitize("integer")))
static inline Word32 L_add(Word32 L_var1, Word32 L_var2, Flag *pOverflow)
{
Word32 L_sum;
diff --git a/media/libstagefright/codecs/amrnb/common/include/bytesused.h b/media/libstagefright/codecs/amrnb/common/include/bytesused.h
deleted file mode 100644
index 934efbe..0000000
--- a/media/libstagefright/codecs/amrnb/common/include/bytesused.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/* ------------------------------------------------------------------
- * Copyright (C) 1998-2009 PacketVideo
- *
- * 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.
- * -------------------------------------------------------------------
- */
-/****************************************************************************************
-Portions of this file are derived from the following 3GPP standard:
-
- 3GPP TS 26.073
- ANSI-C code for the Adaptive Multi-Rate (AMR) speech codec
- Available from http://www.3gpp.org
-
-(C) 2004, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC)
-Permission to distribute, modify and use this file under the standard license
-terms listed above has been obtained from the copyright holder.
-****************************************************************************************/
-/*
-
- Pathname: .audio/gsm-amr/c/include/BytesUsed.h
-
-------------------------------------------------------------------------------
- REVISION HISTORY
-
- Description: Added #ifdef __cplusplus after Include section.
-
- Who: Date:
- Description:
-
-------------------------------------------------------------------------------
- INCLUDE DESCRIPTION
-
- This file declares a table BytesUsed.
-
-------------------------------------------------------------------------------
-*/
-
-/*----------------------------------------------------------------------------
-; CONTINUE ONLY IF NOT ALREADY DEFINED
-----------------------------------------------------------------------------*/
-#ifndef BYTESUSED_H
-#define BYTESUSED_H
-
-/*----------------------------------------------------------------------------
-; INCLUDES
-----------------------------------------------------------------------------*/
-
-/*--------------------------------------------------------------------------*/
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
- /*----------------------------------------------------------------------------
- ; MACROS
- ; Define module specific macros here
- ----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- ; DEFINES
- ; Include all pre-processor statements here.
- ----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- ; EXTERNAL VARIABLES REFERENCES
- ; Declare variables used in this module but defined elsewhere
- ----------------------------------------------------------------------------*/
- extern const short BytesUsed[];
-
- /*----------------------------------------------------------------------------
- ; SIMPLE TYPEDEF'S
- ----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- ; ENUMERATED TYPEDEF'S
- ----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- ; STRUCTURES TYPEDEF'S
- ----------------------------------------------------------------------------*/
-
-
- /*----------------------------------------------------------------------------
- ; GLOBAL FUNCTION DEFINITIONS
- ; Function Prototype declaration
- ----------------------------------------------------------------------------*/
-
-
- /*----------------------------------------------------------------------------
- ; END
- ----------------------------------------------------------------------------*/
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
-
diff --git a/media/libstagefright/codecs/amrnb/common/src/az_lsp.cpp b/media/libstagefright/codecs/amrnb/common/src/az_lsp.cpp
index 976b1a6..459c3c3 100644
--- a/media/libstagefright/codecs/amrnb/common/src/az_lsp.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/az_lsp.cpp
@@ -237,7 +237,9 @@
------------------------------------------------------------------------------
*/
-
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
static Word16 Chebps(Word16 x,
Word16 f[], /* (n) */
Word16 n,
diff --git a/media/libstagefright/codecs/amrnb/common/src/bytesused.cpp b/media/libstagefright/codecs/amrnb/common/src/bytesused.cpp
deleted file mode 100644
index b61bac4..0000000
--- a/media/libstagefright/codecs/amrnb/common/src/bytesused.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/* ------------------------------------------------------------------
- * Copyright (C) 1998-2009 PacketVideo
- *
- * 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.
- * -------------------------------------------------------------------
- */
-/****************************************************************************************
-Portions of this file are derived from the following 3GPP standard:
-
- 3GPP TS 26.073
- ANSI-C code for the Adaptive Multi-Rate (AMR) speech codec
- Available from http://www.3gpp.org
-
-(C) 2004, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC)
-Permission to distribute, modify and use this file under the standard license
-terms listed above has been obtained from the copyright holder.
-****************************************************************************************/
-/*
-
- Pathname: ./audio/gsm-amr/c/src/BytesUsed.c
-
-------------------------------------------------------------------------------
- REVISION HISTORY
-
- Description: Corrected entries for all SID frames and updated function
- description. Updated copyright year.
-
- Description: Added #ifdef __cplusplus and removed "extern" from table
- definition. Removed corresponding header file from Include
- section.
-
- Description: Put "extern" back.
-
- Who: Date:
- Description:
-
-------------------------------------------------------------------------------
- INPUT AND OUTPUT DEFINITIONS
-
- Inputs:
- None
-
- Local Stores/Buffers/Pointers Needed:
- None
-
- Global Stores/Buffers/Pointers Needed:
- None
-
- Outputs:
- None
-
- Pointers and Buffers Modified:
- None
-
- Local Stores Modified:
- None
-
- Global Stores Modified:
- None
-
-------------------------------------------------------------------------------
- FUNCTION DESCRIPTION
-
- This function creates a table called BytesUsed that holds the value that
- describes the number of bytes required to hold one frame worth of data in
- the WMF (non-IF2) frame format. Each table entry is the sum of the frame
- type byte and the number of bytes used up by the core speech data for each
- 3GPP frame type.
-
-------------------------------------------------------------------------------
- REQUIREMENTS
-
- None
-
-------------------------------------------------------------------------------
- REFERENCES
-
- [1] "AMR Speech Codec Frame Structure", 3GPP TS 26.101 version 4.1.0
- Release 4, June 2001, page 13.
-
-------------------------------------------------------------------------------
- PSEUDO-CODE
-
-
-------------------------------------------------------------------------------
- RESOURCES USED
- When the code is written for a specific target processor the
- the resources used should be documented below.
-
- STACK USAGE: [stack count for this module] + [variable to represent
- stack usage for each subroutine called]
-
- where: [stack usage variable] = stack usage for [subroutine
- name] (see [filename].ext)
-
- DATA MEMORY USED: x words
-
- PROGRAM MEMORY USED: x words
-
- CLOCK CYCLES: [cycle count equation for this module] + [variable
- used to represent cycle count for each subroutine
- called]
-
- where: [cycle count variable] = cycle count for [subroutine
- name] (see [filename].ext)
-
-------------------------------------------------------------------------------
-*/
-
-
-/*----------------------------------------------------------------------------
-; INCLUDES
-----------------------------------------------------------------------------*/
-#include "typedef.h"
-
-/*--------------------------------------------------------------------------*/
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
- /*----------------------------------------------------------------------------
- ; MACROS
- ; Define module specific macros here
- ----------------------------------------------------------------------------*/
-
-
- /*----------------------------------------------------------------------------
- ; DEFINES
- ; Include all pre-processor statements here. Include conditional
- ; compile variables also.
- ----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- ; LOCAL FUNCTION DEFINITIONS
- ; Function Prototype declaration
- ----------------------------------------------------------------------------*/
-
-
- /*----------------------------------------------------------------------------
- ; LOCAL STORE/BUFFER/POINTER DEFINITIONS
- ; Variable declaration - defined here and used outside this module
- ----------------------------------------------------------------------------*/
- const short BytesUsed[16] =
- {
- 13, /* 4.75 */
- 14, /* 5.15 */
- 16, /* 5.90 */
- 18, /* 6.70 */
- 20, /* 7.40 */
- 21, /* 7.95 */
- 27, /* 10.2 */
- 32, /* 12.2 */
- 6, /* GsmAmr comfort noise */
- 7, /* Gsm-Efr comfort noise */
- 6, /* IS-641 comfort noise */
- 6, /* Pdc-Efr comfort noise */
- 0, /* future use */
- 0, /* future use */
- 0, /* future use */
- 1 /* No transmission */
- };
- /*----------------------------------------------------------------------------
- ; EXTERNAL FUNCTION REFERENCES
- ; Declare functions defined elsewhere and referenced in this module
- ----------------------------------------------------------------------------*/
-
-
- /*----------------------------------------------------------------------------
- ; EXTERNAL GLOBAL STORE/BUFFER/POINTER REFERENCES
- ; Declare variables used in this module but defined elsewhere
- ----------------------------------------------------------------------------*/
-
-
- /*--------------------------------------------------------------------------*/
-#ifdef __cplusplus
-}
-#endif
-
-/*----------------------------------------------------------------------------
-; FUNCTION CODE
-----------------------------------------------------------------------------*/
-
-/*----------------------------------------------------------------------------
-; Define all local variables
-----------------------------------------------------------------------------*/
-
-
-/*----------------------------------------------------------------------------
-; Function body here
-----------------------------------------------------------------------------*/
-
-
-/*----------------------------------------------------------------------------
-; Return nothing or data or data pointer
-----------------------------------------------------------------------------*/
-
diff --git a/media/libstagefright/codecs/amrnb/common/src/overflow_tbl.cpp b/media/libstagefright/codecs/amrnb/common/src/overflow_tbl.cpp
deleted file mode 100644
index c4a016d..0000000
--- a/media/libstagefright/codecs/amrnb/common/src/overflow_tbl.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/* ------------------------------------------------------------------
- * Copyright (C) 1998-2009 PacketVideo
- *
- * 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.
- * -------------------------------------------------------------------
- */
-/****************************************************************************************
-Portions of this file are derived from the following 3GPP standard:
-
- 3GPP TS 26.073
- ANSI-C code for the Adaptive Multi-Rate (AMR) speech codec
- Available from http://www.3gpp.org
-
-(C) 2004, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC)
-Permission to distribute, modify and use this file under the standard license
-terms listed above has been obtained from the copyright holder.
-****************************************************************************************/
-/*
-
- Filename: /audio/gsm_amr/c/src/overflow_tbl.c
-
-------------------------------------------------------------------------------
- REVISION HISTORY
-
- Description: Added #ifdef __cplusplus and removed "extern" from table
- definition.
-
- Description: Put "extern" back.
-
- Who: Date:
- Description:
-
-------------------------------------------------------------------------------
- MODULE DESCRIPTION
-
- This file contains the declaration for overflow_tbl[] used by the l_shl()
- and l_shr() functions.
-
-------------------------------------------------------------------------------
-*/
-
-/*----------------------------------------------------------------------------
-; INCLUDES
-----------------------------------------------------------------------------*/
-#include "typedef.h"
-
-/*--------------------------------------------------------------------------*/
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
- /*----------------------------------------------------------------------------
- ; MACROS
- ; [Define module specific macros here]
- ----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- ; DEFINES
- ; [Include all pre-processor statements here. Include conditional
- ; compile variables also.]
- ----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- ; LOCAL FUNCTION DEFINITIONS
- ; [List function prototypes here]
- ----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- ; LOCAL VARIABLE DEFINITIONS
- ; [Variable declaration - defined here and used outside this module]
- ----------------------------------------------------------------------------*/
- const Word32 overflow_tbl [32] = {0x7fffffffL, 0x3fffffffL,
- 0x1fffffffL, 0x0fffffffL,
- 0x07ffffffL, 0x03ffffffL,
- 0x01ffffffL, 0x00ffffffL,
- 0x007fffffL, 0x003fffffL,
- 0x001fffffL, 0x000fffffL,
- 0x0007ffffL, 0x0003ffffL,
- 0x0001ffffL, 0x0000ffffL,
- 0x00007fffL, 0x00003fffL,
- 0x00001fffL, 0x00000fffL,
- 0x000007ffL, 0x000003ffL,
- 0x000001ffL, 0x000000ffL,
- 0x0000007fL, 0x0000003fL,
- 0x0000001fL, 0x0000000fL,
- 0x00000007L, 0x00000003L,
- 0x00000001L, 0x00000000L
- };
-
- /*--------------------------------------------------------------------------*/
-#ifdef __cplusplus
-}
-#endif
-
-/*
-------------------------------------------------------------------------------
- FUNCTION NAME:
-------------------------------------------------------------------------------
- INPUT AND OUTPUT DEFINITIONS
-
- Inputs:
- None
-
- Outputs:
- None
-
- Returns:
- None
-
- Global Variables Used:
- None
-
- Local Variables Needed:
- None
-
-------------------------------------------------------------------------------
- FUNCTION DESCRIPTION
-
- None
-
-------------------------------------------------------------------------------
- REQUIREMENTS
-
- None
-
-------------------------------------------------------------------------------
- REFERENCES
-
- [1] l_shl() function in basic_op2.c, UMTS GSM AMR speech codec, R99 -
- Version 3.2.0, March 2, 2001
-
-------------------------------------------------------------------------------
- PSEUDO-CODE
-
-
-------------------------------------------------------------------------------
- RESOURCES USED [optional]
-
- When the code is written for a specific target processor the
- the resources used should be documented below.
-
- HEAP MEMORY USED: x bytes
-
- STACK MEMORY USED: x bytes
-
- CLOCK CYCLES: (cycle count equation for this function) + (variable
- used to represent cycle count for each subroutine
- called)
- where: (cycle count variable) = cycle count for [subroutine
- name]
-
-------------------------------------------------------------------------------
- CAUTION [optional]
- [State any special notes, constraints or cautions for users of this function]
-
-------------------------------------------------------------------------------
-*/
-
-/*----------------------------------------------------------------------------
-; FUNCTION CODE
-----------------------------------------------------------------------------*/
-
diff --git a/media/libstagefright/codecs/amrnb/common/src/sub.cpp b/media/libstagefright/codecs/amrnb/common/src/sub.cpp
index d936128..b956912 100644
--- a/media/libstagefright/codecs/amrnb/common/src/sub.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/sub.cpp
@@ -187,6 +187,9 @@
; FUNCTION CODE
----------------------------------------------------------------------------*/
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
Word16 sub(Word16 var1, Word16 var2, Flag *pOverflow)
{
diff --git a/media/libstagefright/codecs/amrnb/common/src/syn_filt.cpp b/media/libstagefright/codecs/amrnb/common/src/syn_filt.cpp
index bcdc696..36c1d84 100644
--- a/media/libstagefright/codecs/amrnb/common/src/syn_filt.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/syn_filt.cpp
@@ -245,7 +245,9 @@
------------------------------------------------------------------------------
*/
-
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
void Syn_filt(
Word16 a[], /* (i) : a[M+1] prediction coefficients (M=10) */
Word16 x[], /* (i) : input signal */
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index 76a7f40..7967ec3 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -48,6 +48,8 @@
-D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_IMPORT_REF=
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+#LOCAL_SANITIZE := signed-integer-overflow
LOCAL_MODULE := libstagefright_amrnbdec
@@ -71,6 +73,8 @@
LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+#LOCAL_SANITIZE := signed-integer-overflow
LOCAL_STATIC_LIBRARIES := \
libstagefright_amrnbdec libstagefright_amrwbdec
@@ -100,6 +104,9 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright_amrnb_common libaudioutils liblog
+LOCAL_CLANG := true
+#LOCAL_SANITIZE := signed-integer-overflow
+
LOCAL_MODULE := libstagefright_amrnbdec_test
LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
index bdba8a9..f8a41af 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ b/media/libstagefright/codecs/amrnb/enc/Android.mk
@@ -70,6 +70,9 @@
-D"OSCL_UNUSED_ARG(x)=(void)(x)"
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+#addressing b/25409744
+#LOCAL_SANITIZE := signed-integer-overflow
LOCAL_MODULE := libstagefright_amrnbenc
@@ -91,6 +94,9 @@
$(LOCAL_PATH)/../common
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+#addressing b/25409744
+#LOCAL_SANITIZE := signed-integer-overflow
LOCAL_STATIC_LIBRARIES := \
libstagefright_amrnbenc
@@ -103,3 +109,29 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ test/amrnb_enc_test.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/../common/include
+
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_amrnbenc
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright_amrnb_common
+
+LOCAL_CLANG := true
+#addressing b/25409744
+#LOCAL_SANITIZE := signed-integer-overflow
+
+LOCAL_MODULE := libstagefright_amrnbenc_test
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/amrnb/enc/src/l_negate.cpp b/media/libstagefright/codecs/amrnb/enc/src/l_negate.cpp
index 588abbb..523e482 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/l_negate.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/l_negate.cpp
@@ -147,7 +147,7 @@
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
-Word32 L_negate(register Word32 L_var1)
+Word32 L_negate(Word32 L_var1)
{
/*----------------------------------------------------------------------------
; Define all local variables
diff --git a/media/libstagefright/codecs/amrnb/enc/test/amrnb_enc_test.cpp b/media/libstagefright/codecs/amrnb/enc/test/amrnb_enc_test.cpp
new file mode 100644
index 0000000..e2d198e
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/test/amrnb_enc_test.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <stdint.h>
+#include <assert.h>
+#include "gsmamr_enc.h"
+
+enum {
+ kInputSize = 320, // 160 samples * 16-bit per sample.
+ kOutputSize = 1024
+};
+
+struct AmrNbEncState {
+ void *encCtx;
+ void *pidSyncCtx;
+};
+
+void usage(void) {
+ printf("Usage:\n");
+ printf("AMRNBEnc [options] <input file> <output file>\n");
+ printf("\n");
+ printf("Options +M* for setting compression bitrate mode, default is 4.75 kbps\n");
+ printf(" +M0 = 4.75 kbps\n");
+ printf(" +M1 = 5.15 kbps\n");
+ printf(" +M2 = 5.90 kbps\n");
+ printf(" +M3 = 6.70 kbps\n");
+ printf(" +M4 = 7.40 kbps\n");
+ printf(" +M5 = 7.95 kbps\n");
+ printf(" +M6 = 10.2 kbps\n");
+ printf(" +M7 = 12.2 kbps\n");
+ printf("\n");
+}
+
+int encode(int mode, const char *srcFile, const char *dstFile) {
+ int retVal = EXIT_SUCCESS;
+ FILE *fSrc = NULL;
+ FILE *fDst = NULL;
+ int frameNum = 0;
+ bool eofReached = false;
+ uint16_t *inputBuf = NULL;
+ uint8_t *outputBuf = NULL;
+ AmrNbEncState *amr = NULL;
+
+ clock_t start, finish;
+ double duration = 0.0;
+
+ // Open input file.
+ fSrc = fopen(srcFile, "rb");
+ if (fSrc == NULL) {
+ fprintf(stderr, "Error opening input file\n");
+ retVal = EXIT_FAILURE;
+ goto safe_exit;
+ }
+
+ // Open output file.
+ fDst = fopen(dstFile, "wb");
+ if (fDst == NULL) {
+ fprintf(stderr, "Error opening output file\n");
+ retVal = EXIT_FAILURE;
+ goto safe_exit;
+ }
+
+ // Allocate input buffer.
+ inputBuf = (uint16_t*) malloc(kInputSize);
+ assert(inputBuf != NULL);
+
+ // Allocate output buffer.
+ outputBuf = (uint8_t*) malloc(kOutputSize);
+ assert(outputBuf != NULL);
+
+ // Initialize encoder.
+ amr = (AmrNbEncState*) malloc(sizeof(AmrNbEncState));
+ AMREncodeInit(&amr->encCtx, &amr->pidSyncCtx, 0);
+
+ // Write file header.
+ fwrite("#!AMR\n", 1, 6, fDst);
+
+ while (1) {
+ // Read next input frame.
+ int bytesRead;
+ bytesRead = fread(inputBuf, 1, kInputSize, fSrc);
+ if (bytesRead != kInputSize && !feof(fSrc)) {
+ retVal = EXIT_FAILURE; // Invalid magic number.
+ fprintf(stderr, "Error reading input file\n");
+ goto safe_exit;
+ } else if (feof(fSrc) && bytesRead == 0) {
+ eofReached = true;
+ break;
+ }
+
+ start = clock();
+
+ // Encode the frame.
+ Frame_Type_3GPP frame_type = (Frame_Type_3GPP) mode;
+ int bytesGenerated;
+ bytesGenerated = AMREncode(amr->encCtx, amr->pidSyncCtx, (Mode)mode,
+ (Word16*)inputBuf, outputBuf, &frame_type,
+ AMR_TX_WMF);
+
+ // Convert from WMF to RFC 3267 format.
+ if (bytesGenerated > 0) {
+ outputBuf[0] = ((outputBuf[0] << 3) | 4) & 0x7c;
+ }
+
+ finish = clock();
+ duration += finish - start;
+
+ if (bytesGenerated < 0) {
+ retVal = EXIT_FAILURE;
+ fprintf(stderr, "Encoding error\n");
+ goto safe_exit;
+ }
+
+ frameNum++;
+ printf(" Frames processed: %d\n", frameNum);
+
+ // Write the output.
+ fwrite(outputBuf, 1, bytesGenerated, fDst);
+ }
+
+ // Dump the time taken by encode.
+ printf("\n%2.5lf seconds\n", (double)duration/CLOCKS_PER_SEC);
+
+safe_exit:
+
+ // Free the encoder instance.
+ if (amr) {
+ AMREncodeExit(&amr->encCtx, &amr->pidSyncCtx);
+ free(amr);
+ }
+
+ // Free input and output buffer.
+ free(inputBuf);
+ free(outputBuf);
+
+ // Close the input and output files.
+ if (fSrc) {
+ fclose(fSrc);
+ }
+ if (fDst) {
+ fclose(fDst);
+ }
+
+ return retVal;
+}
+
+int main(int argc, char *argv[]) {
+ Mode mode = MR475;
+ int retVal;
+ char *inFileName = NULL;
+ char *outFileName = NULL;
+ int arg, filename = 0;
+
+ if (argc < 3) {
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ for (arg = 1; arg < argc; arg++) {
+ if (argv[arg][0] == '+') {
+ if (argv[arg][1] == 'M') {
+ switch (argv[arg][2]) {
+ case '0': mode = MR475;
+ break;
+ case '1': mode = MR515;
+ break;
+ case '2': mode = MR59;
+ break;
+ case '3': mode = MR67;
+ break;
+ case '4': mode = MR74;
+ break;
+ case '5': mode = MR795;
+ break;
+ case '6': mode = MR102;
+ break;
+ case '7': mode = MR122;
+ break;
+ default:
+ usage();
+ fprintf(stderr, "Invalid parameter '%s'.\n", argv[arg]);
+ return EXIT_FAILURE;
+ break;
+ }
+ } else {
+ usage();
+ fprintf(stderr, "Invalid parameter '%s'.\n", argv[arg]);
+ return EXIT_FAILURE;
+ }
+ } else {
+ switch (filename) {
+ case 0:
+ inFileName = argv[arg];
+ break;
+ case 1:
+ outFileName = argv[arg];
+ break;
+ default:
+ usage();
+ fprintf(stderr, "Invalid parameter '%s'.\n", argv[arg]);
+ return EXIT_FAILURE;
+ }
+ filename++;
+ }
+ }
+ }
+
+ retVal = encode(mode, inFileName, outFileName);
+ return retVal;
+}
+
diff --git a/media/libstagefright/codecs/amrwb/Android.mk b/media/libstagefright/codecs/amrwb/Android.mk
index 686f7a3..1649c4a 100644
--- a/media/libstagefright/codecs/amrwb/Android.mk
+++ b/media/libstagefright/codecs/amrwb/Android.mk
@@ -51,7 +51,33 @@
-D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_IMPORT_REF=
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
LOCAL_MODULE := libstagefright_amrwbdec
include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ test/amrwbdec_test.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include \
+ $(call include-path-for, audio-utils)
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_amrwbdec libsndfile
+
+LOCAL_SHARED_LIBRARIES := \
+ libaudioutils
+
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
+
+LOCAL_MODULE := libstagefright_amrwbdec_test
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/amrwb/test/amrwbdec_test.cpp b/media/libstagefright/codecs/amrwb/test/amrwbdec_test.cpp
new file mode 100644
index 0000000..b04bafd
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/test/amrwbdec_test.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "pvamrwbdecoder.h"
+#include <audio_utils/sndfile.h>
+
+// Constants for AMR-WB.
+enum {
+ kInputBufferSize = 64,
+ kSamplesPerFrame = 320,
+ kBitsPerSample = 16,
+ kOutputBufferSize = kSamplesPerFrame * kBitsPerSample/8,
+ kSampleRate = 16000,
+ kChannels = 1,
+ kFileHeaderSize = 9,
+ kMaxSourceDataUnitSize = 477 * sizeof(int16_t)
+};
+
+const uint32_t kFrameSizes[] = { 17, 23, 32, 36, 40, 46, 50, 58, 60 };
+
+int main(int argc, char *argv[]) {
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage %s <input file> <output file>\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ // Open the input file.
+ FILE* fpInput = fopen(argv[1], "rb");
+ if (fpInput == NULL) {
+ fprintf(stderr, "Could not open %s\n", argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ // Validate the input AMR file.
+ char header[kFileHeaderSize];
+ int bytesRead = fread(header, 1, kFileHeaderSize, fpInput);
+ if ((bytesRead != kFileHeaderSize) ||
+ (memcmp(header, "#!AMR-WB\n", kFileHeaderSize) != 0)) {
+ fprintf(stderr, "Invalid AMR-WB file\n");
+ fclose(fpInput);
+ return EXIT_FAILURE;
+ }
+
+ // Open the output file.
+ SF_INFO sfInfo;
+ memset(&sfInfo, 0, sizeof(SF_INFO));
+ sfInfo.channels = kChannels;
+ sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ sfInfo.samplerate = kSampleRate;
+ SNDFILE *handle = sf_open(argv[2], SFM_WRITE, &sfInfo);
+ if (handle == NULL) {
+ fprintf(stderr, "Could not create %s\n", argv[2]);
+ fclose(fpInput);
+ return EXIT_FAILURE;
+ }
+
+ // Allocate the decoder memory.
+ uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
+ void *decoderBuf = malloc(memRequirements);
+ assert(decoderBuf != NULL);
+
+ // Create AMR-WB decoder instance.
+ void *amrHandle;
+ int16_t *decoderCookie;
+ pvDecoder_AmrWb_Init(&amrHandle, decoderBuf, &decoderCookie);
+
+ // Allocate input buffer.
+ uint8_t *inputBuf = (uint8_t*) malloc(kInputBufferSize);
+ assert(inputBuf != NULL);
+
+ // Allocate input sample buffer.
+ int16_t *inputSampleBuf = (int16_t*) malloc(kMaxSourceDataUnitSize);
+ assert(inputSampleBuf != NULL);
+
+ // Allocate output buffer.
+ int16_t *outputBuf = (int16_t*) malloc(kOutputBufferSize);
+ assert(outputBuf != NULL);
+
+ // Decode loop.
+ int retVal = EXIT_SUCCESS;
+ while (1) {
+ // Read mode.
+ uint8_t modeByte;
+ bytesRead = fread(&modeByte, 1, 1, fpInput);
+ if (bytesRead != 1) break;
+ int16 mode = ((modeByte >> 3) & 0x0f);
+
+ // AMR-WB file format cannot have mode 10, 11, 12 and 13.
+ if (mode >= 10 && mode <= 13) {
+ fprintf(stderr, "Encountered illegal frame type %d\n", mode);
+ retVal = EXIT_FAILURE;
+ break;
+ }
+
+ if (mode >= 9) {
+ // Produce silence for comfort noise, speech lost and no data.
+ memset(outputBuf, 0, kOutputBufferSize);
+ } else /* if (mode < 9) */ {
+ // Read rest of the frame.
+ int32_t frameSize = kFrameSizes[mode];
+ bytesRead = fread(inputBuf, 1, frameSize, fpInput);
+ if (bytesRead != frameSize) break;
+
+ int16 frameType, frameMode;
+ RX_State_wb rx_state;
+ frameMode = mode;
+ mime_unsorting(
+ (uint8_t *)inputBuf,
+ inputSampleBuf,
+ &frameType, &frameMode, 1, &rx_state);
+
+ int16_t numSamplesOutput;
+ pvDecoder_AmrWb(
+ frameMode, inputSampleBuf,
+ outputBuf,
+ &numSamplesOutput,
+ decoderBuf, frameType, decoderCookie);
+
+ if (numSamplesOutput != kSamplesPerFrame) {
+ fprintf(stderr, "Decoder encountered error\n");
+ retVal = EXIT_FAILURE;
+ break;
+ }
+
+ for (int i = 0; i < kSamplesPerFrame; ++i) {
+ outputBuf[i] &= 0xfffC;
+ }
+ }
+
+ // Write output to wav.
+ sf_writef_short(handle, outputBuf, kSamplesPerFrame / kChannels);
+ }
+
+ // Close input and output file.
+ fclose(fpInput);
+ sf_close(handle);
+
+ // Free allocated memory.
+ free(inputBuf);
+ free(inputSampleBuf);
+ free(outputBuf);
+
+ return retVal;
+}
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index 024a292..77a7b1e 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -1,8 +1,5 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-include frameworks/av/media/libstagefright/codecs/common/Config.mk
-
-
LOCAL_SRC_FILES := \
src/autocorr.c \
@@ -53,42 +50,41 @@
src/weight_a.c \
src/mem_align.c
+ifneq ($(ARCH_ARM_HAVE_NEON),true)
+ LOCAL_SRC_FILES_arm := \
+ src/asm/ARMV5E/convolve_opt.s \
+ src/asm/ARMV5E/cor_h_vec_opt.s \
+ src/asm/ARMV5E/Deemph_32_opt.s \
+ src/asm/ARMV5E/Dot_p_opt.s \
+ src/asm/ARMV5E/Filt_6k_7k_opt.s \
+ src/asm/ARMV5E/Norm_Corr_opt.s \
+ src/asm/ARMV5E/pred_lt4_1_opt.s \
+ src/asm/ARMV5E/residu_asm_opt.s \
+ src/asm/ARMV5E/scale_sig_opt.s \
+ src/asm/ARMV5E/Syn_filt_32_opt.s \
+ src/asm/ARMV5E/syn_filt_opt.s
-ifeq ($(VOTT), v5)
-LOCAL_SRC_FILES += \
- src/asm/ARMV5E/convolve_opt.s \
- src/asm/ARMV5E/cor_h_vec_opt.s \
- src/asm/ARMV5E/Deemph_32_opt.s \
- src/asm/ARMV5E/Dot_p_opt.s \
- src/asm/ARMV5E/Filt_6k_7k_opt.s \
- src/asm/ARMV5E/Norm_Corr_opt.s \
- src/asm/ARMV5E/pred_lt4_1_opt.s \
- src/asm/ARMV5E/residu_asm_opt.s \
- src/asm/ARMV5E/scale_sig_opt.s \
- src/asm/ARMV5E/Syn_filt_32_opt.s \
- src/asm/ARMV5E/syn_filt_opt.s
+ LOCAL_CFLAGS_arm := -DARM -DASM_OPT
+ LOCAL_C_INCLUDES_arm = $(LOCAL_PATH)/src/asm/ARMV5E
+else
+ LOCAL_SRC_FILES_arm := \
+ src/asm/ARMV7/convolve_neon.s \
+ src/asm/ARMV7/cor_h_vec_neon.s \
+ src/asm/ARMV7/Deemph_32_neon.s \
+ src/asm/ARMV7/Dot_p_neon.s \
+ src/asm/ARMV7/Filt_6k_7k_neon.s \
+ src/asm/ARMV7/Norm_Corr_neon.s \
+ src/asm/ARMV7/pred_lt4_1_neon.s \
+ src/asm/ARMV7/residu_asm_neon.s \
+ src/asm/ARMV7/scale_sig_neon.s \
+ src/asm/ARMV7/Syn_filt_32_neon.s \
+ src/asm/ARMV7/syn_filt_neon.s
+ LOCAL_CFLAGS_arm := -DARM -DARMV7 -DASM_OPT
+ LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/src/asm/ARMV5E
+ LOCAL_C_INCLUDES_arm += $(LOCAL_PATH)/src/asm/ARMV7
endif
-ifeq ($(VOTT), v7)
-LOCAL_SRC_FILES += \
- src/asm/ARMV7/convolve_neon.s \
- src/asm/ARMV7/cor_h_vec_neon.s \
- src/asm/ARMV7/Deemph_32_neon.s \
- src/asm/ARMV7/Dot_p_neon.s \
- src/asm/ARMV7/Filt_6k_7k_neon.s \
- src/asm/ARMV7/Norm_Corr_neon.s \
- src/asm/ARMV7/pred_lt4_1_neon.s \
- src/asm/ARMV7/residu_asm_neon.s \
- src/asm/ARMV7/scale_sig_neon.s \
- src/asm/ARMV7/Syn_filt_32_neon.s \
- src/asm/ARMV7/syn_filt_neon.s
-
-endif
-
-# ARMV5E/Filt_6k_7k_opt.s does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
-
LOCAL_MODULE := libstagefright_amrwbenc
LOCAL_ARM_MODE := arm
@@ -104,18 +100,9 @@
$(LOCAL_PATH)/src \
$(LOCAL_PATH)/inc
-ifeq ($(VOTT), v5)
-LOCAL_CFLAGS += -DARM -DASM_OPT
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E
-endif
-
-ifeq ($(VOTT), v7)
-LOCAL_CFLAGS += -DARM -DARMV7 -DASM_OPT
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV7
-endif
-
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_STATIC_LIBRARY)
@@ -132,6 +119,8 @@
frameworks/native/include/media/openmax
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
LOCAL_STATIC_LIBRARIES := \
libstagefright_amrwbenc
@@ -144,3 +133,6 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
+
+################################################################################
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c b/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c
index 4ff5f10..0cb0097 100644
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c
+++ b/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <time.h>
#include "voAMRWB.h"
#include "cmnMemory.h"
@@ -222,12 +223,12 @@
fflush(fdst);
}
}
- else if(returnCode == VO_ERR_LICENSE_ERROR)
+ else if((unsigned)returnCode == VO_ERR_LICENSE_ERROR)
{
printf("Encoder time reach upper limit......");
goto safe_exit;
}
- } while(returnCode != VO_ERR_INPUT_BUFFER_SMALL);
+ } while((unsigned)returnCode != VO_ERR_INPUT_BUFFER_SMALL);
finish = clock();
duration += finish - start;
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
index c203f77..65d69a2 100644
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
@@ -5,17 +5,20 @@
AMRWB_E_SAMPLE.c \
../../common/cmnMemory.c
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := AMRWBEncTest
LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -DLINUX
+LOCAL_CFLAGS :=
LOCAL_SHARED_LIBRARIES := \
libstagefright \
libdl
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_amrwbenc
+
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/ \
$(LOCAL_PATH)/../../common \
diff --git a/media/libstagefright/codecs/amrwbenc/inc/acelp.h b/media/libstagefright/codecs/amrwbenc/inc/acelp.h
index 5a1e536..97555d5 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/acelp.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/acelp.h
@@ -18,7 +18,7 @@
/*--------------------------------------------------------------------------*
* ACELP.H *
*--------------------------------------------------------------------------*
- * Function *
+ * Function *
*--------------------------------------------------------------------------*/
#ifndef __ACELP_H__
#define __ACELP_H__
@@ -33,68 +33,68 @@
Word16 median5(Word16 x[]);
void Autocorr(
- Word16 x[], /* (i) : Input signal */
- Word16 m, /* (i) : LPC order */
- Word16 r_h[], /* (o) : Autocorrelations (msb) */
- Word16 r_l[] /* (o) : Autocorrelations (lsb) */
- );
+ Word16 x[], /* (i) : Input signal */
+ Word16 m, /* (i) : LPC order */
+ Word16 r_h[], /* (o) : Autocorrelations (msb) */
+ Word16 r_l[] /* (o) : Autocorrelations (lsb) */
+ );
void Lag_window(
- Word16 r_h[], /* (i/o) : Autocorrelations (msb) */
- Word16 r_l[] /* (i/o) : Autocorrelations (lsb) */
- );
+ Word16 r_h[], /* (i/o) : Autocorrelations (msb) */
+ Word16 r_l[] /* (i/o) : Autocorrelations (lsb) */
+ );
void Init_Levinson(
- Word16 * mem /* output :static memory (18 words) */
- );
+ Word16 * mem /* output :static memory (18 words) */
+ );
void Levinson(
- Word16 Rh[], /* (i) : Rh[M+1] Vector of autocorrelations (msb) */
- Word16 Rl[], /* (i) : Rl[M+1] Vector of autocorrelations (lsb) */
- Word16 A[], /* (o) Q12 : A[M] LPC coefficients (m = 16) */
- Word16 rc[], /* (o) Q15 : rc[M] Reflection coefficients. */
- Word16 * mem /* (i/o) :static memory (18 words) */
- );
+ Word16 Rh[], /* (i) : Rh[M+1] Vector of autocorrelations (msb) */
+ Word16 Rl[], /* (i) : Rl[M+1] Vector of autocorrelations (lsb) */
+ Word16 A[], /* (o) Q12 : A[M] LPC coefficients (m = 16) */
+ Word16 rc[], /* (o) Q15 : rc[M] Reflection coefficients. */
+ Word16 * mem /* (i/o) :static memory (18 words) */
+ );
void Az_isp(
- Word16 a[], /* (i) Q12 : predictor coefficients */
- Word16 isp[], /* (o) Q15 : Immittance spectral pairs */
- Word16 old_isp[] /* (i) : old isp[] (in case not found M roots) */
- );
+ Word16 a[], /* (i) Q12 : predictor coefficients */
+ Word16 isp[], /* (o) Q15 : Immittance spectral pairs */
+ Word16 old_isp[] /* (i) : old isp[] (in case not found M roots) */
+ );
void Isp_Az(
- Word16 isp[], /* (i) Q15 : Immittance spectral pairs */
- Word16 a[], /* (o) Q12 : predictor coefficients (order = M) */
- Word16 m,
- Word16 adaptive_scaling /* (i) 0 : adaptive scaling disabled */
- /* 1 : adaptive scaling enabled */
- );
+ Word16 isp[], /* (i) Q15 : Immittance spectral pairs */
+ Word16 a[], /* (o) Q12 : predictor coefficients (order = M) */
+ Word16 m,
+ Word16 adaptive_scaling /* (i) 0 : adaptive scaling disabled */
+ /* 1 : adaptive scaling enabled */
+ );
void Isp_isf(
- Word16 isp[], /* (i) Q15 : isp[m] (range: -1<=val<1) */
- Word16 isf[], /* (o) Q15 : isf[m] normalized (range: 0.0<=val<=0.5) */
- Word16 m /* (i) : LPC order */
- );
+ Word16 isp[], /* (i) Q15 : isp[m] (range: -1<=val<1) */
+ Word16 isf[], /* (o) Q15 : isf[m] normalized (range: 0.0<=val<=0.5) */
+ Word16 m /* (i) : LPC order */
+ );
void Isf_isp(
- Word16 isf[], /* (i) Q15 : isf[m] normalized (range: 0.0<=val<=0.5) */
- Word16 isp[], /* (o) Q15 : isp[m] (range: -1<=val<1) */
- Word16 m /* (i) : LPC order */
- );
+ Word16 isf[], /* (i) Q15 : isf[m] normalized (range: 0.0<=val<=0.5) */
+ Word16 isp[], /* (o) Q15 : isp[m] (range: -1<=val<1) */
+ Word16 m /* (i) : LPC order */
+ );
void Int_isp(
- Word16 isp_old[], /* input : isps from past frame */
- Word16 isp_new[], /* input : isps from present frame */
- Word16 frac[], /* input : fraction for 3 first subfr (Q15) */
- Word16 Az[] /* output: LP coefficients in 4 subframes */
- );
+ Word16 isp_old[], /* input : isps from past frame */
+ Word16 isp_new[], /* input : isps from present frame */
+ Word16 frac[], /* input : fraction for 3 first subfr (Q15) */
+ Word16 Az[] /* output: LP coefficients in 4 subframes */
+ );
void Weight_a(
- Word16 a[], /* (i) Q12 : a[m+1] LPC coefficients */
- Word16 ap[], /* (o) Q12 : Spectral expanded LPC coefficients */
- Word16 gamma, /* (i) Q15 : Spectral expansion factor. */
- Word16 m /* (i) : LPC order. */
- );
+ Word16 a[], /* (i) Q12 : a[m+1] LPC coefficients */
+ Word16 ap[], /* (o) Q12 : Spectral expanded LPC coefficients */
+ Word16 gamma, /* (i) Q15 : Spectral expansion factor. */
+ Word16 m /* (i) : LPC order. */
+ );
/*-----------------------------------------------------------------*
@@ -102,214 +102,214 @@
*-----------------------------------------------------------------*/
void Qpisf_2s_46b(
- Word16 * isf1, /* (i) Q15 : ISF in the frequency domain (0..0.5) */
- Word16 * isf_q, /* (o) Q15 : quantized ISF (0..0.5) */
- Word16 * past_isfq, /* (io)Q15 : past ISF quantizer */
- Word16 * indice, /* (o) : quantization indices */
- Word16 nb_surv /* (i) : number of survivor (1, 2, 3 or 4) */
- );
+ Word16 * isf1, /* (i) Q15 : ISF in the frequency domain (0..0.5) */
+ Word16 * isf_q, /* (o) Q15 : quantized ISF (0..0.5) */
+ Word16 * past_isfq, /* (io)Q15 : past ISF quantizer */
+ Word16 * indice, /* (o) : quantization indices */
+ Word16 nb_surv /* (i) : number of survivor (1, 2, 3 or 4) */
+ );
void Qpisf_2s_36b(
- Word16 * isf1, /* (i) Q15 : ISF in the frequency domain (0..0.5) */
- Word16 * isf_q, /* (o) Q15 : quantized ISF (0..0.5) */
- Word16 * past_isfq, /* (io)Q15 : past ISF quantizer */
- Word16 * indice, /* (o) : quantization indices */
- Word16 nb_surv /* (i) : number of survivor (1, 2, 3 or 4) */
- );
+ Word16 * isf1, /* (i) Q15 : ISF in the frequency domain (0..0.5) */
+ Word16 * isf_q, /* (o) Q15 : quantized ISF (0..0.5) */
+ Word16 * past_isfq, /* (io)Q15 : past ISF quantizer */
+ Word16 * indice, /* (o) : quantization indices */
+ Word16 nb_surv /* (i) : number of survivor (1, 2, 3 or 4) */
+ );
void Dpisf_2s_46b(
- Word16 * indice, /* input: quantization indices */
- Word16 * isf_q, /* output: quantized ISF in frequency domain (0..0.5) */
- Word16 * past_isfq, /* i/0 : past ISF quantizer */
- Word16 * isfold, /* input : past quantized ISF */
- Word16 * isf_buf, /* input : isf buffer */
- Word16 bfi, /* input : Bad frame indicator */
- Word16 enc_dec
- );
+ Word16 * indice, /* input: quantization indices */
+ Word16 * isf_q, /* output: quantized ISF in frequency domain (0..0.5) */
+ Word16 * past_isfq, /* i/0 : past ISF quantizer */
+ Word16 * isfold, /* input : past quantized ISF */
+ Word16 * isf_buf, /* input : isf buffer */
+ Word16 bfi, /* input : Bad frame indicator */
+ Word16 enc_dec
+ );
void Dpisf_2s_36b(
- Word16 * indice, /* input: quantization indices */
- Word16 * isf_q, /* output: quantized ISF in frequency domain (0..0.5) */
- Word16 * past_isfq, /* i/0 : past ISF quantizer */
- Word16 * isfold, /* input : past quantized ISF */
- Word16 * isf_buf, /* input : isf buffer */
- Word16 bfi, /* input : Bad frame indicator */
- Word16 enc_dec
- );
+ Word16 * indice, /* input: quantization indices */
+ Word16 * isf_q, /* output: quantized ISF in frequency domain (0..0.5) */
+ Word16 * past_isfq, /* i/0 : past ISF quantizer */
+ Word16 * isfold, /* input : past quantized ISF */
+ Word16 * isf_buf, /* input : isf buffer */
+ Word16 bfi, /* input : Bad frame indicator */
+ Word16 enc_dec
+ );
void Qisf_ns(
- Word16 * isf1, /* input : ISF in the frequency domain (0..0.5) */
- Word16 * isf_q, /* output: quantized ISF */
- Word16 * indice /* output: quantization indices */
- );
+ Word16 * isf1, /* input : ISF in the frequency domain (0..0.5) */
+ Word16 * isf_q, /* output: quantized ISF */
+ Word16 * indice /* output: quantization indices */
+ );
void Disf_ns(
- Word16 * indice, /* input: quantization indices */
- Word16 * isf_q /* input : ISF in the frequency domain (0..0.5) */
- );
+ Word16 * indice, /* input: quantization indices */
+ Word16 * isf_q /* input : ISF in the frequency domain (0..0.5) */
+ );
Word16 Sub_VQ( /* output: return quantization index */
- Word16 * x, /* input : ISF residual vector */
- Word16 * dico, /* input : quantization codebook */
- Word16 dim, /* input : dimention of vector */
- Word16 dico_size, /* input : size of quantization codebook */
- Word32 * distance /* output: error of quantization */
- );
+ Word16 * x, /* input : ISF residual vector */
+ Word16 * dico, /* input : quantization codebook */
+ Word16 dim, /* input : dimention of vector */
+ Word16 dico_size, /* input : size of quantization codebook */
+ Word32 * distance /* output: error of quantization */
+ );
void Reorder_isf(
- Word16 * isf, /* (i/o) Q15: ISF in the frequency domain (0..0.5) */
- Word16 min_dist, /* (i) Q15 : minimum distance to keep */
- Word16 n /* (i) : number of ISF */
- );
+ Word16 * isf, /* (i/o) Q15: ISF in the frequency domain (0..0.5) */
+ Word16 min_dist, /* (i) Q15 : minimum distance to keep */
+ Word16 n /* (i) : number of ISF */
+ );
/*-----------------------------------------------------------------*
* filter prototypes *
*-----------------------------------------------------------------*/
void Init_Decim_12k8(
- Word16 mem[] /* output: memory (2*NB_COEF_DOWN) set to zeros */
- );
+ Word16 mem[] /* output: memory (2*NB_COEF_DOWN) set to zeros */
+ );
void Decim_12k8(
- Word16 sig16k[], /* input: signal to downsampling */
- Word16 lg, /* input: length of input */
- Word16 sig12k8[], /* output: decimated signal */
- Word16 mem[] /* in/out: memory (2*NB_COEF_DOWN) */
- );
+ Word16 sig16k[], /* input: signal to downsampling */
+ Word16 lg, /* input: length of input */
+ Word16 sig12k8[], /* output: decimated signal */
+ Word16 mem[] /* in/out: memory (2*NB_COEF_DOWN) */
+ );
void Init_HP50_12k8(Word16 mem[]);
void HP50_12k8(
- Word16 signal[], /* input/output signal */
- Word16 lg, /* lenght of signal */
- Word16 mem[] /* filter memory [6] */
- );
+ Word16 signal[], /* input/output signal */
+ Word16 lg, /* lenght of signal */
+ Word16 mem[] /* filter memory [6] */
+ );
void Init_HP400_12k8(Word16 mem[]);
void HP400_12k8(
- Word16 signal[], /* input/output signal */
- Word16 lg, /* lenght of signal */
- Word16 mem[] /* filter memory [6] */
- );
+ Word16 signal[], /* input/output signal */
+ Word16 lg, /* lenght of signal */
+ Word16 mem[] /* filter memory [6] */
+ );
void Init_Filt_6k_7k(Word16 mem[]);
void Filt_6k_7k(
- Word16 signal[], /* input: signal */
- Word16 lg, /* input: length of input */
- Word16 mem[] /* in/out: memory (size=30) */
- );
+ Word16 signal[], /* input: signal */
+ Word16 lg, /* input: length of input */
+ Word16 mem[] /* in/out: memory (size=30) */
+ );
void Filt_6k_7k_asm(
- Word16 signal[], /* input: signal */
- Word16 lg, /* input: length of input */
- Word16 mem[] /* in/out: memory (size=30) */
- );
+ Word16 signal[], /* input: signal */
+ Word16 lg, /* input: length of input */
+ Word16 mem[] /* in/out: memory (size=30) */
+ );
void LP_Decim2(
- Word16 x[], /* in/out: signal to process */
- Word16 l, /* input : size of filtering */
- Word16 mem[] /* in/out: memory (size=3) */
- );
+ Word16 x[], /* in/out: signal to process */
+ Word16 l, /* input : size of filtering */
+ Word16 mem[] /* in/out: memory (size=3) */
+ );
void Preemph(
- Word16 x[], /* (i/o) : input signal overwritten by the output */
- Word16 mu, /* (i) Q15 : preemphasis coefficient */
- Word16 lg, /* (i) : lenght of filtering */
- Word16 * mem /* (i/o) : memory (x[-1]) */
- );
+ Word16 x[], /* (i/o) : input signal overwritten by the output */
+ Word16 mu, /* (i) Q15 : preemphasis coefficient */
+ Word16 lg, /* (i) : lenght of filtering */
+ Word16 * mem /* (i/o) : memory (x[-1]) */
+ );
void Preemph2(
- Word16 x[], /* (i/o) : input signal overwritten by the output */
- Word16 mu, /* (i) Q15 : preemphasis coefficient */
- Word16 lg, /* (i) : lenght of filtering */
- Word16 * mem /* (i/o) : memory (x[-1]) */
- );
+ Word16 x[], /* (i/o) : input signal overwritten by the output */
+ Word16 mu, /* (i) Q15 : preemphasis coefficient */
+ Word16 lg, /* (i) : lenght of filtering */
+ Word16 * mem /* (i/o) : memory (x[-1]) */
+ );
void Deemph(
- Word16 x[], /* (i/o) : input signal overwritten by the output */
- Word16 mu, /* (i) Q15 : deemphasis factor */
- Word16 L, /* (i) : vector size */
- Word16 * mem /* (i/o) : memory (y[-1]) */
- );
+ Word16 x[], /* (i/o) : input signal overwritten by the output */
+ Word16 mu, /* (i) Q15 : deemphasis factor */
+ Word16 L, /* (i) : vector size */
+ Word16 * mem /* (i/o) : memory (y[-1]) */
+ );
void Deemph2(
- Word16 x[], /* (i/o) : input signal overwritten by the output */
- Word16 mu, /* (i) Q15 : deemphasis factor */
- Word16 L, /* (i) : vector size */
- Word16 * mem /* (i/o) : memory (y[-1]) */
- );
+ Word16 x[], /* (i/o) : input signal overwritten by the output */
+ Word16 mu, /* (i) Q15 : deemphasis factor */
+ Word16 L, /* (i) : vector size */
+ Word16 * mem /* (i/o) : memory (y[-1]) */
+ );
void Deemph_32(
- Word16 x_hi[], /* (i) : input signal (bit31..16) */
- Word16 x_lo[], /* (i) : input signal (bit15..4) */
- Word16 y[], /* (o) : output signal (x16) */
- Word16 mu, /* (i) Q15 : deemphasis factor */
- Word16 L, /* (i) : vector size */
- Word16 * mem /* (i/o) : memory (y[-1]) */
- );
+ Word16 x_hi[], /* (i) : input signal (bit31..16) */
+ Word16 x_lo[], /* (i) : input signal (bit15..4) */
+ Word16 y[], /* (o) : output signal (x16) */
+ Word16 mu, /* (i) Q15 : deemphasis factor */
+ Word16 L, /* (i) : vector size */
+ Word16 * mem /* (i/o) : memory (y[-1]) */
+ );
void Deemph_32_asm(
- Word16 x_hi[], /* (i) : input signal (bit31..16) */
- Word16 x_lo[], /* (i) : input signal (bit15..4) */
- Word16 y[], /* (o) : output signal (x16) */
- Word16 * mem /* (i/o) : memory (y[-1]) */
- );
+ Word16 x_hi[], /* (i) : input signal (bit31..16) */
+ Word16 x_lo[], /* (i) : input signal (bit15..4) */
+ Word16 y[], /* (o) : output signal (x16) */
+ Word16 * mem /* (i/o) : memory (y[-1]) */
+ );
void Convolve(
- Word16 x[], /* (i) : input vector */
- Word16 h[], /* (i) Q15 : impulse response */
- Word16 y[], /* (o) 12 bits: output vector */
- Word16 L /* (i) : vector size */
- );
+ Word16 x[], /* (i) : input vector */
+ Word16 h[], /* (i) Q15 : impulse response */
+ Word16 y[], /* (o) 12 bits: output vector */
+ Word16 L /* (i) : vector size */
+ );
void Convolve_asm(
- Word16 x[], /* (i) : input vector */
- Word16 h[], /* (i) Q15 : impulse response */
- Word16 y[], /* (o) 12 bits: output vector */
- Word16 L /* (i) : vector size */
- );
+ Word16 x[], /* (i) : input vector */
+ Word16 h[], /* (i) Q15 : impulse response */
+ Word16 y[], /* (o) 12 bits: output vector */
+ Word16 L /* (i) : vector size */
+ );
void Residu(
- Word16 a[], /* (i) Q12 : prediction coefficients */
- Word16 x[], /* (i) : speech (values x[-m..-1] are needed */
- Word16 y[], /* (o) : residual signal */
- Word16 lg /* (i) : size of filtering */
- );
+ Word16 a[], /* (i) Q12 : prediction coefficients */
+ Word16 x[], /* (i) : speech (values x[-m..-1] are needed */
+ Word16 y[], /* (o) : residual signal */
+ Word16 lg /* (i) : size of filtering */
+ );
void Residu_opt(
- Word16 a[], /* (i) Q12 : prediction coefficients */
- Word16 x[], /* (i) : speech (values x[-m..-1] are needed */
- Word16 y[], /* (o) : residual signal */
- Word16 lg /* (i) : size of filtering */
- );
+ Word16 a[], /* (i) Q12 : prediction coefficients */
+ Word16 x[], /* (i) : speech (values x[-m..-1] are needed */
+ Word16 y[], /* (o) : residual signal */
+ Word16 lg /* (i) : size of filtering */
+ );
void Syn_filt(
- Word16 a[], /* (i) Q12 : a[m+1] prediction coefficients */
- Word16 x[], /* (i) : input signal */
- Word16 y[], /* (o) : output signal */
- Word16 lg, /* (i) : size of filtering */
- Word16 mem[], /* (i/o) : memory associated with this filtering. */
- Word16 update /* (i) : 0=no update, 1=update of memory. */
- );
+ Word16 a[], /* (i) Q12 : a[m+1] prediction coefficients */
+ Word16 x[], /* (i) : input signal */
+ Word16 y[], /* (o) : output signal */
+ Word16 lg, /* (i) : size of filtering */
+ Word16 mem[], /* (i/o) : memory associated with this filtering. */
+ Word16 update /* (i) : 0=no update, 1=update of memory. */
+ );
void Syn_filt_asm(
- Word16 a[], /* (i) Q12 : a[m+1] prediction coefficients */
- Word16 x[], /* (i) : input signal */
- Word16 y[], /* (o) : output signal */
- Word16 mem[] /* (i/o) : memory associated with this filtering. */
- );
+ Word16 a[], /* (i) Q12 : a[m+1] prediction coefficients */
+ Word16 x[], /* (i) : input signal */
+ Word16 y[], /* (o) : output signal */
+ Word16 mem[] /* (i/o) : memory associated with this filtering. */
+ );
void Syn_filt_32(
- Word16 a[], /* (i) Q12 : a[m+1] prediction coefficients */
- Word16 m, /* (i) : order of LP filter */
- Word16 exc[], /* (i) Qnew: excitation (exc[i] >> Qnew) */
- Word16 Qnew, /* (i) : exc scaling = 0(min) to 8(max) */
- Word16 sig_hi[], /* (o) /16 : synthesis high */
- Word16 sig_lo[], /* (o) /16 : synthesis low */
- Word16 lg /* (i) : size of filtering */
- );
+ Word16 a[], /* (i) Q12 : a[m+1] prediction coefficients */
+ Word16 m, /* (i) : order of LP filter */
+ Word16 exc[], /* (i) Qnew: excitation (exc[i] >> Qnew) */
+ Word16 Qnew, /* (i) : exc scaling = 0(min) to 8(max) */
+ Word16 sig_hi[], /* (o) /16 : synthesis high */
+ Word16 sig_lo[], /* (o) /16 : synthesis low */
+ Word16 lg /* (i) : size of filtering */
+ );
void Syn_filt_32_asm(
- Word16 a[], /* (i) Q12 : a[m+1] prediction coefficients */
- Word16 m, /* (i) : order of LP filter */
- Word16 exc[], /* (i) Qnew: excitation (exc[i] >> Qnew) */
- Word16 Qnew, /* (i) : exc scaling = 0(min) to 8(max) */
- Word16 sig_hi[], /* (o) /16 : synthesis high */
- Word16 sig_lo[], /* (o) /16 : synthesis low */
- Word16 lg /* (i) : size of filtering */
- );
+ Word16 a[], /* (i) Q12 : a[m+1] prediction coefficients */
+ Word16 m, /* (i) : order of LP filter */
+ Word16 exc[], /* (i) Qnew: excitation (exc[i] >> Qnew) */
+ Word16 Qnew, /* (i) : exc scaling = 0(min) to 8(max) */
+ Word16 sig_hi[], /* (o) /16 : synthesis high */
+ Word16 sig_lo[], /* (o) /16 : synthesis low */
+ Word16 lg /* (i) : size of filtering */
+ );
/*-----------------------------------------------------------------*
* pitch prototypes *
*-----------------------------------------------------------------*/
@@ -443,12 +443,12 @@
Word16 nbbits, /* (i) : 20, 36, 44, 52, 64, 72 or 88 bits */
Word16 ser_size, /* (i) : bit rate */
Word16 _index[] /* (o) : index (20): 5+5+5+5 = 20 bits. */
- /* (o) : index (36): 9+9+9+9 = 36 bits. */
- /* (o) : index (44): 13+9+13+9 = 44 bits. */
- /* (o) : index (52): 13+13+13+13 = 52 bits. */
- /* (o) : index (64): 2+2+2+2+14+14+14+14 = 64 bits. */
- /* (o) : index (72): 10+2+10+2+10+14+10+14 = 72 bits. */
- /* (o) : index (88): 11+11+11+11+11+11+11+11 = 88 bits. */
+ /* (o) : index (36): 9+9+9+9 = 36 bits. */
+ /* (o) : index (44): 13+9+13+9 = 44 bits. */
+ /* (o) : index (52): 13+13+13+13 = 52 bits. */
+ /* (o) : index (64): 2+2+2+2+14+14+14+14 = 64 bits. */
+ /* (o) : index (72): 10+2+10+2+10+14+10+14 = 72 bits. */
+ /* (o) : index (88): 11+11+11+11+11+11+11+11 = 88 bits. */
);
void Pit_shrp(
diff --git a/media/libstagefright/codecs/amrwbenc/inc/basic_op.h b/media/libstagefright/codecs/amrwbenc/inc/basic_op.h
index f42a27c..db3e058 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/basic_op.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/basic_op.h
@@ -25,8 +25,8 @@
#define MAX_32 (Word32)0x7fffffffL
#define MIN_32 (Word32)0x80000000L
-#define MAX_16 (Word16)+32767 /* 0x7fff */
-#define MIN_16 (Word16)-32768 /* 0x8000 */
+#define MAX_16 (Word16)+32767 /* 0x7fff */
+#define MIN_16 (Word16)-32768 /* 0x8000 */
#define static_vo static __inline
@@ -41,22 +41,22 @@
#define L_negate(L_var1) (((L_var1) == (MIN_32)) ? (MAX_32) : (-(L_var1))) /* Long negate, 2*/
-#define extract_h(a) ((Word16)(a >> 16))
-#define extract_l(x) (Word16)((x))
-#define add1(a,b) (a + b)
-#define vo_L_msu(a,b,c) ( a - (( b * c ) << 1) )
+#define extract_h(a) ((Word16)(a >> 16))
+#define extract_l(x) (Word16)((x))
+#define add1(a,b) (a + b)
+#define vo_L_msu(a,b,c) ( a - (( b * c ) << 1) )
#define vo_mult32(a, b) ((a) * (b))
-#define vo_mult(a,b) (( a * b ) >> 15 )
-#define vo_L_mult(a,b) (((a) * (b)) << 1)
-#define vo_shr_r(var1, var2) ((var1+((Word16)(1L<<(var2-1))))>>var2)
-#define vo_sub(a,b) (a - b)
-#define vo_L_deposit_h(a) ((Word32)((a) << 16))
-#define vo_round(a) ((a + 0x00008000) >> 16)
-#define vo_extract_l(a) ((Word16)(a))
-#define vo_L_add(a,b) (a + b)
-#define vo_L_sub(a,b) (a - b)
-#define vo_mult_r(a,b) ((( a * b ) + 0x4000 ) >> 15 )
-#define vo_negate(a) (-a)
+#define vo_mult(a,b) (( a * b ) >> 15 )
+#define vo_L_mult(a,b) (((a) * (b)) << 1)
+#define vo_shr_r(var1, var2) ((var1+((Word16)(1L<<(var2-1))))>>var2)
+#define vo_sub(a,b) (a - b)
+#define vo_L_deposit_h(a) ((Word32)((a) << 16))
+#define vo_round(a) ((a + 0x00008000) >> 16)
+#define vo_extract_l(a) ((Word16)(a))
+#define vo_L_add(a,b) (a + b)
+#define vo_L_sub(a,b) (a - b)
+#define vo_mult_r(a,b) ((( a * b ) + 0x4000 ) >> 15 )
+#define vo_negate(a) (-a)
#define vo_L_shr_r(L_var1, var2) ((L_var1+((Word32)(1L<<(var2-1))))>>var2)
@@ -65,25 +65,25 @@
| Prototypes for basic arithmetic operators |
|___________________________________________________________________________|
*/
-static_vo Word16 add (Word16 var1, Word16 var2); /* Short add,1 */
-static_vo Word16 sub (Word16 var1, Word16 var2); /* Short sub,1 */
+static_vo Word16 add (Word16 var1, Word16 var2); /* Short add,1 */
+static_vo Word16 sub (Word16 var1, Word16 var2); /* Short sub,1 */
static_vo Word16 shl (Word16 var1, Word16 var2); /* Short shift left, 1 */
static_vo Word16 shr (Word16 var1, Word16 var2); /* Short shift right, 1 */
static_vo Word16 mult (Word16 var1, Word16 var2); /* Short mult, 1 */
static_vo Word32 L_mult (Word16 var1, Word16 var2); /* Long mult, 1 */
static_vo Word16 voround (Word32 L_var1); /* Round, 1 */
-static_vo Word32 L_mac (Word32 L_var3, Word16 var1, Word16 var2); /* Mac, 1 */
-static_vo Word32 L_msu (Word32 L_var3, Word16 var1, Word16 var2); /* Msu, 1 */
-static_vo Word32 L_add (Word32 L_var1, Word32 L_var2); /* Long add, 2 */
-static_vo Word32 L_sub (Word32 L_var1, Word32 L_var2); /* Long sub, 2 */
-static_vo Word16 mult_r (Word16 var1, Word16 var2); /* Mult with round, 2 */
-static_vo Word32 L_shl2(Word32 L_var1, Word16 var2); /* var2 > 0*/
-static_vo Word32 L_shl (Word32 L_var1, Word16 var2); /* Long shift left, 2 */
-static_vo Word32 L_shr (Word32 L_var1, Word16 var2); /* Long shift right, 2*/
-static_vo Word32 L_shr_r (Word32 L_var1, Word16 var2); /* Long shift right with round, 3 */
-static_vo Word16 norm_s (Word16 var1); /* Short norm, 15 */
-static_vo Word16 div_s (Word16 var1, Word16 var2); /* Short division, 18 */
-static_vo Word16 norm_l (Word32 L_var1); /* Long norm, 30 */
+static_vo Word32 L_mac (Word32 L_var3, Word16 var1, Word16 var2); /* Mac, 1 */
+static_vo Word32 L_msu (Word32 L_var3, Word16 var1, Word16 var2); /* Msu, 1 */
+static_vo Word32 L_add (Word32 L_var1, Word32 L_var2); /* Long add, 2 */
+static_vo Word32 L_sub (Word32 L_var1, Word32 L_var2); /* Long sub, 2 */
+static_vo Word16 mult_r (Word16 var1, Word16 var2); /* Mult with round, 2 */
+static_vo Word32 L_shl2(Word32 L_var1, Word16 var2); /* var2 > 0*/
+static_vo Word32 L_shl (Word32 L_var1, Word16 var2); /* Long shift left, 2 */
+static_vo Word32 L_shr (Word32 L_var1, Word16 var2); /* Long shift right, 2*/
+static_vo Word32 L_shr_r (Word32 L_var1, Word16 var2); /* Long shift right with round, 3 */
+static_vo Word16 norm_s (Word16 var1); /* Short norm, 15 */
+static_vo Word16 div_s (Word16 var1, Word16 var2); /* Short division, 18 */
+static_vo Word16 norm_l (Word32 L_var1); /* Long norm, 30 */
/*___________________________________________________________________________
| |
@@ -125,11 +125,11 @@
*/
static_vo Word16 add (Word16 var1, Word16 var2)
{
- Word16 var_out;
- Word32 L_sum;
- L_sum = (Word32) var1 + var2;
- var_out = saturate (L_sum);
- return (var_out);
+ Word16 var_out;
+ Word32 L_sum;
+ L_sum = (Word32) var1 + var2;
+ var_out = saturate (L_sum);
+ return (var_out);
}
/*___________________________________________________________________________
@@ -168,11 +168,11 @@
static_vo Word16 sub (Word16 var1, Word16 var2)
{
- Word16 var_out;
- Word32 L_diff;
- L_diff = (Word32) var1 - var2;
- var_out = saturate (L_diff);
- return (var_out);
+ Word16 var_out;
+ Word32 L_diff;
+ L_diff = (Word32) var1 - var2;
+ var_out = saturate (L_diff);
+ return (var_out);
}
/*___________________________________________________________________________
@@ -212,27 +212,31 @@
static_vo Word16 shl (Word16 var1, Word16 var2)
{
- Word16 var_out;
- Word32 result;
- if (var2 < 0)
- {
- if (var2 < -16)
- var2 = -16;
- var_out = var1 >> ((Word16)-var2);
- }
- else
- {
- result = (Word32) var1 *((Word32) 1 << var2);
- if ((var2 > 15 && var1 != 0) || (result != (Word32) ((Word16) result)))
- {
- var_out = (Word16)((var1 > 0) ? MAX_16 : MIN_16);
- }
- else
- {
- var_out = extract_l (result);
- }
- }
- return (var_out);
+ Word16 var_out;
+ Word32 result;
+ if (var2 < 0)
+ {
+ if (var2 < -16)
+ var2 = -16;
+ var_out = var1 >> ((Word16)-var2);
+ }
+ else
+ {
+ if (var2 > 15 && var1 != 0)
+ {
+ var_out = (Word16)((var1 > 0) ? MAX_16 : MIN_16);
+ }
+ else
+ {
+ result = (Word32) var1 *((Word32) 1 << var2);
+ if ((result != (Word32) ((Word16) result))) {
+ var_out = (Word16)((var1 > 0) ? MAX_16 : MIN_16);
+ } else {
+ var_out = extract_l (result);
+ }
+ }
+ }
+ return (var_out);
}
/*___________________________________________________________________________
@@ -272,32 +276,32 @@
static_vo Word16 shr (Word16 var1, Word16 var2)
{
- Word16 var_out;
- if (var2 < 0)
- {
- if (var2 < -16)
- var2 = -16;
- var_out = shl(var1, (Word16)-var2);
- }
- else
- {
- if (var2 >= 15)
- {
- var_out = (Word16)((var1 < 0) ? -1 : 0);
- }
- else
- {
- if (var1 < 0)
- {
- var_out = (Word16)(~((~var1) >> var2));
- }
- else
- {
- var_out = (Word16)(var1 >> var2);
- }
- }
- }
- return (var_out);
+ Word16 var_out;
+ if (var2 < 0)
+ {
+ if (var2 < -16)
+ var2 = -16;
+ var_out = shl(var1, (Word16)-var2);
+ }
+ else
+ {
+ if (var2 >= 15)
+ {
+ var_out = (Word16)((var1 < 0) ? -1 : 0);
+ }
+ else
+ {
+ if (var1 < 0)
+ {
+ var_out = (Word16)(~((~var1) >> var2));
+ }
+ else
+ {
+ var_out = (Word16)(var1 >> var2);
+ }
+ }
+ }
+ return (var_out);
}
/*___________________________________________________________________________
@@ -337,14 +341,14 @@
static_vo Word16 mult (Word16 var1, Word16 var2)
{
- Word16 var_out;
- Word32 L_product;
- L_product = (Word32) var1 *(Word32) var2;
- L_product = (L_product & (Word32) 0xffff8000L) >> 15;
- if (L_product & (Word32) 0x00010000L)
- L_product = L_product | (Word32) 0xffff0000L;
- var_out = saturate (L_product);
- return (var_out);
+ Word16 var_out;
+ Word32 L_product;
+ L_product = (Word32) var1 *(Word32) var2;
+ L_product = (L_product & (Word32) 0xffff8000L) >> 15;
+ if (L_product & (Word32) 0x00010000L)
+ L_product = L_product | (Word32) 0xffff0000L;
+ var_out = saturate (L_product);
+ return (var_out);
}
/*___________________________________________________________________________
@@ -384,17 +388,17 @@
static_vo Word32 L_mult (Word16 var1, Word16 var2)
{
- Word32 L_var_out;
- L_var_out = (Word32) var1 *(Word32) var2;
- if (L_var_out != (Word32) 0x40000000L)
- {
- L_var_out *= 2;
- }
- else
- {
- L_var_out = MAX_32;
- }
- return (L_var_out);
+ Word32 L_var_out;
+ L_var_out = (Word32) var1 *(Word32) var2;
+ if (L_var_out != (Word32) 0x40000000L)
+ {
+ L_var_out *= 2;
+ }
+ else
+ {
+ L_var_out = MAX_32;
+ }
+ return (L_var_out);
}
/*___________________________________________________________________________
@@ -430,11 +434,11 @@
static_vo Word16 voround (Word32 L_var1)
{
- Word16 var_out;
- Word32 L_rounded;
- L_rounded = L_add (L_var1, (Word32) 0x00008000L);
- var_out = extract_h (L_rounded);
- return (var_out);
+ Word16 var_out;
+ Word32 L_rounded;
+ L_rounded = L_add (L_var1, (Word32) 0x00008000L);
+ var_out = extract_h (L_rounded);
+ return (var_out);
}
/*___________________________________________________________________________
@@ -476,11 +480,11 @@
static_vo Word32 L_mac (Word32 L_var3, Word16 var1, Word16 var2)
{
- Word32 L_var_out;
- Word32 L_product;
- L_product = ((var1 * var2) << 1);
- L_var_out = L_add (L_var3, L_product);
- return (L_var_out);
+ Word32 L_var_out;
+ Word32 L_product;
+ L_product = ((var1 * var2) << 1);
+ L_var_out = L_add (L_var3, L_product);
+ return (L_var_out);
}
/*___________________________________________________________________________
@@ -522,11 +526,11 @@
static_vo Word32 L_msu (Word32 L_var3, Word16 var1, Word16 var2)
{
- Word32 L_var_out;
- Word32 L_product;
- L_product = (var1 * var2)<<1;
- L_var_out = L_sub (L_var3, L_product);
- return (L_var_out);
+ Word32 L_var_out;
+ Word32 L_product;
+ L_product = (var1 * var2)<<1;
+ L_var_out = L_sub (L_var3, L_product);
+ return (L_var_out);
}
/*___________________________________________________________________________
@@ -561,18 +565,19 @@
|___________________________________________________________________________|
*/
+__attribute__((no_sanitize("integer")))
static_vo Word32 L_add (Word32 L_var1, Word32 L_var2)
{
- Word32 L_var_out;
- L_var_out = L_var1 + L_var2;
- if (((L_var1 ^ L_var2) & MIN_32) == 0)
- {
- if ((L_var_out ^ L_var1) & MIN_32)
- {
- L_var_out = (L_var1 < 0) ? MIN_32 : MAX_32;
- }
- }
- return (L_var_out);
+ Word32 L_var_out;
+ L_var_out = L_var1 + L_var2;
+ if (((L_var1 ^ L_var2) & MIN_32) == 0)
+ {
+ if ((L_var_out ^ L_var1) & MIN_32)
+ {
+ L_var_out = (L_var1 < 0) ? MIN_32 : MAX_32;
+ }
+ }
+ return (L_var_out);
}
/*___________________________________________________________________________
@@ -607,18 +612,19 @@
|___________________________________________________________________________|
*/
+__attribute__((no_sanitize("integer")))
static_vo Word32 L_sub (Word32 L_var1, Word32 L_var2)
{
- Word32 L_var_out;
- L_var_out = L_var1 - L_var2;
- if (((L_var1 ^ L_var2) & MIN_32) != 0)
- {
- if ((L_var_out ^ L_var1) & MIN_32)
- {
- L_var_out = (L_var1 < 0L) ? MIN_32 : MAX_32;
- }
- }
- return (L_var_out);
+ Word32 L_var_out;
+ L_var_out = L_var1 - L_var2;
+ if (((L_var1 ^ L_var2) & MIN_32) != 0)
+ {
+ if ((L_var_out ^ L_var1) & MIN_32)
+ {
+ L_var_out = (L_var1 < 0L) ? MIN_32 : MAX_32;
+ }
+ }
+ return (L_var_out);
}
@@ -658,18 +664,18 @@
static_vo Word16 mult_r (Word16 var1, Word16 var2)
{
- Word16 var_out;
- Word32 L_product_arr;
- L_product_arr = (Word32) var1 *(Word32) var2; /* product */
- L_product_arr += (Word32) 0x00004000L; /* round */
- L_product_arr &= (Word32) 0xffff8000L;
- L_product_arr >>= 15; /* shift */
- if (L_product_arr & (Word32) 0x00010000L) /* sign extend when necessary */
- {
- L_product_arr |= (Word32) 0xffff0000L;
- }
- var_out = saturate (L_product_arr);
- return (var_out);
+ Word16 var_out;
+ Word32 L_product_arr;
+ L_product_arr = (Word32) var1 *(Word32) var2; /* product */
+ L_product_arr += (Word32) 0x00004000L; /* round */
+ L_product_arr &= (Word32) 0xffff8000L;
+ L_product_arr >>= 15; /* shift */
+ if (L_product_arr & (Word32) 0x00010000L) /* sign extend when necessary */
+ {
+ L_product_arr |= (Word32) 0xffff0000L;
+ }
+ var_out = saturate (L_product_arr);
+ return (var_out);
}
/*___________________________________________________________________________
@@ -708,61 +714,61 @@
static_vo Word32 L_shl (Word32 L_var1, Word16 var2)
{
- Word32 L_var_out = 0L;
- if (var2 <= 0)
- {
- if (var2 < -32)
- var2 = -32;
- L_var_out = (L_var1 >> (Word16)-var2);
- }
- else
- {
- for (; var2 > 0; var2--)
- {
- if (L_var1 > (Word32) 0X3fffffffL)
- {
- L_var_out = MAX_32;
- break;
- }
- else
- {
- if (L_var1 < (Word32) 0xc0000000L)
- {
- //Overflow = 1;
- L_var_out = MIN_32;
- break;
- }
- }
- L_var1 *= 2;
- L_var_out = L_var1;
- }
- }
- return (L_var_out);
+ Word32 L_var_out = 0L;
+ if (var2 <= 0)
+ {
+ if (var2 < -32)
+ var2 = -32;
+ L_var_out = (L_var1 >> (Word16)-var2);
+ }
+ else
+ {
+ for (; var2 > 0; var2--)
+ {
+ if (L_var1 > (Word32) 0X3fffffffL)
+ {
+ L_var_out = MAX_32;
+ break;
+ }
+ else
+ {
+ if (L_var1 < (Word32) 0xc0000000L)
+ {
+ //Overflow = 1;
+ L_var_out = MIN_32;
+ break;
+ }
+ }
+ L_var1 *= 2;
+ L_var_out = L_var1;
+ }
+ }
+ return (L_var_out);
}
static_vo Word32 L_shl2(Word32 L_var1, Word16 var2)
{
- Word32 L_var_out = 0L;
+ Word32 L_var_out = 0L;
- for (; var2 > 0; var2--)
- {
- if (L_var1 > (Word32) 0X3fffffffL)
- {
- L_var_out = MAX_32;
- break;
- }
- else
- {
- if (L_var1 < (Word32) 0xc0000000L)
- {
- L_var_out = MIN_32;
- break;
- }
- }
- L_var1 <<=1 ;
- L_var_out = L_var1;
- }
- return (L_var_out);
+ for (; var2 > 0; var2--)
+ {
+ if (L_var1 > (Word32) 0X3fffffffL)
+ {
+ L_var_out = MAX_32;
+ break;
+ }
+ else
+ {
+ if (L_var1 < (Word32) 0xc0000000L)
+ {
+ L_var_out = MIN_32;
+ break;
+ }
+ }
+ L_var1 <<=1 ;
+ L_var_out = L_var1;
+ }
+ return (L_var_out);
}
/*___________________________________________________________________________
@@ -801,32 +807,32 @@
static_vo Word32 L_shr (Word32 L_var1, Word16 var2)
{
- Word32 L_var_out;
- if (var2 < 0)
- {
- if (var2 < -32)
- var2 = -32;
- L_var_out = L_shl2(L_var1, (Word16)-var2);
- }
- else
- {
- if (var2 >= 31)
- {
- L_var_out = (L_var1 < 0L) ? -1 : 0;
- }
- else
- {
- if (L_var1 < 0)
- {
- L_var_out = ~((~L_var1) >> var2);
- }
- else
- {
- L_var_out = L_var1 >> var2;
- }
- }
- }
- return (L_var_out);
+ Word32 L_var_out;
+ if (var2 < 0)
+ {
+ if (var2 < -32)
+ var2 = -32;
+ L_var_out = L_shl2(L_var1, (Word16)-var2);
+ }
+ else
+ {
+ if (var2 >= 31)
+ {
+ L_var_out = (L_var1 < 0L) ? -1 : 0;
+ }
+ else
+ {
+ if (L_var1 < 0)
+ {
+ L_var_out = ~((~L_var1) >> var2);
+ }
+ else
+ {
+ L_var_out = L_var1 >> var2;
+ }
+ }
+ }
+ return (L_var_out);
}
/*___________________________________________________________________________
@@ -873,23 +879,23 @@
static_vo Word32 L_shr_r (Word32 L_var1, Word16 var2)
{
- Word32 L_var_out;
- if (var2 > 31)
- {
- L_var_out = 0;
- }
- else
- {
- L_var_out = L_shr (L_var1, var2);
- if (var2 > 0)
- {
- if ((L_var1 & ((Word32) 1 << (var2 - 1))) != 0)
- {
- L_var_out++;
- }
- }
- }
- return (L_var_out);
+ Word32 L_var_out;
+ if (var2 > 31)
+ {
+ L_var_out = 0;
+ }
+ else
+ {
+ L_var_out = L_shr (L_var1, var2);
+ if (var2 > 0)
+ {
+ if ((L_var1 & ((Word32) 1 << (var2 - 1))) != 0)
+ {
+ L_var_out++;
+ }
+ }
+ }
+ return (L_var_out);
}
/*___________________________________________________________________________
@@ -927,30 +933,30 @@
static_vo Word16 norm_s (Word16 var1)
{
- Word16 var_out = 0;
- if (var1 == 0)
- {
- var_out = 0;
- }
- else
- {
- if (var1 == -1)
- {
- var_out = 15;
- }
- else
- {
- if (var1 < 0)
- {
- var1 = (Word16)~var1;
- }
- for (var_out = 0; var1 < 0x4000; var_out++)
- {
- var1 <<= 1;
- }
- }
- }
- return (var_out);
+ Word16 var_out = 0;
+ if (var1 == 0)
+ {
+ var_out = 0;
+ }
+ else
+ {
+ if (var1 == -1)
+ {
+ var_out = 15;
+ }
+ else
+ {
+ if (var1 < 0)
+ {
+ var1 = (Word16)~var1;
+ }
+ for (var_out = 0; var1 < 0x4000; var_out++)
+ {
+ var1 <<= 1;
+ }
+ }
+ }
+ return (var_out);
}
/*___________________________________________________________________________
@@ -992,47 +998,47 @@
static_vo Word16 div_s (Word16 var1, Word16 var2)
{
- Word16 var_out = 0;
- Word16 iteration;
- Word32 L_num;
- Word32 L_denom;
- if ((var1 < 0) || (var2 < 0))
- {
- var_out = MAX_16;
- return var_out;
- }
- if (var2 == 0)
- {
- var_out = MAX_16;
- return var_out;
- }
- if (var1 == 0)
- {
- var_out = 0;
- }
- else
- {
- if (var1 == var2)
- {
- var_out = MAX_16;
- }
- else
- {
- L_num = L_deposit_l (var1);
- L_denom = L_deposit_l(var2);
- for (iteration = 0; iteration < 15; iteration++)
- {
- var_out <<= 1;
- L_num <<= 1;
- if (L_num >= L_denom)
- {
- L_num -= L_denom;
- var_out += 1;
- }
- }
- }
- }
- return (var_out);
+ Word16 var_out = 0;
+ Word16 iteration;
+ Word32 L_num;
+ Word32 L_denom;
+ if ((var1 < 0) || (var2 < 0))
+ {
+ var_out = MAX_16;
+ return var_out;
+ }
+ if (var2 == 0)
+ {
+ var_out = MAX_16;
+ return var_out;
+ }
+ if (var1 == 0)
+ {
+ var_out = 0;
+ }
+ else
+ {
+ if (var1 == var2)
+ {
+ var_out = MAX_16;
+ }
+ else
+ {
+ L_num = L_deposit_l (var1);
+ L_denom = L_deposit_l(var2);
+ for (iteration = 0; iteration < 15; iteration++)
+ {
+ var_out <<= 1;
+ L_num <<= 1;
+ if (L_num >= L_denom)
+ {
+ L_num -= L_denom;
+ var_out += 1;
+ }
+ }
+ }
+ }
+ return (var_out);
}
/*___________________________________________________________________________
@@ -1070,20 +1076,20 @@
static_vo Word16 norm_l (Word32 L_var1)
{
- Word16 var_out = 0;
- if (L_var1 != 0)
- {
- var_out = 31;
- if (L_var1 != (Word32) 0xffffffffL)
- {
- L_var1 ^= (L_var1 >>31);
- for (var_out = 0; L_var1 < (Word32) 0x40000000L; var_out++)
- {
- L_var1 <<= 1;
- }
- }
- }
- return (var_out);
+ Word16 var_out = 0;
+ if (L_var1 != 0)
+ {
+ var_out = 31;
+ if (L_var1 != (Word32) 0xffffffffL)
+ {
+ L_var1 ^= (L_var1 >>31);
+ for (var_out = 0; L_var1 < (Word32) 0x40000000L; var_out++)
+ {
+ L_var1 <<= 1;
+ }
+ }
+ }
+ return (var_out);
}
#endif //__BASIC_OP_H__
diff --git a/media/libstagefright/codecs/amrwbenc/inc/bits.h b/media/libstagefright/codecs/amrwbenc/inc/bits.h
index e880684..ff9c0c1 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/bits.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/bits.h
@@ -18,7 +18,7 @@
/*--------------------------------------------------------------------------*
* BITS.H *
*--------------------------------------------------------------------------*
-* Number of bits for different modes *
+* Number of bits for different modes *
*--------------------------------------------------------------------------*/
#ifndef __BITS_H__
@@ -52,16 +52,16 @@
#define RX_FRAME_TYPE (Word16)0x6b20
static const Word16 nb_of_bits[NUM_OF_MODES] = {
- NBBITS_7k,
- NBBITS_9k,
- NBBITS_12k,
- NBBITS_14k,
- NBBITS_16k,
- NBBITS_18k,
- NBBITS_20k,
- NBBITS_23k,
- NBBITS_24k,
- NBBITS_SID
+ NBBITS_7k,
+ NBBITS_9k,
+ NBBITS_12k,
+ NBBITS_14k,
+ NBBITS_16k,
+ NBBITS_18k,
+ NBBITS_20k,
+ NBBITS_23k,
+ NBBITS_24k,
+ NBBITS_SID
};
/*typedef struct
@@ -74,18 +74,18 @@
//typedef struct
//{
-// Word16 prev_ft;
-// Word16 prev_mode;
+// Word16 prev_ft;
+// Word16 prev_mode;
//} RX_State;
int PackBits(Word16 prms[], Word16 coding_mode, Word16 mode, Coder_State *st);
void Parm_serial(
- Word16 value, /* input : parameter value */
- Word16 no_of_bits, /* input : number of bits */
- Word16 ** prms
- );
+ Word16 value, /* input : parameter value */
+ Word16 no_of_bits, /* input : number of bits */
+ Word16 ** prms
+ );
#endif //__BITS_H__
diff --git a/media/libstagefright/codecs/amrwbenc/inc/cod_main.h b/media/libstagefright/codecs/amrwbenc/inc/cod_main.h
index 53ca55e..170981e 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/cod_main.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/cod_main.h
@@ -18,7 +18,7 @@
/*--------------------------------------------------------------------------*
* COD_MAIN.H *
*--------------------------------------------------------------------------*
- * Static memory in the encoder *
+ * Static memory in the encoder *
*--------------------------------------------------------------------------*/
#ifndef __COD_MAIN_H__
#define __COD_MAIN_H__
@@ -79,21 +79,21 @@
Word16 vad_hist;
Word16 gain_alpha;
/* TX_State structure */
- Word16 sid_update_counter;
+ Word16 sid_update_counter;
Word16 sid_handover_debt;
Word16 prev_ft;
- Word16 allow_dtx;
- /*some input/output buffer parameters */
- unsigned char *inputStream;
- int inputSize;
- VOAMRWBMODE mode;
- VOAMRWBFRAMETYPE frameType;
- unsigned short *outputStream;
- int outputSize;
- FrameStream *stream;
- VO_MEM_OPERATOR *pvoMemop;
- VO_MEM_OPERATOR voMemoprator;
- VO_PTR hCheck;
+ Word16 allow_dtx;
+ /*some input/output buffer parameters */
+ unsigned char *inputStream;
+ int inputSize;
+ VOAMRWBMODE mode;
+ VOAMRWBFRAMETYPE frameType;
+ unsigned short *outputStream;
+ int outputSize;
+ FrameStream *stream;
+ VO_MEM_OPERATOR *pvoMemop;
+ VO_MEM_OPERATOR voMemoprator;
+ VO_PTR hCheck;
} Coder_State;
typedef void* HAMRENC;
diff --git a/media/libstagefright/codecs/amrwbenc/inc/dtx.h b/media/libstagefright/codecs/amrwbenc/inc/dtx.h
index 0bdda67..82a9bf4 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/dtx.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/dtx.h
@@ -16,9 +16,9 @@
/*--------------------------------------------------------------------------*
- * DTX.H *
+ * DTX.H *
*--------------------------------------------------------------------------*
- * Static memory, constants and frametypes for the DTX *
+ * Static memory, constants and frametypes for the DTX *
*--------------------------------------------------------------------------*/
#ifndef __DTX_H__
diff --git a/media/libstagefright/codecs/amrwbenc/inc/log2.h b/media/libstagefright/codecs/amrwbenc/inc/log2.h
index b065eb4..3d9a6c4 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/log2.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/log2.h
@@ -45,17 +45,17 @@
********************************************************************************
*/
void Log2 (
- Word32 L_x, /* (i) : input value */
- Word16 *exponent, /* (o) : Integer part of Log2. (range: 0<=val<=30) */
- Word16 *fraction /* (o) : Fractional part of Log2. (range: 0<=val<1)*/
- );
+ Word32 L_x, /* (i) : input value */
+ Word16 *exponent, /* (o) : Integer part of Log2. (range: 0<=val<=30) */
+ Word16 *fraction /* (o) : Fractional part of Log2. (range: 0<=val<1)*/
+ );
void Log2_norm (
- Word32 L_x, /* (i) : input value (normalized) */
- Word16 exp, /* (i) : norm_l (L_x) */
- Word16 *exponent, /* (o) : Integer part of Log2. (range: 0<=val<=30) */
- Word16 *fraction /* (o) : Fractional part of Log2. (range: 0<=val<1) */
- );
+ Word32 L_x, /* (i) : input value (normalized) */
+ Word16 exp, /* (i) : norm_l (L_x) */
+ Word16 *exponent, /* (o) : Integer part of Log2. (range: 0<=val<=30) */
+ Word16 *fraction /* (o) : Fractional part of Log2. (range: 0<=val<1) */
+ );
#endif //__LOG2_H__
diff --git a/media/libstagefright/codecs/amrwbenc/inc/main.h b/media/libstagefright/codecs/amrwbenc/inc/main.h
index 3a6f963..adef2df 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/main.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/main.h
@@ -17,9 +17,9 @@
/*--------------------------------------------------------------------------*
- * MAIN.H *
+ * MAIN.H *
*--------------------------------------------------------------------------*
- * Main functions *
+ * Main functions *
*--------------------------------------------------------------------------*/
#ifndef __MAIN_H__
diff --git a/media/libstagefright/codecs/amrwbenc/inc/math_op.h b/media/libstagefright/codecs/amrwbenc/inc/math_op.h
index 7b6196b..c3c00bc 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/math_op.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/math_op.h
@@ -16,40 +16,40 @@
/*--------------------------------------------------------------------------*
- * MATH_OP.H *
+ * MATH_OP.H *
*--------------------------------------------------------------------------*
- * Mathematical operations *
+ * Mathematical operations *
*--------------------------------------------------------------------------*/
#ifndef __MATH_OP_H__
#define __MATH_OP_H__
Word32 Isqrt( /* (o) Q31 : output value (range: 0<=val<1) */
- Word32 L_x /* (i) Q0 : input value (range: 0<=val<=7fffffff) */
- );
+ Word32 L_x /* (i) Q0 : input value (range: 0<=val<=7fffffff) */
+ );
void Isqrt_n(
- Word32 * frac, /* (i/o) Q31: normalized value (1.0 < frac <= 0.5) */
- Word16 * exp /* (i/o) : exponent (value = frac x 2^exponent) */
- );
+ Word32 * frac, /* (i/o) Q31: normalized value (1.0 < frac <= 0.5) */
+ Word16 * exp /* (i/o) : exponent (value = frac x 2^exponent) */
+ );
Word32 Pow2( /* (o) Q0 : result (range: 0<=val<=0x7fffffff) */
- Word16 exponant, /* (i) Q0 : Integer part. (range: 0<=val<=30) */
- Word16 fraction /* (i) Q15 : Fractionnal part. (range: 0.0<=val<1.0) */
- );
+ Word16 exponant, /* (i) Q0 : Integer part. (range: 0<=val<=30) */
+ Word16 fraction /* (i) Q15 : Fractionnal part. (range: 0.0<=val<1.0) */
+ );
Word32 Dot_product12( /* (o) Q31: normalized result (1 < val <= -1) */
- Word16 x[], /* (i) 12bits: x vector */
- Word16 y[], /* (i) 12bits: y vector */
- Word16 lg, /* (i) : vector length */
- Word16 * exp /* (o) : exponent of result (0..+30) */
- );
+ Word16 x[], /* (i) 12bits: x vector */
+ Word16 y[], /* (i) 12bits: y vector */
+ Word16 lg, /* (i) : vector length */
+ Word16 * exp /* (o) : exponent of result (0..+30) */
+ );
Word32 Dot_product12_asm( /* (o) Q31: normalized result (1 < val <= -1) */
- Word16 x[], /* (i) 12bits: x vector */
- Word16 y[], /* (i) 12bits: y vector */
- Word16 lg, /* (i) : vector length */
- Word16 * exp /* (o) : exponent of result (0..+30) */
- );
+ Word16 x[], /* (i) 12bits: x vector */
+ Word16 y[], /* (i) 12bits: y vector */
+ Word16 lg, /* (i) : vector length */
+ Word16 * exp /* (o) : exponent of result (0..+30) */
+ );
#endif //__MATH_OP_H__
diff --git a/media/libstagefright/codecs/amrwbenc/inc/mem_align.h b/media/libstagefright/codecs/amrwbenc/inc/mem_align.h
index 442786a..2ae5a6c 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/mem_align.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/mem_align.h
@@ -14,9 +14,9 @@
** limitations under the License.
*/
/*******************************************************************************
- File: mem_align.h
+ File: mem_align.h
- Content: Memory alloc alignments functions
+ Content: Memory alloc alignments functions
*******************************************************************************/
@@ -29,7 +29,7 @@
extern void *mem_malloc(VO_MEM_OPERATOR *pMemop, unsigned int size, unsigned char alignment, unsigned int CodecID);
extern void mem_free(VO_MEM_OPERATOR *pMemop, void *mem_ptr, unsigned int CodecID);
-#endif /* __VO_MEM_ALIGN_H__ */
+#endif /* __VO_MEM_ALIGN_H__ */
diff --git a/media/libstagefright/codecs/amrwbenc/inc/p_med_o.h b/media/libstagefright/codecs/amrwbenc/inc/p_med_o.h
index 4a13f16..77487ed 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/p_med_o.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/p_med_o.h
@@ -17,36 +17,36 @@
/*--------------------------------------------------------------------------*
* P_MED_O.H *
*--------------------------------------------------------------------------*
- * Median open-loop lag search *
+ * Median open-loop lag search *
*--------------------------------------------------------------------------*/
#ifndef __P_MED_O_H__
#define __P_MED_O_H__
Word16 Pitch_med_ol( /* output: open loop pitch lag */
- Word16 wsp[], /* input : signal used to compute the open loop pitch */
- /* wsp[-pit_max] to wsp[-1] should be known */
- Word16 L_min, /* input : minimum pitch lag */
- Word16 L_max, /* input : maximum pitch lag */
- Word16 L_frame, /* input : length of frame to compute pitch */
- Word16 L_0, /* input : old_ open-loop pitch */
- Word16 * gain, /* output: normalize correlation of hp_wsp for the Lag */
- Word16 * hp_wsp_mem, /* i:o : memory of the hypass filter for hp_wsp[] (lg=9) */
- Word16 * old_hp_wsp, /* i:o : hypass wsp[] */
- Word16 wght_flg /* input : is weighting function used */
- );
+ Word16 wsp[], /* input : signal used to compute the open loop pitch */
+ /* wsp[-pit_max] to wsp[-1] should be known */
+ Word16 L_min, /* input : minimum pitch lag */
+ Word16 L_max, /* input : maximum pitch lag */
+ Word16 L_frame, /* input : length of frame to compute pitch */
+ Word16 L_0, /* input : old_ open-loop pitch */
+ Word16 * gain, /* output: normalize correlation of hp_wsp for the Lag */
+ Word16 * hp_wsp_mem, /* i:o : memory of the hypass filter for hp_wsp[] (lg=9) */
+ Word16 * old_hp_wsp, /* i:o : hypass wsp[] */
+ Word16 wght_flg /* input : is weighting function used */
+ );
Word16 Med_olag( /* output : median of 5 previous open-loop lags */
- Word16 prev_ol_lag, /* input : previous open-loop lag */
- Word16 old_ol_lag[5]
- );
+ Word16 prev_ol_lag, /* input : previous open-loop lag */
+ Word16 old_ol_lag[5]
+ );
void Hp_wsp(
- Word16 wsp[], /* i : wsp[] signal */
- Word16 hp_wsp[], /* o : hypass wsp[] */
- Word16 lg, /* i : lenght of signal */
- Word16 mem[] /* i/o : filter memory [9] */
- );
+ Word16 wsp[], /* i : wsp[] signal */
+ Word16 hp_wsp[], /* o : hypass wsp[] */
+ Word16 lg, /* i : lenght of signal */
+ Word16 mem[] /* i/o : filter memory [9] */
+ );
#endif //__P_MED_O_H__
diff --git a/media/libstagefright/codecs/amrwbenc/inc/q_pulse.h b/media/libstagefright/codecs/amrwbenc/inc/q_pulse.h
index b5d5280..67140fc 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/q_pulse.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/q_pulse.h
@@ -19,7 +19,7 @@
/*--------------------------------------------------------------------------*
* Q_PULSE.H *
*--------------------------------------------------------------------------*
- * Coding and decoding of algebraic codebook *
+ * Coding and decoding of algebraic codebook *
*--------------------------------------------------------------------------*/
#ifndef __Q_PULSE_H__
@@ -28,38 +28,38 @@
#include "typedef.h"
Word32 quant_1p_N1( /* (o) return (N+1) bits */
- Word16 pos, /* (i) position of the pulse */
- Word16 N); /* (i) number of bits for position */
+ Word16 pos, /* (i) position of the pulse */
+ Word16 N); /* (i) number of bits for position */
Word32 quant_2p_2N1( /* (o) return (2*N)+1 bits */
- Word16 pos1, /* (i) position of the pulse 1 */
- Word16 pos2, /* (i) position of the pulse 2 */
- Word16 N); /* (i) number of bits for position */
+ Word16 pos1, /* (i) position of the pulse 1 */
+ Word16 pos2, /* (i) position of the pulse 2 */
+ Word16 N); /* (i) number of bits for position */
Word32 quant_3p_3N1( /* (o) return (3*N)+1 bits */
- Word16 pos1, /* (i) position of the pulse 1 */
- Word16 pos2, /* (i) position of the pulse 2 */
- Word16 pos3, /* (i) position of the pulse 3 */
- Word16 N); /* (i) number of bits for position */
+ Word16 pos1, /* (i) position of the pulse 1 */
+ Word16 pos2, /* (i) position of the pulse 2 */
+ Word16 pos3, /* (i) position of the pulse 3 */
+ Word16 N); /* (i) number of bits for position */
Word32 quant_4p_4N1( /* (o) return (4*N)+1 bits */
- Word16 pos1, /* (i) position of the pulse 1 */
- Word16 pos2, /* (i) position of the pulse 2 */
- Word16 pos3, /* (i) position of the pulse 3 */
- Word16 pos4, /* (i) position of the pulse 4 */
- Word16 N); /* (i) number of bits for position */
+ Word16 pos1, /* (i) position of the pulse 1 */
+ Word16 pos2, /* (i) position of the pulse 2 */
+ Word16 pos3, /* (i) position of the pulse 3 */
+ Word16 pos4, /* (i) position of the pulse 4 */
+ Word16 N); /* (i) number of bits for position */
Word32 quant_4p_4N( /* (o) return 4*N bits */
- Word16 pos[], /* (i) position of the pulse 1..4 */
- Word16 N); /* (i) number of bits for position */
+ Word16 pos[], /* (i) position of the pulse 1..4 */
+ Word16 N); /* (i) number of bits for position */
Word32 quant_5p_5N( /* (o) return 5*N bits */
- Word16 pos[], /* (i) position of the pulse 1..5 */
- Word16 N); /* (i) number of bits for position */
+ Word16 pos[], /* (i) position of the pulse 1..5 */
+ Word16 N); /* (i) number of bits for position */
Word32 quant_6p_6N_2( /* (o) return (6*N)-2 bits */
- Word16 pos[], /* (i) position of the pulse 1..6 */
- Word16 N); /* (i) number of bits for position */
+ Word16 pos[], /* (i) position of the pulse 1..6 */
+ Word16 N); /* (i) number of bits for position */
#endif //__Q_PULSE_H__
diff --git a/media/libstagefright/codecs/amrwbenc/inc/stream.h b/media/libstagefright/codecs/amrwbenc/inc/stream.h
index 4c1d0f0..ec1a700 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/stream.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/stream.h
@@ -17,7 +17,7 @@
/***********************************************************************
-File: stream.h
+File: stream.h
Contains: VOME API Buffer Operator Implement Header
@@ -28,16 +28,16 @@
#include "voMem.h"
#define Frame_Maxsize 1024 * 2 //Work Buffer 10K
#define Frame_MaxByte 640 //AMR_WB Encoder one frame 320 samples = 640 Bytes
-#define MIN(a,b) ((a) < (b)? (a) : (b))
+#define MIN(a,b) ((a) < (b)? (a) : (b))
typedef struct{
- unsigned char *set_ptr;
- unsigned char *frame_ptr;
- unsigned char *frame_ptr_bk;
- int set_len;
- int framebuffer_len;
- int frame_storelen;
- int used_len;
+ unsigned char *set_ptr;
+ unsigned char *frame_ptr;
+ unsigned char *frame_ptr_bk;
+ int set_len;
+ int framebuffer_len;
+ int frame_storelen;
+ int used_len;
}FrameStream;
void voAWB_UpdateFrameBuffer(FrameStream *stream, VO_MEM_OPERATOR *pMemOP);
diff --git a/media/libstagefright/codecs/amrwbenc/inc/wb_vad.h b/media/libstagefright/codecs/amrwbenc/inc/wb_vad.h
index 6822f48..9a9af4f 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/wb_vad.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/wb_vad.h
@@ -37,28 +37,28 @@
typedef struct
{
- Word16 bckr_est[COMPLEN]; /* background noise estimate */
- Word16 ave_level[COMPLEN]; /* averaged input components for stationary */
- /* estimation */
- Word16 old_level[COMPLEN]; /* input levels of the previous frame */
- Word16 sub_level[COMPLEN]; /* input levels calculated at the end of a frame (lookahead) */
- Word16 a_data5[F_5TH_CNT][2]; /* memory for the filter bank */
- Word16 a_data3[F_3TH_CNT]; /* memory for the filter bank */
+ Word16 bckr_est[COMPLEN]; /* background noise estimate */
+ Word16 ave_level[COMPLEN]; /* averaged input components for stationary */
+ /* estimation */
+ Word16 old_level[COMPLEN]; /* input levels of the previous frame */
+ Word16 sub_level[COMPLEN]; /* input levels calculated at the end of a frame (lookahead) */
+ Word16 a_data5[F_5TH_CNT][2]; /* memory for the filter bank */
+ Word16 a_data3[F_3TH_CNT]; /* memory for the filter bank */
- Word16 burst_count; /* counts length of a speech burst */
- Word16 hang_count; /* hangover counter */
- Word16 stat_count; /* stationary counter */
+ Word16 burst_count; /* counts length of a speech burst */
+ Word16 hang_count; /* hangover counter */
+ Word16 stat_count; /* stationary counter */
- /* Note that each of the following two variables holds 15 flags. Each flag reserves 1 bit of the
- * variable. The newest flag is in the bit 15 (assuming that LSB is bit 1 and MSB is bit 16). */
- Word16 vadreg; /* flags for intermediate VAD decisions */
- Word16 tone_flag; /* tone detection flags */
+ /* Note that each of the following two variables holds 15 flags. Each flag reserves 1 bit of the
+ * variable. The newest flag is in the bit 15 (assuming that LSB is bit 1 and MSB is bit 16). */
+ Word16 vadreg; /* flags for intermediate VAD decisions */
+ Word16 tone_flag; /* tone detection flags */
- Word16 sp_est_cnt; /* counter for speech level estimation */
- Word16 sp_max; /* maximum level */
- Word16 sp_max_cnt; /* counts frames that contains speech */
- Word16 speech_level; /* estimated speech level */
- Word32 prev_pow_sum; /* power of previous frame */
+ Word16 sp_est_cnt; /* counter for speech level estimation */
+ Word16 sp_max; /* maximum level */
+ Word16 sp_max_cnt; /* counts frames that contains speech */
+ Word16 speech_level; /* estimated speech level */
+ Word32 prev_pow_sum; /* power of previous frame */
} VadVars;
diff --git a/media/libstagefright/codecs/amrwbenc/inc/wb_vad_c.h b/media/libstagefright/codecs/amrwbenc/inc/wb_vad_c.h
index 04fd318..00b1779 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/wb_vad_c.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/wb_vad_c.h
@@ -16,9 +16,9 @@
/*-------------------------------------------------------------------*
- * WB_VAD_C.H *
+ * WB_VAD_C.H *
*-------------------------------------------------------------------*
- * Constants for Voice Activity Detection. *
+ * Constants for Voice Activity Detection. *
*-------------------------------------------------------------------*/
#ifndef __WB_VAD_C_H__
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Deemph_32_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Deemph_32_opt.s
index 282db92..42ebc32 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Deemph_32_opt.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Deemph_32_opt.s
@@ -99,6 +99,6 @@
LDMFD r13!, {r4 - r12, r15}
@ENDP
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Dot_p_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Dot_p_opt.s
index 4aa317e..3f060ff 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Dot_p_opt.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Dot_p_opt.s
@@ -75,6 +75,6 @@
LDMFD r13!, {r4 - r12, r15}
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Filt_6k_7k_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Filt_6k_7k_opt.s
index f23b5a0..9cad479 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Filt_6k_7k_opt.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Filt_6k_7k_opt.s
@@ -183,6 +183,6 @@
Lable1:
.word fir_6k_7k-Lable1
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Norm_Corr_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Norm_Corr_opt.s
index 49bdc2b..ffedbde 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Norm_Corr_opt.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Norm_Corr_opt.s
@@ -226,6 +226,6 @@
ADD r13, r13, #voSTACK
LDMFD r13!, {r4 - r12, r15}
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Syn_filt_32_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Syn_filt_32_opt.s
index 3f4930c..9743b9e 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Syn_filt_32_opt.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Syn_filt_32_opt.s
@@ -221,6 +221,6 @@
LDMFD r13!, {r4 - r12, r15}
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/convolve_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/convolve_opt.s
index 71bb532..cd75179 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/convolve_opt.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/convolve_opt.s
@@ -181,6 +181,6 @@
LDMFD r13!, {r4 - r12, r15}
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/cor_h_vec_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/cor_h_vec_opt.s
index 2d4c7cc..eedccc7 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/cor_h_vec_opt.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/cor_h_vec_opt.s
@@ -143,7 +143,7 @@
LDMFD r13!, {r4 - r12, r15}
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/pred_lt4_1_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/pred_lt4_1_opt.s
index deb7efc..60c2a47 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/pred_lt4_1_opt.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/pred_lt4_1_opt.s
@@ -45,7 +45,8 @@
SUBLT r5, r5, #2 @x--
SUB r5, r5, #30 @x -= 15
RSB r4, r2, #3 @k = 3 - frac
- ADRL r8, Table
+ ADR r8, Table
+ NOP @space for fixed up relative address of ADR
LDR r6, [r8]
ADD r6, r8
MOV r8, r4, LSL #6
@@ -456,7 +457,7 @@
Table:
.word inter4_2-Table
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/residu_asm_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/residu_asm_opt.s
index 5ff0964..d71d790 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/residu_asm_opt.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/residu_asm_opt.s
@@ -220,7 +220,7 @@
LDMFD r13!, {r4 -r12,pc}
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/scale_sig_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/scale_sig_opt.s
index b300224..e8802f5 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/scale_sig_opt.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/scale_sig_opt.s
@@ -67,7 +67,7 @@
LDMFD r13!, {r4 - r12, r15}
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/syn_filt_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/syn_filt_opt.s
index 0c287a4..2a1e0d7 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/syn_filt_opt.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/syn_filt_opt.s
@@ -233,6 +233,6 @@
ADD r13, r13, #700
LDMFD r13!, {r4 - r12, r15}
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Deemph_32_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Deemph_32_neon.s
index 1d5893f..91feea0 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Deemph_32_neon.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Deemph_32_neon.s
@@ -98,5 +98,5 @@
LDMFD r13!, {r4 - r12, r15}
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Dot_p_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Dot_p_neon.s
index 8230944..7149a49 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Dot_p_neon.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Dot_p_neon.s
@@ -123,5 +123,5 @@
LDMFD r13!, {r4 - r12, r15}
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Filt_6k_7k_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Filt_6k_7k_neon.s
index 8df0caa..e0f992f 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Filt_6k_7k_neon.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Filt_6k_7k_neon.s
@@ -226,6 +226,6 @@
Lable1:
.word fir_6k_7k-Lable1
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Norm_Corr_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Norm_Corr_neon.s
index 4263cd4..28e6d6c 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Norm_Corr_neon.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Norm_Corr_neon.s
@@ -265,6 +265,6 @@
ADD r13, r13, #voSTACK
LDMFD r13!, {r4 - r12, r15}
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Syn_filt_32_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Syn_filt_32_neon.s
index e786dde..9687431 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Syn_filt_32_neon.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Syn_filt_32_neon.s
@@ -128,6 +128,6 @@
LDMFD r13!, {r4 - r12, r15}
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/convolve_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/convolve_neon.s
index 8efa9fb..9fb3a6e 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/convolve_neon.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/convolve_neon.s
@@ -174,5 +174,5 @@
LDMFD r13!, {r4 - r12, r15}
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/cor_h_vec_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/cor_h_vec_neon.s
index 8904289..a4deda3 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/cor_h_vec_neon.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/cor_h_vec_neon.s
@@ -143,7 +143,7 @@
the_end:
LDMFD r13!, {r4 - r12, r15}
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/pred_lt4_1_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/pred_lt4_1_neon.s
index 67be1ed..f8b634f 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/pred_lt4_1_neon.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/pred_lt4_1_neon.s
@@ -99,5 +99,5 @@
Lable1:
.word inter4_2-Lable1
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/residu_asm_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/residu_asm_neon.s
index 394fa83..bc3d780 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/residu_asm_neon.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/residu_asm_neon.s
@@ -122,6 +122,6 @@
LDMFD r13!, {r4 - r12, r15}
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/scale_sig_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/scale_sig_neon.s
index e45daac..89c0572 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/scale_sig_neon.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/scale_sig_neon.s
@@ -133,6 +133,6 @@
LDMFD r13!, {r4 - r12, r15}
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/syn_filt_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/syn_filt_neon.s
index 5731bdb..029560e 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/syn_filt_neon.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/syn_filt_neon.s
@@ -101,6 +101,6 @@
ADD r13, r13, #700
LDMFD r13!, {r4 - r12, r15}
@ENDFUNC
- .END
+ .end
diff --git a/media/libstagefright/codecs/amrwbenc/src/autocorr.c b/media/libstagefright/codecs/amrwbenc/src/autocorr.c
index 0b2ea89..3ea53f7 100644
--- a/media/libstagefright/codecs/amrwbenc/src/autocorr.c
+++ b/media/libstagefright/codecs/amrwbenc/src/autocorr.c
@@ -31,100 +31,100 @@
#define UNUSED(x) (void)(x)
void Autocorr(
- Word16 x[], /* (i) : Input signal */
- Word16 m, /* (i) : LPC order */
- Word16 r_h[], /* (o) Q15: Autocorrelations (msb) */
- Word16 r_l[] /* (o) : Autocorrelations (lsb) */
- )
+ Word16 x[], /* (i) : Input signal */
+ Word16 m, /* (i) : LPC order */
+ Word16 r_h[], /* (o) Q15: Autocorrelations (msb) */
+ Word16 r_l[] /* (o) : Autocorrelations (lsb) */
+ )
{
- Word32 i, norm, shift;
- Word16 y[L_WINDOW];
- Word32 L_sum, L_sum1, L_tmp, F_LEN;
- Word16 *p1,*p2,*p3;
- const Word16 *p4;
+ Word32 i, norm, shift;
+ Word16 y[L_WINDOW];
+ Word32 L_sum, L_sum1, L_tmp, F_LEN;
+ Word16 *p1,*p2,*p3;
+ const Word16 *p4;
UNUSED(m);
- /* Windowing of signal */
- p1 = x;
- p4 = vo_window;
- p3 = y;
+ /* Windowing of signal */
+ p1 = x;
+ p4 = vo_window;
+ p3 = y;
- for (i = 0; i < L_WINDOW; i+=4)
- {
- *p3++ = vo_mult_r((*p1++), (*p4++));
- *p3++ = vo_mult_r((*p1++), (*p4++));
- *p3++ = vo_mult_r((*p1++), (*p4++));
- *p3++ = vo_mult_r((*p1++), (*p4++));
- }
+ for (i = 0; i < L_WINDOW; i+=4)
+ {
+ *p3++ = vo_mult_r((*p1++), (*p4++));
+ *p3++ = vo_mult_r((*p1++), (*p4++));
+ *p3++ = vo_mult_r((*p1++), (*p4++));
+ *p3++ = vo_mult_r((*p1++), (*p4++));
+ }
- /* calculate energy of signal */
- L_sum = vo_L_deposit_h(16); /* sqrt(256), avoid overflow after rounding */
- for (i = 0; i < L_WINDOW; i++)
- {
- L_tmp = vo_L_mult(y[i], y[i]);
- L_tmp = (L_tmp >> 8);
- L_sum += L_tmp;
- }
+ /* calculate energy of signal */
+ L_sum = vo_L_deposit_h(16); /* sqrt(256), avoid overflow after rounding */
+ for (i = 0; i < L_WINDOW; i++)
+ {
+ L_tmp = vo_L_mult(y[i], y[i]);
+ L_tmp = (L_tmp >> 8);
+ L_sum += L_tmp;
+ }
- /* scale signal to avoid overflow in autocorrelation */
- norm = norm_l(L_sum);
- shift = 4 - (norm >> 1);
- if(shift > 0)
- {
- p1 = y;
- for (i = 0; i < L_WINDOW; i+=4)
- {
- *p1 = vo_shr_r(*p1, shift);
- p1++;
- *p1 = vo_shr_r(*p1, shift);
- p1++;
- *p1 = vo_shr_r(*p1, shift);
- p1++;
- *p1 = vo_shr_r(*p1, shift);
- p1++;
- }
- }
+ /* scale signal to avoid overflow in autocorrelation */
+ norm = norm_l(L_sum);
+ shift = 4 - (norm >> 1);
+ if(shift > 0)
+ {
+ p1 = y;
+ for (i = 0; i < L_WINDOW; i+=4)
+ {
+ *p1 = vo_shr_r(*p1, shift);
+ p1++;
+ *p1 = vo_shr_r(*p1, shift);
+ p1++;
+ *p1 = vo_shr_r(*p1, shift);
+ p1++;
+ *p1 = vo_shr_r(*p1, shift);
+ p1++;
+ }
+ }
- /* Compute and normalize r[0] */
- L_sum = 1;
- for (i = 0; i < L_WINDOW; i+=4)
- {
- L_sum += vo_L_mult(y[i], y[i]);
- L_sum += vo_L_mult(y[i+1], y[i+1]);
- L_sum += vo_L_mult(y[i+2], y[i+2]);
- L_sum += vo_L_mult(y[i+3], y[i+3]);
- }
+ /* Compute and normalize r[0] */
+ L_sum = 1;
+ for (i = 0; i < L_WINDOW; i+=4)
+ {
+ L_sum += vo_L_mult(y[i], y[i]);
+ L_sum += vo_L_mult(y[i+1], y[i+1]);
+ L_sum += vo_L_mult(y[i+2], y[i+2]);
+ L_sum += vo_L_mult(y[i+3], y[i+3]);
+ }
- norm = norm_l(L_sum);
- L_sum = (L_sum << norm);
+ norm = norm_l(L_sum);
+ L_sum = (L_sum << norm);
- r_h[0] = L_sum >> 16;
- r_l[0] = (L_sum & 0xffff)>>1;
+ r_h[0] = L_sum >> 16;
+ r_l[0] = (L_sum & 0xffff)>>1;
- /* Compute r[1] to r[m] */
- for (i = 1; i <= 8; i++)
- {
- L_sum1 = 0;
- L_sum = 0;
- F_LEN = (Word32)(L_WINDOW - 2*i);
- p1 = y;
- p2 = y + (2*i)-1;
- do{
- L_sum1 += *p1 * *p2++;
- L_sum += *p1++ * *p2;
- }while(--F_LEN!=0);
+ /* Compute r[1] to r[m] */
+ for (i = 1; i <= 8; i++)
+ {
+ L_sum1 = 0;
+ L_sum = 0;
+ F_LEN = (Word32)(L_WINDOW - 2*i);
+ p1 = y;
+ p2 = y + (2*i)-1;
+ do{
+ L_sum1 += *p1 * *p2++;
+ L_sum += *p1++ * *p2;
+ }while(--F_LEN!=0);
- L_sum1 += *p1 * *p2++;
+ L_sum1 += *p1 * *p2++;
- L_sum1 = L_sum1<<norm;
- L_sum = L_sum<<norm;
+ L_sum1 = L_sum1<<norm;
+ L_sum = L_sum<<norm;
- r_h[(2*i)-1] = L_sum1 >> 15;
- r_l[(2*i)-1] = L_sum1 & 0x00007fff;
- r_h[(2*i)] = L_sum >> 15;
- r_l[(2*i)] = L_sum & 0x00007fff;
- }
- return;
+ r_h[(2*i)-1] = L_sum1 >> 15;
+ r_l[(2*i)-1] = L_sum1 & 0x00007fff;
+ r_h[(2*i)] = L_sum >> 15;
+ r_l[(2*i)] = L_sum & 0x00007fff;
+ }
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/az_isp.c b/media/libstagefright/codecs/amrwbenc/src/az_isp.c
index 43db27a..d7074f0 100644
--- a/media/libstagefright/codecs/amrwbenc/src/az_isp.c
+++ b/media/libstagefright/codecs/amrwbenc/src/az_isp.c
@@ -58,138 +58,138 @@
static __inline Word16 Chebps2(Word16 x, Word16 f[], Word32 n);
void Az_isp(
- Word16 a[], /* (i) Q12 : predictor coefficients */
- Word16 isp[], /* (o) Q15 : Immittance spectral pairs */
- Word16 old_isp[] /* (i) : old isp[] (in case not found M roots) */
- )
+ Word16 a[], /* (i) Q12 : predictor coefficients */
+ Word16 isp[], /* (o) Q15 : Immittance spectral pairs */
+ Word16 old_isp[] /* (i) : old isp[] (in case not found M roots) */
+ )
{
- Word32 i, j, nf, ip, order;
- Word16 xlow, ylow, xhigh, yhigh, xmid, ymid, xint;
- Word16 x, y, sign, exp;
- Word16 *coef;
- Word16 f1[NC + 1], f2[NC];
- Word32 t0;
- /*-------------------------------------------------------------*
- * find the sum and diff polynomials F1(z) and F2(z) *
- * F1(z) = [A(z) + z^M A(z^-1)] *
- * F2(z) = [A(z) - z^M A(z^-1)]/(1-z^-2) *
- * *
- * for (i=0; i<NC; i++) *
- * { *
- * f1[i] = a[i] + a[M-i]; *
- * f2[i] = a[i] - a[M-i]; *
- * } *
- * f1[NC] = 2.0*a[NC]; *
- * *
- * for (i=2; i<NC; i++) Divide by (1-z^-2) *
- * f2[i] += f2[i-2]; *
- *-------------------------------------------------------------*/
- for (i = 0; i < NC; i++)
- {
- t0 = a[i] << 15;
- f1[i] = vo_round(t0 + (a[M - i] << 15)); /* =(a[i]+a[M-i])/2 */
- f2[i] = vo_round(t0 - (a[M - i] << 15)); /* =(a[i]-a[M-i])/2 */
- }
- f1[NC] = a[NC];
- for (i = 2; i < NC; i++) /* Divide by (1-z^-2) */
- f2[i] = add1(f2[i], f2[i - 2]);
+ Word32 i, j, nf, ip, order;
+ Word16 xlow, ylow, xhigh, yhigh, xmid, ymid, xint;
+ Word16 x, y, sign, exp;
+ Word16 *coef;
+ Word16 f1[NC + 1], f2[NC];
+ Word32 t0;
+ /*-------------------------------------------------------------*
+ * find the sum and diff polynomials F1(z) and F2(z) *
+ * F1(z) = [A(z) + z^M A(z^-1)] *
+ * F2(z) = [A(z) - z^M A(z^-1)]/(1-z^-2) *
+ * *
+ * for (i=0; i<NC; i++) *
+ * { *
+ * f1[i] = a[i] + a[M-i]; *
+ * f2[i] = a[i] - a[M-i]; *
+ * } *
+ * f1[NC] = 2.0*a[NC]; *
+ * *
+ * for (i=2; i<NC; i++) Divide by (1-z^-2) *
+ * f2[i] += f2[i-2]; *
+ *-------------------------------------------------------------*/
+ for (i = 0; i < NC; i++)
+ {
+ t0 = a[i] << 15;
+ f1[i] = vo_round(t0 + (a[M - i] << 15)); /* =(a[i]+a[M-i])/2 */
+ f2[i] = vo_round(t0 - (a[M - i] << 15)); /* =(a[i]-a[M-i])/2 */
+ }
+ f1[NC] = a[NC];
+ for (i = 2; i < NC; i++) /* Divide by (1-z^-2) */
+ f2[i] = add1(f2[i], f2[i - 2]);
- /*---------------------------------------------------------------------*
- * Find the ISPs (roots of F1(z) and F2(z) ) using the *
- * Chebyshev polynomial evaluation. *
- * The roots of F1(z) and F2(z) are alternatively searched. *
- * We start by finding the first root of F1(z) then we switch *
- * to F2(z) then back to F1(z) and so on until all roots are found. *
- * *
- * - Evaluate Chebyshev pol. at grid points and check for sign change.*
- * - If sign change track the root by subdividing the interval *
- * 2 times and ckecking sign change. *
- *---------------------------------------------------------------------*/
- nf = 0; /* number of found frequencies */
- ip = 0; /* indicator for f1 or f2 */
- coef = f1;
- order = NC;
- xlow = vogrid[0];
- ylow = Chebps2(xlow, coef, order);
- j = 0;
- while ((nf < M - 1) && (j < GRID_POINTS))
- {
- j ++;
- xhigh = xlow;
- yhigh = ylow;
- xlow = vogrid[j];
- ylow = Chebps2(xlow, coef, order);
- if ((ylow * yhigh) <= (Word32) 0)
- {
- /* divide 2 times the interval */
- for (i = 0; i < 2; i++)
- {
- xmid = (xlow >> 1) + (xhigh >> 1); /* xmid = (xlow + xhigh)/2 */
- ymid = Chebps2(xmid, coef, order);
- if ((ylow * ymid) <= (Word32) 0)
- {
- yhigh = ymid;
- xhigh = xmid;
- } else
- {
- ylow = ymid;
- xlow = xmid;
- }
- }
- /*-------------------------------------------------------------*
- * Linear interpolation *
- * xint = xlow - ylow*(xhigh-xlow)/(yhigh-ylow); *
- *-------------------------------------------------------------*/
- x = xhigh - xlow;
- y = yhigh - ylow;
- if (y == 0)
- {
- xint = xlow;
- } else
- {
- sign = y;
- y = abs_s(y);
- exp = norm_s(y);
- y = y << exp;
- y = div_s((Word16) 16383, y);
- t0 = x * y;
- t0 = (t0 >> (19 - exp));
- y = vo_extract_l(t0); /* y= (xhigh-xlow)/(yhigh-ylow) in Q11 */
- if (sign < 0)
- y = -y;
- t0 = ylow * y; /* result in Q26 */
- t0 = (t0 >> 10); /* result in Q15 */
- xint = vo_sub(xlow, vo_extract_l(t0)); /* xint = xlow - ylow*y */
- }
- isp[nf] = xint;
- xlow = xint;
- nf++;
- if (ip == 0)
- {
- ip = 1;
- coef = f2;
- order = NC - 1;
- } else
- {
- ip = 0;
- coef = f1;
- order = NC;
- }
- ylow = Chebps2(xlow, coef, order);
- }
- }
- /* Check if M-1 roots found */
- if(nf < M - 1)
- {
- for (i = 0; i < M; i++)
- {
- isp[i] = old_isp[i];
- }
- } else
- {
- isp[M - 1] = a[M] << 3; /* From Q12 to Q15 with saturation */
- }
- return;
+ /*---------------------------------------------------------------------*
+ * Find the ISPs (roots of F1(z) and F2(z) ) using the *
+ * Chebyshev polynomial evaluation. *
+ * The roots of F1(z) and F2(z) are alternatively searched. *
+ * We start by finding the first root of F1(z) then we switch *
+ * to F2(z) then back to F1(z) and so on until all roots are found. *
+ * *
+ * - Evaluate Chebyshev pol. at grid points and check for sign change.*
+ * - If sign change track the root by subdividing the interval *
+ * 2 times and ckecking sign change. *
+ *---------------------------------------------------------------------*/
+ nf = 0; /* number of found frequencies */
+ ip = 0; /* indicator for f1 or f2 */
+ coef = f1;
+ order = NC;
+ xlow = vogrid[0];
+ ylow = Chebps2(xlow, coef, order);
+ j = 0;
+ while ((nf < M - 1) && (j < GRID_POINTS))
+ {
+ j ++;
+ xhigh = xlow;
+ yhigh = ylow;
+ xlow = vogrid[j];
+ ylow = Chebps2(xlow, coef, order);
+ if ((ylow * yhigh) <= (Word32) 0)
+ {
+ /* divide 2 times the interval */
+ for (i = 0; i < 2; i++)
+ {
+ xmid = (xlow >> 1) + (xhigh >> 1); /* xmid = (xlow + xhigh)/2 */
+ ymid = Chebps2(xmid, coef, order);
+ if ((ylow * ymid) <= (Word32) 0)
+ {
+ yhigh = ymid;
+ xhigh = xmid;
+ } else
+ {
+ ylow = ymid;
+ xlow = xmid;
+ }
+ }
+ /*-------------------------------------------------------------*
+ * Linear interpolation *
+ * xint = xlow - ylow*(xhigh-xlow)/(yhigh-ylow); *
+ *-------------------------------------------------------------*/
+ x = xhigh - xlow;
+ y = yhigh - ylow;
+ if (y == 0)
+ {
+ xint = xlow;
+ } else
+ {
+ sign = y;
+ y = abs_s(y);
+ exp = norm_s(y);
+ y = y << exp;
+ y = div_s((Word16) 16383, y);
+ t0 = x * y;
+ t0 = (t0 >> (19 - exp));
+ y = vo_extract_l(t0); /* y= (xhigh-xlow)/(yhigh-ylow) in Q11 */
+ if (sign < 0)
+ y = -y;
+ t0 = ylow * y; /* result in Q26 */
+ t0 = (t0 >> 10); /* result in Q15 */
+ xint = vo_sub(xlow, vo_extract_l(t0)); /* xint = xlow - ylow*y */
+ }
+ isp[nf] = xint;
+ xlow = xint;
+ nf++;
+ if (ip == 0)
+ {
+ ip = 1;
+ coef = f2;
+ order = NC - 1;
+ } else
+ {
+ ip = 0;
+ coef = f1;
+ order = NC;
+ }
+ ylow = Chebps2(xlow, coef, order);
+ }
+ }
+ /* Check if M-1 roots found */
+ if(nf < M - 1)
+ {
+ for (i = 0; i < M; i++)
+ {
+ isp[i] = old_isp[i];
+ }
+ } else
+ {
+ isp[M - 1] = a[M] << 3; /* From Q12 to Q15 with saturation */
+ }
+ return;
}
/*--------------------------------------------------------------*
@@ -213,55 +213,55 @@
static __inline Word16 Chebps2(Word16 x, Word16 f[], Word32 n)
{
- Word32 i, cheb;
- Word16 b0_h, b0_l, b1_h, b1_l, b2_h, b2_l;
- Word32 t0;
+ Word32 i, cheb;
+ Word16 b0_h, b0_l, b1_h, b1_l, b2_h, b2_l;
+ Word32 t0;
- /* Note: All computation are done in Q24. */
+ /* Note: All computation are done in Q24. */
- t0 = f[0] << 13;
- b2_h = t0 >> 16;
- b2_l = (t0 & 0xffff)>>1;
+ t0 = f[0] << 13;
+ b2_h = t0 >> 16;
+ b2_l = (t0 & 0xffff)>>1;
- t0 = ((b2_h * x)<<1) + (((b2_l * x)>>15)<<1);
- t0 <<= 1;
- t0 += (f[1] << 13); /* + f[1] in Q24 */
+ t0 = ((b2_h * x)<<1) + (((b2_l * x)>>15)<<1);
+ t0 <<= 1;
+ t0 += (f[1] << 13); /* + f[1] in Q24 */
- b1_h = t0 >> 16;
- b1_l = (t0 & 0xffff) >> 1;
+ b1_h = t0 >> 16;
+ b1_l = (t0 & 0xffff) >> 1;
- for (i = 2; i < n; i++)
- {
- t0 = ((b1_h * x)<<1) + (((b1_l * x)>>15)<<1);
+ for (i = 2; i < n; i++)
+ {
+ t0 = ((b1_h * x)<<1) + (((b1_l * x)>>15)<<1);
- t0 += (b2_h * (-16384))<<1;
- t0 += (f[i] << 12);
- t0 <<= 1;
- t0 -= (b2_l << 1); /* t0 = 2.0*x*b1 - b2 + f[i]; */
+ t0 += (b2_h * (-16384))<<1;
+ t0 += (f[i] << 12);
+ t0 <<= 1;
+ t0 -= (b2_l << 1); /* t0 = 2.0*x*b1 - b2 + f[i]; */
- b0_h = t0 >> 16;
- b0_l = (t0 & 0xffff) >> 1;
+ b0_h = t0 >> 16;
+ b0_l = (t0 & 0xffff) >> 1;
- b2_l = b1_l; /* b2 = b1; */
- b2_h = b1_h;
- b1_l = b0_l; /* b1 = b0; */
- b1_h = b0_h;
- }
+ b2_l = b1_l; /* b2 = b1; */
+ b2_h = b1_h;
+ b1_l = b0_l; /* b1 = b0; */
+ b1_h = b0_h;
+ }
- t0 = ((b1_h * x)<<1) + (((b1_l * x)>>15)<<1);
- t0 += (b2_h * (-32768))<<1; /* t0 = x*b1 - b2 */
- t0 -= (b2_l << 1);
- t0 += (f[n] << 12); /* t0 = x*b1 - b2 + f[i]/2 */
+ t0 = ((b1_h * x)<<1) + (((b1_l * x)>>15)<<1);
+ t0 += (b2_h * (-32768))<<1; /* t0 = x*b1 - b2 */
+ t0 -= (b2_l << 1);
+ t0 += (f[n] << 12); /* t0 = x*b1 - b2 + f[i]/2 */
- t0 = L_shl2(t0, 6); /* Q24 to Q30 with saturation */
+ t0 = L_shl2(t0, 6); /* Q24 to Q30 with saturation */
- cheb = extract_h(t0); /* Result in Q14 */
+ cheb = extract_h(t0); /* Result in Q14 */
- if (cheb == -32768)
- {
- cheb = -32767; /* to avoid saturation in Az_isp */
- }
- return (cheb);
+ if (cheb == -32768)
+ {
+ cheb = -32767; /* to avoid saturation in Az_isp */
+ }
+ return (cheb);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/bits.c b/media/libstagefright/codecs/amrwbenc/src/bits.c
index e78dc1f..6b8bddd 100644
--- a/media/libstagefright/codecs/amrwbenc/src/bits.c
+++ b/media/libstagefright/codecs/amrwbenc/src/bits.c
@@ -17,7 +17,7 @@
/***********************************************************************
File: bits.c
- Description: Performs bit stream manipulation
+ Description: Performs bit stream manipulation
************************************************************************/
@@ -33,151 +33,151 @@
int PackBits(Word16 prms[], /* i: analysis parameters */
- Word16 coding_mode, /* i: coding bit-stream ratio mode */
- Word16 mode, /* i: coding bit-stream ratio mode*/
- Coder_State *st /*i/o: coder global parameters struct */
- )
+ Word16 coding_mode, /* i: coding bit-stream ratio mode */
+ Word16 mode, /* i: coding bit-stream ratio mode*/
+ Coder_State *st /*i/o: coder global parameters struct */
+ )
{
- Word16 i, frame_type;
- UWord8 temp;
- UWord8 *stream_ptr;
- Word16 bitstreamformat = st->frameType;
+ Word16 i, frame_type;
+ UWord8 temp;
+ UWord8 *stream_ptr;
+ Word16 bitstreamformat = st->frameType;
- unsigned short* dataOut = st->outputStream;
+ unsigned short* dataOut = st->outputStream;
- if (coding_mode == MRDTX)
- {
- st->sid_update_counter--;
+ if (coding_mode == MRDTX)
+ {
+ st->sid_update_counter--;
- if (st->prev_ft == TX_SPEECH)
- {
- frame_type = TX_SID_FIRST;
- st->sid_update_counter = 3;
- } else
- {
- if ((st->sid_handover_debt > 0) && (st->sid_update_counter > 2))
- {
- /* ensure extra updates are properly delayed after a possible SID_FIRST */
- frame_type = TX_SID_UPDATE;
- st->sid_handover_debt--;
- } else
- {
- if (st->sid_update_counter == 0)
- {
- frame_type = TX_SID_UPDATE;
- st->sid_update_counter = 8;
- } else
- {
- frame_type = TX_NO_DATA;
- }
- }
- }
- } else
- {
- st->sid_update_counter = 8;
- frame_type = TX_SPEECH;
- }
- st->prev_ft = frame_type;
+ if (st->prev_ft == TX_SPEECH)
+ {
+ frame_type = TX_SID_FIRST;
+ st->sid_update_counter = 3;
+ } else
+ {
+ if ((st->sid_handover_debt > 0) && (st->sid_update_counter > 2))
+ {
+ /* ensure extra updates are properly delayed after a possible SID_FIRST */
+ frame_type = TX_SID_UPDATE;
+ st->sid_handover_debt--;
+ } else
+ {
+ if (st->sid_update_counter == 0)
+ {
+ frame_type = TX_SID_UPDATE;
+ st->sid_update_counter = 8;
+ } else
+ {
+ frame_type = TX_NO_DATA;
+ }
+ }
+ }
+ } else
+ {
+ st->sid_update_counter = 8;
+ frame_type = TX_SPEECH;
+ }
+ st->prev_ft = frame_type;
- if(bitstreamformat == 0) /* default file format */
- {
- *(dataOut) = TX_FRAME_TYPE;
- *(dataOut + 1) = frame_type;
- *(dataOut + 2) = mode;
- for (i = 0; i < nb_of_bits[coding_mode]; i++)
- {
- *(dataOut + 3 + i) = prms[i];
- }
- return (3 + nb_of_bits[coding_mode])<<1;
- } else
- {
- if (bitstreamformat == 1) /* ITU file format */
- {
- *(dataOut) = 0x6b21;
- if(frame_type != TX_NO_DATA && frame_type != TX_SID_FIRST)
- {
- *(dataOut + 1) = nb_of_bits[coding_mode];
- for (i = 0; i < nb_of_bits[coding_mode]; i++)
- {
- if(prms[i] == BIT_0){
- *(dataOut + 2 + i) = BIT_0_ITU;
- }
- else{
- *(dataOut + 2 + i) = BIT_1_ITU;
- }
- }
- return (2 + nb_of_bits[coding_mode])<<1;
- } else
- {
- *(dataOut + 1) = 0;
- return 2<<1;
- }
- } else /* MIME/storage file format */
- {
+ if(bitstreamformat == 0) /* default file format */
+ {
+ *(dataOut) = TX_FRAME_TYPE;
+ *(dataOut + 1) = frame_type;
+ *(dataOut + 2) = mode;
+ for (i = 0; i < nb_of_bits[coding_mode]; i++)
+ {
+ *(dataOut + 3 + i) = prms[i];
+ }
+ return (3 + nb_of_bits[coding_mode])<<1;
+ } else
+ {
+ if (bitstreamformat == 1) /* ITU file format */
+ {
+ *(dataOut) = 0x6b21;
+ if(frame_type != TX_NO_DATA && frame_type != TX_SID_FIRST)
+ {
+ *(dataOut + 1) = nb_of_bits[coding_mode];
+ for (i = 0; i < nb_of_bits[coding_mode]; i++)
+ {
+ if(prms[i] == BIT_0){
+ *(dataOut + 2 + i) = BIT_0_ITU;
+ }
+ else{
+ *(dataOut + 2 + i) = BIT_1_ITU;
+ }
+ }
+ return (2 + nb_of_bits[coding_mode])<<1;
+ } else
+ {
+ *(dataOut + 1) = 0;
+ return 2<<1;
+ }
+ } else /* MIME/storage file format */
+ {
#define MRSID 9
- /* change mode index in case of SID frame */
- if (coding_mode == MRDTX)
- {
- coding_mode = MRSID;
- if (frame_type == TX_SID_FIRST)
- {
- for (i = 0; i < NBBITS_SID; i++) prms[i] = BIT_0;
- }
- }
- /* -> force NO_DATA frame */
- if (coding_mode < 0 || coding_mode > 15 || (coding_mode > MRSID && coding_mode < 14))
- {
- coding_mode = 15;
- }
- /* mark empty frames between SID updates as NO_DATA frames */
- if (coding_mode == MRSID && frame_type == TX_NO_DATA)
- {
- coding_mode = 15;
- }
- /* set pointer for packed frame, note that we handle data as bytes */
- stream_ptr = (UWord8*)dataOut;
- /* insert table of contents (ToC) byte at the beginning of the packet */
- *stream_ptr = toc_byte[coding_mode];
- stream_ptr++;
- temp = 0;
- /* sort and pack AMR-WB speech or SID bits */
- for (i = 1; i < unpacked_size[coding_mode] + 1; i++)
- {
- if (prms[sort_ptr[coding_mode][i-1]] == BIT_1)
- {
- temp++;
- }
- if (i&0x7)
- {
- temp <<= 1;
- }
- else
- {
- *stream_ptr = temp;
- stream_ptr++;
- temp = 0;
- }
- }
- /* insert SID type indication and speech mode in case of SID frame */
- if (coding_mode == MRSID)
- {
- if (frame_type == TX_SID_UPDATE)
- {
- temp++;
- }
- temp <<= 4;
- temp += mode & 0x000F;
- }
- /* insert unused bits (zeros) at the tail of the last byte */
- if (unused_size[coding_mode])
- {
- temp <<= (unused_size[coding_mode] - 1);
- }
- *stream_ptr = temp;
- /* write packed frame into file (1 byte added to cover ToC entry) */
- return (1 + packed_size[coding_mode]);
- }
- }
+ /* change mode index in case of SID frame */
+ if (coding_mode == MRDTX)
+ {
+ coding_mode = MRSID;
+ if (frame_type == TX_SID_FIRST)
+ {
+ for (i = 0; i < NBBITS_SID; i++) prms[i] = BIT_0;
+ }
+ }
+ /* -> force NO_DATA frame */
+ if (coding_mode < 0 || coding_mode > 15 || (coding_mode > MRSID && coding_mode < 14))
+ {
+ coding_mode = 15;
+ }
+ /* mark empty frames between SID updates as NO_DATA frames */
+ if (coding_mode == MRSID && frame_type == TX_NO_DATA)
+ {
+ coding_mode = 15;
+ }
+ /* set pointer for packed frame, note that we handle data as bytes */
+ stream_ptr = (UWord8*)dataOut;
+ /* insert table of contents (ToC) byte at the beginning of the packet */
+ *stream_ptr = toc_byte[coding_mode];
+ stream_ptr++;
+ temp = 0;
+ /* sort and pack AMR-WB speech or SID bits */
+ for (i = 1; i < unpacked_size[coding_mode] + 1; i++)
+ {
+ if (prms[sort_ptr[coding_mode][i-1]] == BIT_1)
+ {
+ temp++;
+ }
+ if (i&0x7)
+ {
+ temp <<= 1;
+ }
+ else
+ {
+ *stream_ptr = temp;
+ stream_ptr++;
+ temp = 0;
+ }
+ }
+ /* insert SID type indication and speech mode in case of SID frame */
+ if (coding_mode == MRSID)
+ {
+ if (frame_type == TX_SID_UPDATE)
+ {
+ temp++;
+ }
+ temp <<= 4;
+ temp += mode & 0x000F;
+ }
+ /* insert unused bits (zeros) at the tail of the last byte */
+ if (unused_size[coding_mode])
+ {
+ temp <<= (unused_size[coding_mode] - 1);
+ }
+ *stream_ptr = temp;
+ /* write packed frame into file (1 byte added to cover ToC entry) */
+ return (1 + packed_size[coding_mode]);
+ }
+ }
}
/*-----------------------------------------------------*
@@ -185,24 +185,24 @@
*-----------------------------------------------------*/
void Parm_serial(
- Word16 value, /* input : parameter value */
- Word16 no_of_bits, /* input : number of bits */
- Word16 ** prms
- )
+ Word16 value, /* input : parameter value */
+ Word16 no_of_bits, /* input : number of bits */
+ Word16 ** prms
+ )
{
- Word16 i, bit;
- *prms += no_of_bits;
- for (i = 0; i < no_of_bits; i++)
- {
- bit = (Word16) (value & 0x0001); /* get lsb */
- if (bit == 0)
- *--(*prms) = BIT_0;
- else
- *--(*prms) = BIT_1;
- value >>= 1;
- }
- *prms += no_of_bits;
- return;
+ Word16 i, bit;
+ *prms += no_of_bits;
+ for (i = 0; i < no_of_bits; i++)
+ {
+ bit = (Word16) (value & 0x0001); /* get lsb */
+ if (bit == 0)
+ *--(*prms) = BIT_0;
+ else
+ *--(*prms) = BIT_1;
+ value >>= 1;
+ }
+ *prms += no_of_bits;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/c2t64fx.c b/media/libstagefright/codecs/amrwbenc/src/c2t64fx.c
index 18698e2..dbb94c6 100644
--- a/media/libstagefright/codecs/amrwbenc/src/c2t64fx.c
+++ b/media/libstagefright/codecs/amrwbenc/src/c2t64fx.c
@@ -17,7 +17,7 @@
/************************************************************************
* File: c2t64fx.c *
* *
-* Description:Performs algebraic codebook search for 6.60kbits mode*
+* Description:Performs algebraic codebook search for 6.60kbits mode*
* *
*************************************************************************/
@@ -45,252 +45,255 @@
**************************************************************************/
void ACELP_2t64_fx(
- Word16 dn[], /* (i) <12b : correlation between target x[] and H[] */
- Word16 cn[], /* (i) <12b : residual after long term prediction */
- Word16 H[], /* (i) Q12: impulse response of weighted synthesis filter */
- Word16 code[], /* (o) Q9 : algebraic (fixed) codebook excitation */
- Word16 y[], /* (o) Q9 : filtered fixed codebook excitation */
- Word16 * index /* (o) : index (12): 5+1+5+1 = 11 bits. */
- )
+ Word16 dn[], /* (i) <12b : correlation between target x[] and H[] */
+ Word16 cn[], /* (i) <12b : residual after long term prediction */
+ Word16 H[], /* (i) Q12: impulse response of weighted synthesis filter */
+ Word16 code[], /* (o) Q9 : algebraic (fixed) codebook excitation */
+ Word16 y[], /* (o) Q9 : filtered fixed codebook excitation */
+ Word16 * index /* (o) : index (12): 5+1+5+1 = 11 bits. */
+ )
{
- Word32 i, j, k, i0, i1, ix, iy, pos, pos2;
- Word16 ps, psk, ps1, ps2, alpk, alp1, alp2, sq;
- Word16 alp, val, exp, k_cn, k_dn;
- Word16 *p0, *p1, *p2, *psign;
- Word16 *h, *h_inv, *ptr_h1, *ptr_h2, *ptr_hf;
+ Word32 i, j, k, i0, i1, ix, iy, pos, pos2;
+ Word16 ps, psk, ps1, ps2, alpk, alp1, alp2, sq;
+ Word16 alp, val, exp, k_cn, k_dn;
+ Word16 *p0, *p1, *p2, *psign;
+ Word16 *h, *h_inv, *ptr_h1, *ptr_h2, *ptr_hf;
- Word16 sign[L_SUBFR], vec[L_SUBFR], dn2[L_SUBFR];
- Word16 h_buf[4 * L_SUBFR] = {0};
- Word16 rrixix[NB_TRACK][NB_POS];
- Word16 rrixiy[MSIZE];
- Word32 s, cor;
+ Word16 sign[L_SUBFR], vec[L_SUBFR], dn2[L_SUBFR];
+ Word16 h_buf[4 * L_SUBFR] = {0};
+ Word16 rrixix[NB_TRACK][NB_POS];
+ Word16 rrixiy[MSIZE];
+ Word32 s, cor;
- /*----------------------------------------------------------------*
- * Find sign for each pulse position. *
- *----------------------------------------------------------------*/
- alp = 8192; /* alp = 2.0 (Q12) */
+ /*----------------------------------------------------------------*
+ * Find sign for each pulse position. *
+ *----------------------------------------------------------------*/
+ alp = 8192; /* alp = 2.0 (Q12) */
- /* calculate energy for normalization of cn[] and dn[] */
- /* set k_cn = 32..32767 (ener_cn = 2^30..256-0) */
+ /* calculate energy for normalization of cn[] and dn[] */
+ /* set k_cn = 32..32767 (ener_cn = 2^30..256-0) */
#ifdef ASM_OPT /* asm optimization branch */
- s = Dot_product12_asm(cn, cn, L_SUBFR, &exp);
+ s = Dot_product12_asm(cn, cn, L_SUBFR, &exp);
#else
- s = Dot_product12(cn, cn, L_SUBFR, &exp);
+ s = Dot_product12(cn, cn, L_SUBFR, &exp);
#endif
- Isqrt_n(&s, &exp);
- s = L_shl(s, add1(exp, 5));
- k_cn = vo_round(s);
+ Isqrt_n(&s, &exp);
+ s = L_shl(s, add1(exp, 5));
+ if (s > INT_MAX - 0x8000) {
+ s = INT_MAX - 0x8000;
+ }
+ k_cn = vo_round(s);
- /* set k_dn = 32..512 (ener_dn = 2^30..2^22) */
+ /* set k_dn = 32..512 (ener_dn = 2^30..2^22) */
#ifdef ASM_OPT /* asm optimization branch */
- s = Dot_product12_asm(dn, dn, L_SUBFR, &exp);
+ s = Dot_product12_asm(dn, dn, L_SUBFR, &exp);
#else
- s = Dot_product12(dn, dn, L_SUBFR, &exp);
+ s = Dot_product12(dn, dn, L_SUBFR, &exp);
#endif
- Isqrt_n(&s, &exp);
- k_dn = vo_round(L_shl(s, (exp + 8))); /* k_dn = 256..4096 */
- k_dn = vo_mult_r(alp, k_dn); /* alp in Q12 */
+ Isqrt_n(&s, &exp);
+ k_dn = voround(L_shl(s, (exp + 8))); /* k_dn = 256..4096 */
+ k_dn = vo_mult_r(alp, k_dn); /* alp in Q12 */
- /* mix normalized cn[] and dn[] */
- p0 = cn;
- p1 = dn;
- p2 = dn2;
+ /* mix normalized cn[] and dn[] */
+ p0 = cn;
+ p1 = dn;
+ p2 = dn2;
- for (i = 0; i < L_SUBFR/4; i++)
- {
- s = (k_cn* (*p0++))+(k_dn * (*p1++));
- *p2++ = s >> 7;
- s = (k_cn* (*p0++))+(k_dn * (*p1++));
- *p2++ = s >> 7;
- s = (k_cn* (*p0++))+(k_dn * (*p1++));
- *p2++ = s >> 7;
- s = (k_cn* (*p0++))+(k_dn * (*p1++));
- *p2++ = s >> 7;
- }
+ for (i = 0; i < L_SUBFR/4; i++)
+ {
+ s = (k_cn* (*p0++))+(k_dn * (*p1++));
+ *p2++ = s >> 7;
+ s = (k_cn* (*p0++))+(k_dn * (*p1++));
+ *p2++ = s >> 7;
+ s = (k_cn* (*p0++))+(k_dn * (*p1++));
+ *p2++ = s >> 7;
+ s = (k_cn* (*p0++))+(k_dn * (*p1++));
+ *p2++ = s >> 7;
+ }
- /* set sign according to dn2[] = k_cn*cn[] + k_dn*dn[] */
- for (i = 0; i < L_SUBFR; i ++)
- {
- val = dn[i];
- ps = dn2[i];
- if (ps >= 0)
- {
- sign[i] = 32767; /* sign = +1 (Q12) */
- vec[i] = -32768;
- } else
- {
- sign[i] = -32768; /* sign = -1 (Q12) */
- vec[i] = 32767;
- dn[i] = -val;
- }
- }
- /*------------------------------------------------------------*
- * Compute h_inv[i]. *
- *------------------------------------------------------------*/
- /* impulse response buffer for fast computation */
- h = h_buf + L_SUBFR;
- h_inv = h + (L_SUBFR<<1);
+ /* set sign according to dn2[] = k_cn*cn[] + k_dn*dn[] */
+ for (i = 0; i < L_SUBFR; i ++)
+ {
+ val = dn[i];
+ ps = dn2[i];
+ if (ps >= 0)
+ {
+ sign[i] = 32767; /* sign = +1 (Q12) */
+ vec[i] = -32768;
+ } else
+ {
+ sign[i] = -32768; /* sign = -1 (Q12) */
+ vec[i] = 32767;
+ dn[i] = -val;
+ }
+ }
+ /*------------------------------------------------------------*
+ * Compute h_inv[i]. *
+ *------------------------------------------------------------*/
+ /* impulse response buffer for fast computation */
+ h = h_buf + L_SUBFR;
+ h_inv = h + (L_SUBFR<<1);
- for (i = 0; i < L_SUBFR; i++)
- {
- h[i] = H[i];
- h_inv[i] = vo_negate(h[i]);
- }
+ for (i = 0; i < L_SUBFR; i++)
+ {
+ h[i] = H[i];
+ h_inv[i] = vo_negate(h[i]);
+ }
- /*------------------------------------------------------------*
- * Compute rrixix[][] needed for the codebook search. *
- * Result is multiplied by 0.5 *
- *------------------------------------------------------------*/
- /* Init pointers to last position of rrixix[] */
- p0 = &rrixix[0][NB_POS - 1];
- p1 = &rrixix[1][NB_POS - 1];
+ /*------------------------------------------------------------*
+ * Compute rrixix[][] needed for the codebook search. *
+ * Result is multiplied by 0.5 *
+ *------------------------------------------------------------*/
+ /* Init pointers to last position of rrixix[] */
+ p0 = &rrixix[0][NB_POS - 1];
+ p1 = &rrixix[1][NB_POS - 1];
- ptr_h1 = h;
- cor = 0x00010000L; /* for rounding */
- for (i = 0; i < NB_POS; i++)
- {
- cor += ((*ptr_h1) * (*ptr_h1) << 1);
- ptr_h1++;
- *p1-- = (extract_h(cor) >> 1);
- cor += ((*ptr_h1) * (*ptr_h1) << 1);
- ptr_h1++;
- *p0-- = (extract_h(cor) >> 1);
- }
+ ptr_h1 = h;
+ cor = 0x00010000L; /* for rounding */
+ for (i = 0; i < NB_POS; i++)
+ {
+ cor += ((*ptr_h1) * (*ptr_h1) << 1);
+ ptr_h1++;
+ *p1-- = (extract_h(cor) >> 1);
+ cor += ((*ptr_h1) * (*ptr_h1) << 1);
+ ptr_h1++;
+ *p0-- = (extract_h(cor) >> 1);
+ }
- /*------------------------------------------------------------*
- * Compute rrixiy[][] needed for the codebook search. *
- *------------------------------------------------------------*/
- pos = MSIZE - 1;
- pos2 = MSIZE - 2;
- ptr_hf = h + 1;
+ /*------------------------------------------------------------*
+ * Compute rrixiy[][] needed for the codebook search. *
+ *------------------------------------------------------------*/
+ pos = MSIZE - 1;
+ pos2 = MSIZE - 2;
+ ptr_hf = h + 1;
- for (k = 0; k < NB_POS; k++)
- {
- p1 = &rrixiy[pos];
- p0 = &rrixiy[pos2];
- cor = 0x00008000L; /* for rounding */
- ptr_h1 = h;
- ptr_h2 = ptr_hf;
+ for (k = 0; k < NB_POS; k++)
+ {
+ p1 = &rrixiy[pos];
+ p0 = &rrixiy[pos2];
+ cor = 0x00008000L; /* for rounding */
+ ptr_h1 = h;
+ ptr_h2 = ptr_hf;
- for (i = (k + 1); i < NB_POS; i++)
- {
- cor += ((*ptr_h1) * (*ptr_h2))<<1;
- ptr_h1++;
- ptr_h2++;
- *p1 = extract_h(cor);
- cor += ((*ptr_h1) * (*ptr_h2))<<1;
- ptr_h1++;
- ptr_h2++;
- *p0 = extract_h(cor);
+ for (i = (k + 1); i < NB_POS; i++)
+ {
+ cor += ((*ptr_h1) * (*ptr_h2))<<1;
+ ptr_h1++;
+ ptr_h2++;
+ *p1 = extract_h(cor);
+ cor += ((*ptr_h1) * (*ptr_h2))<<1;
+ ptr_h1++;
+ ptr_h2++;
+ *p0 = extract_h(cor);
- p1 -= (NB_POS + 1);
- p0 -= (NB_POS + 1);
- }
- cor += ((*ptr_h1) * (*ptr_h2))<<1;
- ptr_h1++;
- ptr_h2++;
- *p1 = extract_h(cor);
+ p1 -= (NB_POS + 1);
+ p0 -= (NB_POS + 1);
+ }
+ cor += ((*ptr_h1) * (*ptr_h2))<<1;
+ ptr_h1++;
+ ptr_h2++;
+ *p1 = extract_h(cor);
- pos -= NB_POS;
- pos2--;
- ptr_hf += STEP;
- }
+ pos -= NB_POS;
+ pos2--;
+ ptr_hf += STEP;
+ }
- /*------------------------------------------------------------*
- * Modification of rrixiy[][] to take signs into account. *
- *------------------------------------------------------------*/
- p0 = rrixiy;
- for (i = 0; i < L_SUBFR; i += STEP)
- {
- psign = sign;
- if (psign[i] < 0)
- {
- psign = vec;
- }
- for (j = 1; j < L_SUBFR; j += STEP)
- {
- *p0 = vo_mult(*p0, psign[j]);
- p0++;
- }
- }
- /*-------------------------------------------------------------------*
- * search 2 pulses: *
- * ~@~~~~~~~~~~~~~~ *
- * 32 pos x 32 pos = 1024 tests (all combinaisons is tested) *
- *-------------------------------------------------------------------*/
- p0 = rrixix[0];
- p1 = rrixix[1];
- p2 = rrixiy;
+ /*------------------------------------------------------------*
+ * Modification of rrixiy[][] to take signs into account. *
+ *------------------------------------------------------------*/
+ p0 = rrixiy;
+ for (i = 0; i < L_SUBFR; i += STEP)
+ {
+ psign = sign;
+ if (psign[i] < 0)
+ {
+ psign = vec;
+ }
+ for (j = 1; j < L_SUBFR; j += STEP)
+ {
+ *p0 = vo_mult(*p0, psign[j]);
+ p0++;
+ }
+ }
+ /*-------------------------------------------------------------------*
+ * search 2 pulses: *
+ * ~@~~~~~~~~~~~~~~ *
+ * 32 pos x 32 pos = 1024 tests (all combinaisons is tested) *
+ *-------------------------------------------------------------------*/
+ p0 = rrixix[0];
+ p1 = rrixix[1];
+ p2 = rrixiy;
- psk = -1;
- alpk = 1;
- ix = 0;
- iy = 1;
+ psk = -1;
+ alpk = 1;
+ ix = 0;
+ iy = 1;
- for (i0 = 0; i0 < L_SUBFR; i0 += STEP)
- {
- ps1 = dn[i0];
- alp1 = (*p0++);
- pos = -1;
- for (i1 = 1; i1 < L_SUBFR; i1 += STEP)
- {
- ps2 = add1(ps1, dn[i1]);
- alp2 = add1(alp1, add1(*p1++, *p2++));
- sq = vo_mult(ps2, ps2);
- s = vo_L_mult(alpk, sq) - ((psk * alp2)<<1);
- if (s > 0)
- {
- psk = sq;
- alpk = alp2;
- pos = i1;
- }
- }
- p1 -= NB_POS;
- if (pos >= 0)
- {
- ix = i0;
- iy = pos;
- }
- }
- /*-------------------------------------------------------------------*
- * Build the codeword, the filtered codeword and index of codevector.*
- *-------------------------------------------------------------------*/
+ for (i0 = 0; i0 < L_SUBFR; i0 += STEP)
+ {
+ ps1 = dn[i0];
+ alp1 = (*p0++);
+ pos = -1;
+ for (i1 = 1; i1 < L_SUBFR; i1 += STEP)
+ {
+ ps2 = add1(ps1, dn[i1]);
+ alp2 = add1(alp1, add1(*p1++, *p2++));
+ sq = vo_mult(ps2, ps2);
+ s = vo_L_mult(alpk, sq) - ((psk * alp2)<<1);
+ if (s > 0)
+ {
+ psk = sq;
+ alpk = alp2;
+ pos = i1;
+ }
+ }
+ p1 -= NB_POS;
+ if (pos >= 0)
+ {
+ ix = i0;
+ iy = pos;
+ }
+ }
+ /*-------------------------------------------------------------------*
+ * Build the codeword, the filtered codeword and index of codevector.*
+ *-------------------------------------------------------------------*/
- for (i = 0; i < L_SUBFR; i++)
- {
- code[i] = 0;
- }
+ for (i = 0; i < L_SUBFR; i++)
+ {
+ code[i] = 0;
+ }
- i0 = (ix >> 1); /* pos of pulse 1 (0..31) */
- i1 = (iy >> 1); /* pos of pulse 2 (0..31) */
- if (sign[ix] > 0)
- {
- code[ix] = 512; /* codeword in Q9 format */
- p0 = h - ix;
- } else
- {
- code[ix] = -512;
- i0 += NB_POS;
- p0 = h_inv - ix;
- }
- if (sign[iy] > 0)
- {
- code[iy] = 512;
- p1 = h - iy;
- } else
- {
- code[iy] = -512;
- i1 += NB_POS;
- p1 = h_inv - iy;
- }
- *index = add1((i0 << 6), i1);
- for (i = 0; i < L_SUBFR; i++)
- {
- y[i] = vo_shr_r(add1((*p0++), (*p1++)), 3);
- }
- return;
+ i0 = (ix >> 1); /* pos of pulse 1 (0..31) */
+ i1 = (iy >> 1); /* pos of pulse 2 (0..31) */
+ if (sign[ix] > 0)
+ {
+ code[ix] = 512; /* codeword in Q9 format */
+ p0 = h - ix;
+ } else
+ {
+ code[ix] = -512;
+ i0 += NB_POS;
+ p0 = h_inv - ix;
+ }
+ if (sign[iy] > 0)
+ {
+ code[iy] = 512;
+ p1 = h - iy;
+ } else
+ {
+ code[iy] = -512;
+ i1 += NB_POS;
+ p1 = h_inv - iy;
+ }
+ *index = add1((i0 << 6), i1);
+ for (i = 0; i < L_SUBFR; i++)
+ {
+ y[i] = vo_shr_r(add1((*p0++), (*p1++)), 3);
+ }
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c b/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
index 1ecc11f..8bf15ea 100644
--- a/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
+++ b/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
@@ -17,7 +17,7 @@
/***********************************************************************
* File: c4t64fx.c *
* *
-* Description:Performs algebraic codebook search for higher modes *
+* Description:Performs algebraic codebook search for higher modes *
* *
************************************************************************/
@@ -48,15 +48,15 @@
#include "q_pulse.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 */
- 2, 3, 0, 1, /* starting point &ipos[8], 3rd iter */
- 3, 0, 1, 2, /* starting point &ipos[12], 4th iter */
- 0, 1, 2, 3,
- 1, 2, 3, 0,
- 2, 3, 0, 1,
- 3, 0, 1, 2,
- 0, 1, 2, 3}; /* end point for 24 pulses &ipos[35], 4th iter */
+ 0, 1, 2, 3, /* starting point &ipos[0], 1st iter */
+ 1, 2, 3, 0, /* starting point &ipos[4], 2nd iter */
+ 2, 3, 0, 1, /* starting point &ipos[8], 3rd iter */
+ 3, 0, 1, 2, /* starting point &ipos[12], 4th iter */
+ 0, 1, 2, 3,
+ 1, 2, 3, 0,
+ 2, 3, 0, 1,
+ 3, 0, 1, 2,
+ 0, 1, 2, 3}; /* end point for 24 pulses &ipos[35], 4th iter */
#define NB_PULSE_MAX 24
@@ -70,751 +70,759 @@
/* Private functions */
void cor_h_vec_012(
- Word16 h[], /* (i) scaled impulse response */
- Word16 vec[], /* (i) scaled vector (/8) to correlate with h[] */
- Word16 track, /* (i) track to use */
- Word16 sign[], /* (i) sign vector */
- Word16 rrixix[][NB_POS], /* (i) correlation of h[x] with h[x] */
- Word16 cor_1[], /* (o) result of correlation (NB_POS elements) */
- Word16 cor_2[] /* (o) result of correlation (NB_POS elements) */
- );
+ Word16 h[], /* (i) scaled impulse response */
+ Word16 vec[], /* (i) scaled vector (/8) to correlate with h[] */
+ Word16 track, /* (i) track to use */
+ Word16 sign[], /* (i) sign vector */
+ Word16 rrixix[][NB_POS], /* (i) correlation of h[x] with h[x] */
+ Word16 cor_1[], /* (o) result of correlation (NB_POS elements) */
+ Word16 cor_2[] /* (o) result of correlation (NB_POS elements) */
+ );
void cor_h_vec_012_asm(
- Word16 h[], /* (i) scaled impulse response */
- Word16 vec[], /* (i) scaled vector (/8) to correlate with h[] */
- Word16 track, /* (i) track to use */
- Word16 sign[], /* (i) sign vector */
- Word16 rrixix[][NB_POS], /* (i) correlation of h[x] with h[x] */
- Word16 cor_1[], /* (o) result of correlation (NB_POS elements) */
- Word16 cor_2[] /* (o) result of correlation (NB_POS elements) */
- );
+ Word16 h[], /* (i) scaled impulse response */
+ Word16 vec[], /* (i) scaled vector (/8) to correlate with h[] */
+ Word16 track, /* (i) track to use */
+ Word16 sign[], /* (i) sign vector */
+ Word16 rrixix[][NB_POS], /* (i) correlation of h[x] with h[x] */
+ Word16 cor_1[], /* (o) result of correlation (NB_POS elements) */
+ Word16 cor_2[] /* (o) result of correlation (NB_POS elements) */
+ );
void cor_h_vec_30(
- Word16 h[], /* (i) scaled impulse response */
- Word16 vec[], /* (i) scaled vector (/8) to correlate with h[] */
- Word16 track, /* (i) track to use */
- Word16 sign[], /* (i) sign vector */
- Word16 rrixix[][NB_POS], /* (i) correlation of h[x] with h[x] */
- Word16 cor_1[], /* (o) result of correlation (NB_POS elements) */
- Word16 cor_2[] /* (o) result of correlation (NB_POS elements) */
- );
+ Word16 h[], /* (i) scaled impulse response */
+ Word16 vec[], /* (i) scaled vector (/8) to correlate with h[] */
+ Word16 track, /* (i) track to use */
+ Word16 sign[], /* (i) sign vector */
+ Word16 rrixix[][NB_POS], /* (i) correlation of h[x] with h[x] */
+ Word16 cor_1[], /* (o) result of correlation (NB_POS elements) */
+ Word16 cor_2[] /* (o) result of correlation (NB_POS elements) */
+ );
void search_ixiy(
- Word16 nb_pos_ix, /* (i) nb of pos for pulse 1 (1..8) */
- Word16 track_x, /* (i) track of pulse 1 */
- Word16 track_y, /* (i) track of pulse 2 */
- Word16 * ps, /* (i/o) correlation of all fixed pulses */
- Word16 * alp, /* (i/o) energy of all fixed pulses */
- Word16 * ix, /* (o) position of pulse 1 */
- Word16 * iy, /* (o) position of pulse 2 */
- Word16 dn[], /* (i) corr. between target and h[] */
- Word16 dn2[], /* (i) vector of selected positions */
- Word16 cor_x[], /* (i) corr. of pulse 1 with fixed pulses */
- Word16 cor_y[], /* (i) corr. of pulse 2 with fixed pulses */
- Word16 rrixiy[][MSIZE] /* (i) corr. of pulse 1 with pulse 2 */
- );
+ Word16 nb_pos_ix, /* (i) nb of pos for pulse 1 (1..8) */
+ Word16 track_x, /* (i) track of pulse 1 */
+ Word16 track_y, /* (i) track of pulse 2 */
+ Word16 * ps, /* (i/o) correlation of all fixed pulses */
+ Word16 * alp, /* (i/o) energy of all fixed pulses */
+ Word16 * ix, /* (o) position of pulse 1 */
+ Word16 * iy, /* (o) position of pulse 2 */
+ Word16 dn[], /* (i) corr. between target and h[] */
+ Word16 dn2[], /* (i) vector of selected positions */
+ Word16 cor_x[], /* (i) corr. of pulse 1 with fixed pulses */
+ Word16 cor_y[], /* (i) corr. of pulse 2 with fixed pulses */
+ Word16 rrixiy[][MSIZE] /* (i) corr. of pulse 1 with pulse 2 */
+ );
void ACELP_4t64_fx(
- Word16 dn[], /* (i) <12b : correlation between target x[] and H[] */
- Word16 cn[], /* (i) <12b : residual after long term prediction */
- Word16 H[], /* (i) Q12: impulse response of weighted synthesis filter */
- Word16 code[], /* (o) Q9 : algebraic (fixed) codebook excitation */
- Word16 y[], /* (o) Q9 : filtered fixed codebook excitation */
- Word16 nbbits, /* (i) : 20, 36, 44, 52, 64, 72 or 88 bits */
- Word16 ser_size, /* (i) : bit rate */
- Word16 _index[] /* (o) : index (20): 5+5+5+5 = 20 bits. */
- /* (o) : index (36): 9+9+9+9 = 36 bits. */
- /* (o) : index (44): 13+9+13+9 = 44 bits. */
- /* (o) : index (52): 13+13+13+13 = 52 bits. */
- /* (o) : index (64): 2+2+2+2+14+14+14+14 = 64 bits. */
- /* (o) : index (72): 10+2+10+2+10+14+10+14 = 72 bits. */
- /* (o) : index (88): 11+11+11+11+11+11+11+11 = 88 bits. */
- )
+ Word16 dn[], /* (i) <12b : correlation between target x[] and H[] */
+ Word16 cn[], /* (i) <12b : residual after long term prediction */
+ Word16 H[], /* (i) Q12: impulse response of weighted synthesis filter */
+ Word16 code[], /* (o) Q9 : algebraic (fixed) codebook excitation */
+ Word16 y[], /* (o) Q9 : filtered fixed codebook excitation */
+ Word16 nbbits, /* (i) : 20, 36, 44, 52, 64, 72 or 88 bits */
+ Word16 ser_size, /* (i) : bit rate */
+ Word16 _index[] /* (o) : index (20): 5+5+5+5 = 20 bits. */
+ /* (o) : index (36): 9+9+9+9 = 36 bits. */
+ /* (o) : index (44): 13+9+13+9 = 44 bits. */
+ /* (o) : index (52): 13+13+13+13 = 52 bits. */
+ /* (o) : index (64): 2+2+2+2+14+14+14+14 = 64 bits. */
+ /* (o) : index (72): 10+2+10+2+10+14+10+14 = 72 bits. */
+ /* (o) : index (88): 11+11+11+11+11+11+11+11 = 88 bits. */
+ )
{
- Word32 i, j, k;
- Word16 st, ix, iy, pos, index, track, nb_pulse, nbiter, j_temp;
- Word16 psk, ps, alpk, alp, val, k_cn, k_dn, exp;
- Word16 *p0, *p1, *p2, *p3, *psign;
- Word16 *h, *h_inv, *ptr_h1, *ptr_h2, *ptr_hf, h_shift;
- Word32 s, cor, L_tmp, L_index;
- Word16 dn2[L_SUBFR], sign[L_SUBFR], vec[L_SUBFR];
- Word16 ind[NPMAXPT * NB_TRACK];
- Word16 codvec[NB_PULSE_MAX], nbpos[10];
- Word16 cor_x[NB_POS], cor_y[NB_POS], pos_max[NB_TRACK];
- Word16 h_buf[4 * L_SUBFR];
- Word16 rrixix[NB_TRACK][NB_POS], rrixiy[NB_TRACK][MSIZE];
- Word16 ipos[NB_PULSE_MAX];
+ Word32 i, j, k;
+ Word16 st, ix, iy, pos, index, track, nb_pulse, nbiter, j_temp;
+ Word16 psk, ps, alpk, alp, val, k_cn, k_dn, exp;
+ Word16 *p0, *p1, *p2, *p3, *psign;
+ Word16 *h, *h_inv, *ptr_h1, *ptr_h2, *ptr_hf, h_shift;
+ Word32 s, cor, L_tmp, L_index;
+ Word16 dn2[L_SUBFR], sign[L_SUBFR], vec[L_SUBFR];
+ Word16 ind[NPMAXPT * NB_TRACK];
+ Word16 codvec[NB_PULSE_MAX], nbpos[10];
+ Word16 cor_x[NB_POS], cor_y[NB_POS], pos_max[NB_TRACK];
+ Word16 h_buf[4 * L_SUBFR];
+ Word16 rrixix[NB_TRACK][NB_POS], rrixiy[NB_TRACK][MSIZE];
+ Word16 ipos[NB_PULSE_MAX];
- switch (nbbits)
- {
- case 20: /* 20 bits, 4 pulses, 4 tracks */
- nbiter = 4; /* 4x16x16=1024 loop */
- alp = 8192; /* alp = 2.0 (Q12) */
- nb_pulse = 4;
- nbpos[0] = 4;
- nbpos[1] = 8;
- break;
- case 36: /* 36 bits, 8 pulses, 4 tracks */
- nbiter = 4; /* 4x20x16=1280 loop */
- alp = 4096; /* alp = 1.0 (Q12) */
- nb_pulse = 8;
- nbpos[0] = 4;
- nbpos[1] = 8;
- nbpos[2] = 8;
- break;
- case 44: /* 44 bits, 10 pulses, 4 tracks */
- nbiter = 4; /* 4x26x16=1664 loop */
- alp = 4096; /* alp = 1.0 (Q12) */
- nb_pulse = 10;
- nbpos[0] = 4;
- nbpos[1] = 6;
- nbpos[2] = 8;
- nbpos[3] = 8;
- break;
- case 52: /* 52 bits, 12 pulses, 4 tracks */
- nbiter = 4; /* 4x26x16=1664 loop */
- alp = 4096; /* alp = 1.0 (Q12) */
- nb_pulse = 12;
- nbpos[0] = 4;
- nbpos[1] = 6;
- nbpos[2] = 8;
- nbpos[3] = 8;
- break;
- case 64: /* 64 bits, 16 pulses, 4 tracks */
- nbiter = 3; /* 3x36x16=1728 loop */
- alp = 3277; /* alp = 0.8 (Q12) */
- nb_pulse = 16;
- nbpos[0] = 4;
- nbpos[1] = 4;
- nbpos[2] = 6;
- nbpos[3] = 6;
- nbpos[4] = 8;
- nbpos[5] = 8;
- break;
- case 72: /* 72 bits, 18 pulses, 4 tracks */
- nbiter = 3; /* 3x35x16=1680 loop */
- alp = 3072; /* alp = 0.75 (Q12) */
- nb_pulse = 18;
- nbpos[0] = 2;
- nbpos[1] = 3;
- nbpos[2] = 4;
- nbpos[3] = 5;
- nbpos[4] = 6;
- nbpos[5] = 7;
- nbpos[6] = 8;
- break;
- case 88: /* 88 bits, 24 pulses, 4 tracks */
- if(ser_size > 462)
- nbiter = 1;
- else
- nbiter = 2; /* 2x53x16=1696 loop */
+ switch (nbbits)
+ {
+ case 20: /* 20 bits, 4 pulses, 4 tracks */
+ nbiter = 4; /* 4x16x16=1024 loop */
+ alp = 8192; /* alp = 2.0 (Q12) */
+ nb_pulse = 4;
+ nbpos[0] = 4;
+ nbpos[1] = 8;
+ break;
+ case 36: /* 36 bits, 8 pulses, 4 tracks */
+ nbiter = 4; /* 4x20x16=1280 loop */
+ alp = 4096; /* alp = 1.0 (Q12) */
+ nb_pulse = 8;
+ nbpos[0] = 4;
+ nbpos[1] = 8;
+ nbpos[2] = 8;
+ break;
+ case 44: /* 44 bits, 10 pulses, 4 tracks */
+ nbiter = 4; /* 4x26x16=1664 loop */
+ alp = 4096; /* alp = 1.0 (Q12) */
+ nb_pulse = 10;
+ nbpos[0] = 4;
+ nbpos[1] = 6;
+ nbpos[2] = 8;
+ nbpos[3] = 8;
+ break;
+ case 52: /* 52 bits, 12 pulses, 4 tracks */
+ nbiter = 4; /* 4x26x16=1664 loop */
+ alp = 4096; /* alp = 1.0 (Q12) */
+ nb_pulse = 12;
+ nbpos[0] = 4;
+ nbpos[1] = 6;
+ nbpos[2] = 8;
+ nbpos[3] = 8;
+ break;
+ case 64: /* 64 bits, 16 pulses, 4 tracks */
+ nbiter = 3; /* 3x36x16=1728 loop */
+ alp = 3277; /* alp = 0.8 (Q12) */
+ nb_pulse = 16;
+ nbpos[0] = 4;
+ nbpos[1] = 4;
+ nbpos[2] = 6;
+ nbpos[3] = 6;
+ nbpos[4] = 8;
+ nbpos[5] = 8;
+ break;
+ case 72: /* 72 bits, 18 pulses, 4 tracks */
+ nbiter = 3; /* 3x35x16=1680 loop */
+ alp = 3072; /* alp = 0.75 (Q12) */
+ nb_pulse = 18;
+ nbpos[0] = 2;
+ nbpos[1] = 3;
+ nbpos[2] = 4;
+ nbpos[3] = 5;
+ nbpos[4] = 6;
+ nbpos[5] = 7;
+ nbpos[6] = 8;
+ break;
+ case 88: /* 88 bits, 24 pulses, 4 tracks */
+ if(ser_size > 462)
+ nbiter = 1;
+ else
+ nbiter = 2; /* 2x53x16=1696 loop */
- alp = 2048; /* alp = 0.5 (Q12) */
- nb_pulse = 24;
- nbpos[0] = 2;
- nbpos[1] = 2;
- nbpos[2] = 3;
- nbpos[3] = 4;
- nbpos[4] = 5;
- nbpos[5] = 6;
- nbpos[6] = 7;
- nbpos[7] = 8;
- nbpos[8] = 8;
- nbpos[9] = 8;
- break;
- default:
- nbiter = 0;
- alp = 0;
- nb_pulse = 0;
- }
+ alp = 2048; /* alp = 0.5 (Q12) */
+ nb_pulse = 24;
+ nbpos[0] = 2;
+ nbpos[1] = 2;
+ nbpos[2] = 3;
+ nbpos[3] = 4;
+ nbpos[4] = 5;
+ nbpos[5] = 6;
+ nbpos[6] = 7;
+ nbpos[7] = 8;
+ nbpos[8] = 8;
+ nbpos[9] = 8;
+ break;
+ default:
+ nbiter = 0;
+ alp = 0;
+ nb_pulse = 0;
+ }
- for (i = 0; i < nb_pulse; i++)
- {
- codvec[i] = i;
- }
+ for (i = 0; i < nb_pulse; i++)
+ {
+ codvec[i] = i;
+ }
- /*----------------------------------------------------------------*
- * Find sign for each pulse position. *
- *----------------------------------------------------------------*/
- /* calculate energy for normalization of cn[] and dn[] */
- /* set k_cn = 32..32767 (ener_cn = 2^30..256-0) */
+ /*----------------------------------------------------------------*
+ * Find sign for each pulse position. *
+ *----------------------------------------------------------------*/
+ /* calculate energy for normalization of cn[] and dn[] */
+ /* set k_cn = 32..32767 (ener_cn = 2^30..256-0) */
#ifdef ASM_OPT /* asm optimization branch */
- s = Dot_product12_asm(cn, cn, L_SUBFR, &exp);
+ s = Dot_product12_asm(cn, cn, L_SUBFR, &exp);
#else
- s = Dot_product12(cn, cn, L_SUBFR, &exp);
+ s = Dot_product12(cn, cn, L_SUBFR, &exp);
#endif
- Isqrt_n(&s, &exp);
- s = L_shl(s, (exp + 5));
- k_cn = extract_h(L_add(s, 0x8000));
+ Isqrt_n(&s, &exp);
+ s = L_shl(s, (exp + 5));
+ k_cn = extract_h(L_add(s, 0x8000));
- /* set k_dn = 32..512 (ener_dn = 2^30..2^22) */
+ /* set k_dn = 32..512 (ener_dn = 2^30..2^22) */
#ifdef ASM_OPT /* asm optimization branch */
- s = Dot_product12_asm(dn, dn, L_SUBFR, &exp);
+ s = Dot_product12_asm(dn, dn, L_SUBFR, &exp);
#else
- s = Dot_product12(dn, dn, L_SUBFR, &exp);
+ s = Dot_product12(dn, dn, L_SUBFR, &exp);
#endif
- Isqrt_n(&s, &exp);
- k_dn = (L_shl(s, (exp + 5 + 3)) + 0x8000) >> 16; /* k_dn = 256..4096 */
- k_dn = vo_mult_r(alp, k_dn); /* alp in Q12 */
+ Isqrt_n(&s, &exp);
+ k_dn = voround(L_shl(s, (exp + 5 + 3))); /* k_dn = 256..4096 */
+ k_dn = vo_mult_r(alp, k_dn); /* alp in Q12 */
- /* mix normalized cn[] and dn[] */
- p0 = cn;
- p1 = dn;
- p2 = dn2;
+ /* mix normalized cn[] and dn[] */
+ p0 = cn;
+ p1 = dn;
+ p2 = dn2;
- for (i = 0; i < L_SUBFR/4; i++)
- {
- s = (k_cn* (*p0++))+(k_dn * (*p1++));
- *p2++ = s >> 7;
- s = (k_cn* (*p0++))+(k_dn * (*p1++));
- *p2++ = s >> 7;
- s = (k_cn* (*p0++))+(k_dn * (*p1++));
- *p2++ = s >> 7;
- s = (k_cn* (*p0++))+(k_dn * (*p1++));
- *p2++ = s >> 7;
- }
+ for (i = 0; i < L_SUBFR/4; i++)
+ {
+ s = (k_cn* (*p0++))+(k_dn * (*p1++));
+ *p2++ = s >> 7;
+ s = (k_cn* (*p0++))+(k_dn * (*p1++));
+ *p2++ = s >> 7;
+ s = (k_cn* (*p0++))+(k_dn * (*p1++));
+ *p2++ = s >> 7;
+ s = (k_cn* (*p0++))+(k_dn * (*p1++));
+ *p2++ = s >> 7;
+ }
- /* set sign according to dn2[] = k_cn*cn[] + k_dn*dn[] */
- for(i = 0; i < L_SUBFR; i++)
- {
- val = dn[i];
- ps = dn2[i];
- if (ps >= 0)
- {
- sign[i] = 32767; /* sign = +1 (Q12) */
- vec[i] = -32768;
- } else
- {
- sign[i] = -32768; /* sign = -1 (Q12) */
- vec[i] = 32767;
- dn[i] = -val;
- dn2[i] = -ps;
- }
- }
- /*----------------------------------------------------------------*
- * Select NB_MAX position per track according to max of dn2[]. *
- *----------------------------------------------------------------*/
- pos = 0;
- for (i = 0; i < NB_TRACK; i++)
- {
- for (k = 0; k < NB_MAX; k++)
- {
- ps = -1;
- for (j = i; j < L_SUBFR; j += STEP)
- {
- if(dn2[j] > ps)
- {
- ps = dn2[j];
- pos = j;
- }
- }
- dn2[pos] = (k - NB_MAX); /* dn2 < 0 when position is selected */
- if (k == 0)
- {
- pos_max[i] = pos;
- }
- }
- }
+ /* set sign according to dn2[] = k_cn*cn[] + k_dn*dn[] */
+ for(i = 0; i < L_SUBFR; i++)
+ {
+ val = dn[i];
+ ps = dn2[i];
+ if (ps >= 0)
+ {
+ sign[i] = 32767; /* sign = +1 (Q12) */
+ vec[i] = -32768;
+ } else
+ {
+ sign[i] = -32768; /* sign = -1 (Q12) */
+ vec[i] = 32767;
+ dn[i] = -val;
+ dn2[i] = -ps;
+ }
+ }
+ /*----------------------------------------------------------------*
+ * Select NB_MAX position per track according to max of dn2[]. *
+ *----------------------------------------------------------------*/
+ pos = 0;
+ for (i = 0; i < NB_TRACK; i++)
+ {
+ for (k = 0; k < NB_MAX; k++)
+ {
+ ps = -1;
+ for (j = i; j < L_SUBFR; j += STEP)
+ {
+ if(dn2[j] > ps)
+ {
+ ps = dn2[j];
+ pos = j;
+ }
+ }
+ dn2[pos] = (k - NB_MAX); /* dn2 < 0 when position is selected */
+ if (k == 0)
+ {
+ pos_max[i] = pos;
+ }
+ }
+ }
- /*--------------------------------------------------------------*
- * Scale h[] to avoid overflow and to get maximum of precision *
- * on correlation. *
- * *
- * Maximum of h[] (h[0]) is fixed to 2048 (MAX16 / 16). *
- * ==> This allow addition of 16 pulses without saturation. *
- * *
- * Energy worst case (on resonant impulse response), *
- * - energy of h[] is approximately MAX/16. *
- * - During search, the energy is divided by 8 to avoid *
- * overflow on "alp". (energy of h[] = MAX/128). *
- * ==> "alp" worst case detected is 22854 on sinusoidal wave. *
- *--------------------------------------------------------------*/
+ /*--------------------------------------------------------------*
+ * Scale h[] to avoid overflow and to get maximum of precision *
+ * on correlation. *
+ * *
+ * Maximum of h[] (h[0]) is fixed to 2048 (MAX16 / 16). *
+ * ==> This allow addition of 16 pulses without saturation. *
+ * *
+ * Energy worst case (on resonant impulse response), *
+ * - energy of h[] is approximately MAX/16. *
+ * - During search, the energy is divided by 8 to avoid *
+ * overflow on "alp". (energy of h[] = MAX/128). *
+ * ==> "alp" worst case detected is 22854 on sinusoidal wave. *
+ *--------------------------------------------------------------*/
- /* impulse response buffer for fast computation */
+ /* impulse response buffer for fast computation */
- h = h_buf;
- h_inv = h_buf + (2 * L_SUBFR);
- L_tmp = 0;
- for (i = 0; i < L_SUBFR; i++)
- {
- *h++ = 0;
- *h_inv++ = 0;
- L_tmp += (H[i] * H[i]) << 1;
- }
- /* scale h[] down (/2) when energy of h[] is high with many pulses used */
- val = extract_h(L_tmp);
- h_shift = 0;
+ h = h_buf;
+ h_inv = h_buf + (2 * L_SUBFR);
+ L_tmp = 0;
+ for (i = 0; i < L_SUBFR; i++)
+ {
+ *h++ = 0;
+ *h_inv++ = 0;
+ L_tmp += (H[i] * H[i]) << 1;
+ }
+ /* scale h[] down (/2) when energy of h[] is high with many pulses used */
+ val = extract_h(L_tmp);
+ h_shift = 0;
- if ((nb_pulse >= 12) && (val > 1024))
- {
- h_shift = 1;
- }
- p0 = H;
- p1 = h;
- p2 = h_inv;
+ if ((nb_pulse >= 12) && (val > 1024))
+ {
+ h_shift = 1;
+ }
+ p0 = H;
+ p1 = h;
+ p2 = h_inv;
- for (i = 0; i < L_SUBFR/4; i++)
- {
- *p1 = *p0++ >> h_shift;
- *p2++ = -(*p1++);
- *p1 = *p0++ >> h_shift;
- *p2++ = -(*p1++);
- *p1 = *p0++ >> h_shift;
- *p2++ = -(*p1++);
- *p1 = *p0++ >> h_shift;
- *p2++ = -(*p1++);
- }
+ for (i = 0; i < L_SUBFR/4; i++)
+ {
+ *p1 = *p0++ >> h_shift;
+ *p2++ = -(*p1++);
+ *p1 = *p0++ >> h_shift;
+ *p2++ = -(*p1++);
+ *p1 = *p0++ >> h_shift;
+ *p2++ = -(*p1++);
+ *p1 = *p0++ >> h_shift;
+ *p2++ = -(*p1++);
+ }
- /*------------------------------------------------------------*
- * Compute rrixix[][] needed for the codebook search. *
- * This algorithm compute impulse response energy of all *
- * positions (16) in each track (4). Total = 4x16 = 64. *
- *------------------------------------------------------------*/
+ /*------------------------------------------------------------*
+ * Compute rrixix[][] needed for the codebook search. *
+ * This algorithm compute impulse response energy of all *
+ * positions (16) in each track (4). Total = 4x16 = 64. *
+ *------------------------------------------------------------*/
- /* storage order --> i3i3, i2i2, i1i1, i0i0 */
+ /* storage order --> i3i3, i2i2, i1i1, i0i0 */
- /* Init pointers to last position of rrixix[] */
- p0 = &rrixix[0][NB_POS - 1];
- p1 = &rrixix[1][NB_POS - 1];
- p2 = &rrixix[2][NB_POS - 1];
- p3 = &rrixix[3][NB_POS - 1];
+ /* Init pointers to last position of rrixix[] */
+ p0 = &rrixix[0][NB_POS - 1];
+ p1 = &rrixix[1][NB_POS - 1];
+ p2 = &rrixix[2][NB_POS - 1];
+ p3 = &rrixix[3][NB_POS - 1];
- ptr_h1 = h;
- cor = 0x00008000L; /* for rounding */
- for (i = 0; i < NB_POS; i++)
- {
- cor += vo_L_mult((*ptr_h1), (*ptr_h1));
- ptr_h1++;
- *p3-- = extract_h(cor);
- cor += vo_L_mult((*ptr_h1), (*ptr_h1));
- ptr_h1++;
- *p2-- = extract_h(cor);
- cor += vo_L_mult((*ptr_h1), (*ptr_h1));
- ptr_h1++;
- *p1-- = extract_h(cor);
- cor += vo_L_mult((*ptr_h1), (*ptr_h1));
- ptr_h1++;
- *p0-- = extract_h(cor);
- }
+ ptr_h1 = h;
+ cor = 0x00008000L; /* for rounding */
+ for (i = 0; i < NB_POS; i++)
+ {
+ cor += vo_L_mult((*ptr_h1), (*ptr_h1));
+ ptr_h1++;
+ *p3-- = extract_h(cor);
+ cor += vo_L_mult((*ptr_h1), (*ptr_h1));
+ ptr_h1++;
+ *p2-- = extract_h(cor);
+ cor += vo_L_mult((*ptr_h1), (*ptr_h1));
+ ptr_h1++;
+ *p1-- = extract_h(cor);
+ cor += vo_L_mult((*ptr_h1), (*ptr_h1));
+ ptr_h1++;
+ *p0-- = extract_h(cor);
+ }
- /*------------------------------------------------------------*
- * Compute rrixiy[][] needed for the codebook search. *
- * This algorithm compute correlation between 2 pulses *
- * (2 impulses responses) in 4 possible adjacents tracks. *
- * (track 0-1, 1-2, 2-3 and 3-0). Total = 4x16x16 = 1024. *
- *------------------------------------------------------------*/
+ /*------------------------------------------------------------*
+ * Compute rrixiy[][] needed for the codebook search. *
+ * This algorithm compute correlation between 2 pulses *
+ * (2 impulses responses) in 4 possible adjacents tracks. *
+ * (track 0-1, 1-2, 2-3 and 3-0). Total = 4x16x16 = 1024. *
+ *------------------------------------------------------------*/
- /* storage order --> i2i3, i1i2, i0i1, i3i0 */
+ /* storage order --> i2i3, i1i2, i0i1, i3i0 */
- pos = MSIZE - 1;
- ptr_hf = h + 1;
+ pos = MSIZE - 1;
+ ptr_hf = h + 1;
- for (k = 0; k < NB_POS; k++)
- {
- p3 = &rrixiy[2][pos];
- p2 = &rrixiy[1][pos];
- p1 = &rrixiy[0][pos];
- p0 = &rrixiy[3][pos - NB_POS];
+ for (k = 0; k < NB_POS; k++)
+ {
+ p3 = &rrixiy[2][pos];
+ p2 = &rrixiy[1][pos];
+ p1 = &rrixiy[0][pos];
+ p0 = &rrixiy[3][pos - NB_POS];
- cor = 0x00008000L; /* for rounding */
- ptr_h1 = h;
- ptr_h2 = ptr_hf;
+ cor = 0x00008000L; /* for rounding */
+ ptr_h1 = h;
+ ptr_h2 = ptr_hf;
- for (i = k + 1; i < NB_POS; i++)
- {
- cor += vo_L_mult((*ptr_h1), (*ptr_h2));
- ptr_h1++;
- ptr_h2++;
- *p3 = extract_h(cor);
- cor += vo_L_mult((*ptr_h1), (*ptr_h2));
- ptr_h1++;
- ptr_h2++;
- *p2 = extract_h(cor);
- cor += vo_L_mult((*ptr_h1), (*ptr_h2));
- ptr_h1++;
- ptr_h2++;
- *p1 = extract_h(cor);
- cor += vo_L_mult((*ptr_h1), (*ptr_h2));
- ptr_h1++;
- ptr_h2++;
- *p0 = extract_h(cor);
+ for (i = k + 1; i < NB_POS; i++)
+ {
+ cor += vo_L_mult((*ptr_h1), (*ptr_h2));
+ ptr_h1++;
+ ptr_h2++;
+ *p3 = extract_h(cor);
+ cor += vo_L_mult((*ptr_h1), (*ptr_h2));
+ ptr_h1++;
+ ptr_h2++;
+ *p2 = extract_h(cor);
+ cor += vo_L_mult((*ptr_h1), (*ptr_h2));
+ ptr_h1++;
+ ptr_h2++;
+ *p1 = extract_h(cor);
+ cor += vo_L_mult((*ptr_h1), (*ptr_h2));
+ ptr_h1++;
+ ptr_h2++;
+ *p0 = extract_h(cor);
- p3 -= (NB_POS + 1);
- p2 -= (NB_POS + 1);
- p1 -= (NB_POS + 1);
- p0 -= (NB_POS + 1);
- }
- cor += vo_L_mult((*ptr_h1), (*ptr_h2));
- ptr_h1++;
- ptr_h2++;
- *p3 = extract_h(cor);
- cor += vo_L_mult((*ptr_h1), (*ptr_h2));
- ptr_h1++;
- ptr_h2++;
- *p2 = extract_h(cor);
- cor += vo_L_mult((*ptr_h1), (*ptr_h2));
- ptr_h1++;
- ptr_h2++;
- *p1 = extract_h(cor);
+ p3 -= (NB_POS + 1);
+ p2 -= (NB_POS + 1);
+ p1 -= (NB_POS + 1);
+ p0 -= (NB_POS + 1);
+ }
+ cor += vo_L_mult((*ptr_h1), (*ptr_h2));
+ ptr_h1++;
+ ptr_h2++;
+ *p3 = extract_h(cor);
+ cor += vo_L_mult((*ptr_h1), (*ptr_h2));
+ ptr_h1++;
+ ptr_h2++;
+ *p2 = extract_h(cor);
+ cor += vo_L_mult((*ptr_h1), (*ptr_h2));
+ ptr_h1++;
+ ptr_h2++;
+ *p1 = extract_h(cor);
- pos -= NB_POS;
- ptr_hf += STEP;
- }
+ pos -= NB_POS;
+ ptr_hf += STEP;
+ }
- /* storage order --> i3i0, i2i3, i1i2, i0i1 */
+ /* storage order --> i3i0, i2i3, i1i2, i0i1 */
- pos = MSIZE - 1;
- ptr_hf = h + 3;
+ pos = MSIZE - 1;
+ ptr_hf = h + 3;
- for (k = 0; k < NB_POS; k++)
- {
- p3 = &rrixiy[3][pos];
- p2 = &rrixiy[2][pos - 1];
- p1 = &rrixiy[1][pos - 1];
- p0 = &rrixiy[0][pos - 1];
+ for (k = 0; k < NB_POS; k++)
+ {
+ p3 = &rrixiy[3][pos];
+ p2 = &rrixiy[2][pos - 1];
+ p1 = &rrixiy[1][pos - 1];
+ p0 = &rrixiy[0][pos - 1];
- cor = 0x00008000L; /* for rounding */
- ptr_h1 = h;
- ptr_h2 = ptr_hf;
+ cor = 0x00008000L; /* for rounding */
+ ptr_h1 = h;
+ ptr_h2 = ptr_hf;
- for (i = k + 1; i < NB_POS; i++)
- {
- cor += vo_L_mult((*ptr_h1), (*ptr_h2));
- ptr_h1++;
- ptr_h2++;
- *p3 = extract_h(cor);
- cor += vo_L_mult((*ptr_h1), (*ptr_h2));
- ptr_h1++;
- ptr_h2++;
- *p2 = extract_h(cor);
- cor += vo_L_mult((*ptr_h1), (*ptr_h2));
- ptr_h1++;
- ptr_h2++;
- *p1 = extract_h(cor);
- cor += vo_L_mult((*ptr_h1), (*ptr_h2));
- ptr_h1++;
- ptr_h2++;
- *p0 = extract_h(cor);
+ for (i = k + 1; i < NB_POS; i++)
+ {
+ cor += vo_L_mult((*ptr_h1), (*ptr_h2));
+ ptr_h1++;
+ ptr_h2++;
+ *p3 = extract_h(cor);
+ cor += vo_L_mult((*ptr_h1), (*ptr_h2));
+ ptr_h1++;
+ ptr_h2++;
+ *p2 = extract_h(cor);
+ cor += vo_L_mult((*ptr_h1), (*ptr_h2));
+ ptr_h1++;
+ ptr_h2++;
+ *p1 = extract_h(cor);
+ cor += vo_L_mult((*ptr_h1), (*ptr_h2));
+ ptr_h1++;
+ ptr_h2++;
+ *p0 = extract_h(cor);
- p3 -= (NB_POS + 1);
- p2 -= (NB_POS + 1);
- p1 -= (NB_POS + 1);
- p0 -= (NB_POS + 1);
- }
- cor += vo_L_mult((*ptr_h1), (*ptr_h2));
- ptr_h1++;
- ptr_h2++;
- *p3 = extract_h(cor);
+ p3 -= (NB_POS + 1);
+ p2 -= (NB_POS + 1);
+ p1 -= (NB_POS + 1);
+ p0 -= (NB_POS + 1);
+ }
+ cor += vo_L_mult((*ptr_h1), (*ptr_h2));
+ ptr_h1++;
+ ptr_h2++;
+ *p3 = extract_h(cor);
- pos--;
- ptr_hf += STEP;
- }
+ pos--;
+ ptr_hf += STEP;
+ }
- /*------------------------------------------------------------*
- * Modification of rrixiy[][] to take signs into account. *
- *------------------------------------------------------------*/
+ /*------------------------------------------------------------*
+ * Modification of rrixiy[][] to take signs into account. *
+ *------------------------------------------------------------*/
- p0 = &rrixiy[0][0];
+ p0 = &rrixiy[0][0];
- for (k = 0; k < NB_TRACK; k++)
- {
- j_temp = (k + 1)&0x03;
- for (i = k; i < L_SUBFR; i += STEP)
- {
- psign = sign;
- if (psign[i] < 0)
- {
- psign = vec;
- }
- j = j_temp;
- for (; j < L_SUBFR; j += STEP)
- {
- *p0 = vo_mult(*p0, psign[j]);
- p0++;
- }
- }
- }
+ for (k = 0; k < NB_TRACK; k++)
+ {
+ j_temp = (k + 1)&0x03;
+ for (i = k; i < L_SUBFR; i += STEP)
+ {
+ psign = sign;
+ if (psign[i] < 0)
+ {
+ psign = vec;
+ }
+ j = j_temp;
+ for (; j < L_SUBFR; j += STEP)
+ {
+ *p0 = vo_mult(*p0, psign[j]);
+ p0++;
+ }
+ }
+ }
- /*-------------------------------------------------------------------*
- * Deep first search *
- *-------------------------------------------------------------------*/
+ /*-------------------------------------------------------------------*
+ * Deep first search *
+ *-------------------------------------------------------------------*/
- psk = -1;
- alpk = 1;
+ psk = -1;
+ alpk = 1;
- for (k = 0; k < nbiter; k++)
- {
- j_temp = k<<2;
- for (i = 0; i < nb_pulse; i++)
- ipos[i] = tipos[j_temp + i];
+ for (k = 0; k < nbiter; k++)
+ {
+ j_temp = k<<2;
+ for (i = 0; i < nb_pulse; i++)
+ ipos[i] = tipos[j_temp + i];
- if(nbbits == 20)
- {
- pos = 0;
- ps = 0;
- alp = 0;
- for (i = 0; i < L_SUBFR; i++)
- {
- vec[i] = 0;
- }
- } else if ((nbbits == 36) || (nbbits == 44))
- {
- /* first stage: fix 2 pulses */
- pos = 2;
+ if(nbbits == 20)
+ {
+ pos = 0;
+ ps = 0;
+ alp = 0;
+ for (i = 0; i < L_SUBFR; i++)
+ {
+ vec[i] = 0;
+ }
+ } else if ((nbbits == 36) || (nbbits == 44))
+ {
+ /* first stage: fix 2 pulses */
+ pos = 2;
- ix = ind[0] = pos_max[ipos[0]];
- iy = ind[1] = pos_max[ipos[1]];
- ps = dn[ix] + dn[iy];
- i = ix >> 2; /* ix / STEP */
- j = iy >> 2; /* iy / STEP */
- s = rrixix[ipos[0]][i] << 13;
- s += rrixix[ipos[1]][j] << 13;
- i = (i << 4) + j; /* (ix/STEP)*NB_POS + (iy/STEP) */
- s += rrixiy[ipos[0]][i] << 14;
- alp = (s + 0x8000) >> 16;
- if (sign[ix] < 0)
- p0 = h_inv - ix;
- else
- p0 = h - ix;
- if (sign[iy] < 0)
- p1 = h_inv - iy;
- else
- p1 = h - iy;
+ ix = ind[0] = pos_max[ipos[0]];
+ iy = ind[1] = pos_max[ipos[1]];
+ ps = dn[ix] + dn[iy];
+ i = ix >> 2; /* ix / STEP */
+ j = iy >> 2; /* iy / STEP */
+ s = rrixix[ipos[0]][i] << 13;
+ s += rrixix[ipos[1]][j] << 13;
+ i = (i << 4) + j; /* (ix/STEP)*NB_POS + (iy/STEP) */
+ s += rrixiy[ipos[0]][i] << 14;
+ alp = (s + 0x8000) >> 16;
+ if (sign[ix] < 0)
+ p0 = h_inv - ix;
+ else
+ p0 = h - ix;
+ if (sign[iy] < 0)
+ p1 = h_inv - iy;
+ else
+ p1 = h - iy;
- for (i = 0; i < L_SUBFR; i++)
- {
- vec[i] = (*p0++) + (*p1++);
- }
+ for (i = 0; i < L_SUBFR; i++)
+ {
+ vec[i] = (*p0++) + (*p1++);
+ }
- if(nbbits == 44)
- {
- ipos[8] = 0;
- ipos[9] = 1;
- }
- } else
- {
- /* first stage: fix 4 pulses */
- pos = 4;
+ if(nbbits == 44)
+ {
+ ipos[8] = 0;
+ ipos[9] = 1;
+ }
+ } else
+ {
+ /* first stage: fix 4 pulses */
+ pos = 4;
- ix = ind[0] = pos_max[ipos[0]];
- iy = ind[1] = pos_max[ipos[1]];
- i = ind[2] = pos_max[ipos[2]];
- j = ind[3] = pos_max[ipos[3]];
- ps = add1(add1(add1(dn[ix], dn[iy]), dn[i]), dn[j]);
+ ix = ind[0] = pos_max[ipos[0]];
+ iy = ind[1] = pos_max[ipos[1]];
+ i = ind[2] = pos_max[ipos[2]];
+ j = ind[3] = pos_max[ipos[3]];
+ ps = add1(add1(add1(dn[ix], dn[iy]), dn[i]), dn[j]);
- if (sign[ix] < 0)
- p0 = h_inv - ix;
- else
- p0 = h - ix;
+ if (sign[ix] < 0)
+ p0 = h_inv - ix;
+ else
+ p0 = h - ix;
- if (sign[iy] < 0)
- p1 = h_inv - iy;
- else
- p1 = h - iy;
+ if (sign[iy] < 0)
+ p1 = h_inv - iy;
+ else
+ p1 = h - iy;
- if (sign[i] < 0)
- p2 = h_inv - i;
- else
- p2 = h - i;
+ if (sign[i] < 0)
+ p2 = h_inv - i;
+ else
+ p2 = h - i;
- if (sign[j] < 0)
- p3 = h_inv - j;
- else
- p3 = h - j;
+ if (sign[j] < 0)
+ p3 = h_inv - j;
+ else
+ p3 = h - j;
- L_tmp = 0L;
- for(i = 0; i < L_SUBFR; i++)
- {
- vec[i] = add1(add1(add1(*p0++, *p1++), *p2++), *p3++);
- L_tmp += (vec[i] * vec[i]) << 1;
- }
+ L_tmp = 0L;
+ for(i = 0; i < L_SUBFR; i++)
+ {
+ Word32 vecSq2;
+ vec[i] = add1(add1(add1(*p0++, *p1++), *p2++), *p3++);
+ vecSq2 = (vec[i] * vec[i]) << 1;
+ if (vecSq2 > 0 && L_tmp > INT_MAX - vecSq2) {
+ L_tmp = INT_MAX;
+ } else if (vecSq2 < 0 && L_tmp < INT_MIN - vecSq2) {
+ L_tmp = INT_MIN;
+ } else {
+ L_tmp += vecSq2;
+ }
+ }
- alp = ((L_tmp >> 3) + 0x8000) >> 16;
+ alp = ((L_tmp >> 3) + 0x8000) >> 16;
- if(nbbits == 72)
- {
- ipos[16] = 0;
- ipos[17] = 1;
- }
- }
+ if(nbbits == 72)
+ {
+ ipos[16] = 0;
+ ipos[17] = 1;
+ }
+ }
- /* other stages of 2 pulses */
+ /* other stages of 2 pulses */
- for (j = pos, st = 0; j < nb_pulse; j += 2, st++)
- {
- /*--------------------------------------------------*
- * Calculate correlation of all possible positions *
- * of the next 2 pulses with previous fixed pulses. *
- * Each pulse can have 16 possible positions. *
- *--------------------------------------------------*/
- if(ipos[j] == 3)
- {
- cor_h_vec_30(h, vec, ipos[j], sign, rrixix, cor_x, cor_y);
- }
- else
- {
+ for (j = pos, st = 0; j < nb_pulse; j += 2, st++)
+ {
+ /*--------------------------------------------------*
+ * Calculate correlation of all possible positions *
+ * of the next 2 pulses with previous fixed pulses. *
+ * Each pulse can have 16 possible positions. *
+ *--------------------------------------------------*/
+ if(ipos[j] == 3)
+ {
+ cor_h_vec_30(h, vec, ipos[j], sign, rrixix, cor_x, cor_y);
+ }
+ else
+ {
#ifdef ASM_OPT /* asm optimization branch */
- cor_h_vec_012_asm(h, vec, ipos[j], sign, rrixix, cor_x, cor_y);
+ cor_h_vec_012_asm(h, vec, ipos[j], sign, rrixix, cor_x, cor_y);
#else
- cor_h_vec_012(h, vec, ipos[j], sign, rrixix, cor_x, cor_y);
+ cor_h_vec_012(h, vec, ipos[j], sign, rrixix, cor_x, cor_y);
#endif
- }
- /*--------------------------------------------------*
- * Find best positions of 2 pulses. *
- *--------------------------------------------------*/
- search_ixiy(nbpos[st], ipos[j], ipos[j + 1], &ps, &alp,
- &ix, &iy, dn, dn2, cor_x, cor_y, rrixiy);
+ }
+ /*--------------------------------------------------*
+ * Find best positions of 2 pulses. *
+ *--------------------------------------------------*/
+ search_ixiy(nbpos[st], ipos[j], ipos[j + 1], &ps, &alp,
+ &ix, &iy, dn, dn2, cor_x, cor_y, rrixiy);
- ind[j] = ix;
- ind[j + 1] = iy;
+ ind[j] = ix;
+ ind[j + 1] = iy;
- if (sign[ix] < 0)
- p0 = h_inv - ix;
- else
- p0 = h - ix;
- if (sign[iy] < 0)
- p1 = h_inv - iy;
- else
- p1 = h - iy;
+ if (sign[ix] < 0)
+ p0 = h_inv - ix;
+ else
+ p0 = h - ix;
+ if (sign[iy] < 0)
+ p1 = h_inv - iy;
+ else
+ p1 = h - iy;
- for (i = 0; i < L_SUBFR; i+=4)
- {
- vec[i] += add1((*p0++), (*p1++));
- vec[i+1] += add1((*p0++), (*p1++));
- vec[i+2] += add1((*p0++), (*p1++));
- vec[i+3] += add1((*p0++), (*p1++));
- }
- }
- /* memorise the best codevector */
- ps = vo_mult(ps, ps);
- s = vo_L_msu(vo_L_mult(alpk, ps), psk, alp);
- if (s > 0)
- {
- psk = ps;
- alpk = alp;
- for (i = 0; i < nb_pulse; i++)
- {
- codvec[i] = ind[i];
- }
- for (i = 0; i < L_SUBFR; i++)
- {
- y[i] = vec[i];
- }
- }
- }
- /*-------------------------------------------------------------------*
- * Build the codeword, the filtered codeword and index of codevector.*
- *-------------------------------------------------------------------*/
- for (i = 0; i < NPMAXPT * NB_TRACK; i++)
- {
- ind[i] = -1;
- }
- for (i = 0; i < L_SUBFR; i++)
- {
- code[i] = 0;
- y[i] = vo_shr_r(y[i], 3); /* Q12 to Q9 */
- }
- val = (512 >> h_shift); /* codeword in Q9 format */
- for (k = 0; k < nb_pulse; k++)
- {
- i = codvec[k]; /* read pulse position */
- j = sign[i]; /* read sign */
- index = i >> 2; /* index = pos of pulse (0..15) */
- track = (Word16) (i & 0x03); /* track = i % NB_TRACK (0..3) */
+ for (i = 0; i < L_SUBFR; i+=4)
+ {
+ vec[i] += add1((*p0++), (*p1++));
+ vec[i+1] += add1((*p0++), (*p1++));
+ vec[i+2] += add1((*p0++), (*p1++));
+ vec[i+3] += add1((*p0++), (*p1++));
+ }
+ }
+ /* memorise the best codevector */
+ ps = vo_mult(ps, ps);
+ s = vo_L_msu(vo_L_mult(alpk, ps), psk, alp);
+ if (s > 0)
+ {
+ psk = ps;
+ alpk = alp;
+ for (i = 0; i < nb_pulse; i++)
+ {
+ codvec[i] = ind[i];
+ }
+ for (i = 0; i < L_SUBFR; i++)
+ {
+ y[i] = vec[i];
+ }
+ }
+ }
+ /*-------------------------------------------------------------------*
+ * Build the codeword, the filtered codeword and index of codevector.*
+ *-------------------------------------------------------------------*/
+ for (i = 0; i < NPMAXPT * NB_TRACK; i++)
+ {
+ ind[i] = -1;
+ }
+ for (i = 0; i < L_SUBFR; i++)
+ {
+ code[i] = 0;
+ y[i] = vo_shr_r(y[i], 3); /* Q12 to Q9 */
+ }
+ val = (512 >> h_shift); /* codeword in Q9 format */
+ for (k = 0; k < nb_pulse; k++)
+ {
+ i = codvec[k]; /* read pulse position */
+ j = sign[i]; /* read sign */
+ index = i >> 2; /* index = pos of pulse (0..15) */
+ track = (Word16) (i & 0x03); /* track = i % NB_TRACK (0..3) */
- if (j > 0)
- {
- code[i] += val;
- codvec[k] += 128;
- } else
- {
- code[i] -= val;
- index += NB_POS;
- }
+ if (j > 0)
+ {
+ code[i] += val;
+ codvec[k] += 128;
+ } else
+ {
+ code[i] -= val;
+ index += NB_POS;
+ }
- i = (Word16)((vo_L_mult(track, NPMAXPT) >> 1));
+ i = (Word16)((vo_L_mult(track, NPMAXPT) >> 1));
- while (ind[i] >= 0)
- {
- i += 1;
- }
- ind[i] = index;
- }
+ while (ind[i] >= 0)
+ {
+ i += 1;
+ }
+ ind[i] = index;
+ }
- k = 0;
- /* Build index of codevector */
- if(nbbits == 20)
- {
- for (track = 0; track < NB_TRACK; track++)
- {
- _index[track] = (Word16)(quant_1p_N1(ind[k], 4));
- k += NPMAXPT;
- }
- } else if(nbbits == 36)
- {
- for (track = 0; track < NB_TRACK; track++)
- {
- _index[track] = (Word16)(quant_2p_2N1(ind[k], ind[k + 1], 4));
- k += NPMAXPT;
- }
- } else if(nbbits == 44)
- {
- for (track = 0; track < NB_TRACK - 2; track++)
- {
- _index[track] = (Word16)(quant_3p_3N1(ind[k], ind[k + 1], ind[k + 2], 4));
- k += NPMAXPT;
- }
- for (track = 2; track < NB_TRACK; track++)
- {
- _index[track] = (Word16)(quant_2p_2N1(ind[k], ind[k + 1], 4));
- k += NPMAXPT;
- }
- } else if(nbbits == 52)
- {
- for (track = 0; track < NB_TRACK; track++)
- {
- _index[track] = (Word16)(quant_3p_3N1(ind[k], ind[k + 1], ind[k + 2], 4));
- k += NPMAXPT;
- }
- } else if(nbbits == 64)
- {
- for (track = 0; track < NB_TRACK; track++)
- {
- L_index = quant_4p_4N(&ind[k], 4);
- _index[track] = (Word16)((L_index >> 14) & 3);
- _index[track + NB_TRACK] = (Word16)(L_index & 0x3FFF);
- k += NPMAXPT;
- }
- } else if(nbbits == 72)
- {
- for (track = 0; track < NB_TRACK - 2; track++)
- {
- L_index = quant_5p_5N(&ind[k], 4);
- _index[track] = (Word16)((L_index >> 10) & 0x03FF);
- _index[track + NB_TRACK] = (Word16)(L_index & 0x03FF);
- k += NPMAXPT;
- }
- for (track = 2; track < NB_TRACK; track++)
- {
- L_index = quant_4p_4N(&ind[k], 4);
- _index[track] = (Word16)((L_index >> 14) & 3);
- _index[track + NB_TRACK] = (Word16)(L_index & 0x3FFF);
- k += NPMAXPT;
- }
- } else if(nbbits == 88)
- {
- for (track = 0; track < NB_TRACK; track++)
- {
- L_index = quant_6p_6N_2(&ind[k], 4);
- _index[track] = (Word16)((L_index >> 11) & 0x07FF);
- _index[track + NB_TRACK] = (Word16)(L_index & 0x07FF);
- k += NPMAXPT;
- }
- }
- return;
+ k = 0;
+ /* Build index of codevector */
+ if(nbbits == 20)
+ {
+ for (track = 0; track < NB_TRACK; track++)
+ {
+ _index[track] = (Word16)(quant_1p_N1(ind[k], 4));
+ k += NPMAXPT;
+ }
+ } else if(nbbits == 36)
+ {
+ for (track = 0; track < NB_TRACK; track++)
+ {
+ _index[track] = (Word16)(quant_2p_2N1(ind[k], ind[k + 1], 4));
+ k += NPMAXPT;
+ }
+ } else if(nbbits == 44)
+ {
+ for (track = 0; track < NB_TRACK - 2; track++)
+ {
+ _index[track] = (Word16)(quant_3p_3N1(ind[k], ind[k + 1], ind[k + 2], 4));
+ k += NPMAXPT;
+ }
+ for (track = 2; track < NB_TRACK; track++)
+ {
+ _index[track] = (Word16)(quant_2p_2N1(ind[k], ind[k + 1], 4));
+ k += NPMAXPT;
+ }
+ } else if(nbbits == 52)
+ {
+ for (track = 0; track < NB_TRACK; track++)
+ {
+ _index[track] = (Word16)(quant_3p_3N1(ind[k], ind[k + 1], ind[k + 2], 4));
+ k += NPMAXPT;
+ }
+ } else if(nbbits == 64)
+ {
+ for (track = 0; track < NB_TRACK; track++)
+ {
+ L_index = quant_4p_4N(&ind[k], 4);
+ _index[track] = (Word16)((L_index >> 14) & 3);
+ _index[track + NB_TRACK] = (Word16)(L_index & 0x3FFF);
+ k += NPMAXPT;
+ }
+ } else if(nbbits == 72)
+ {
+ for (track = 0; track < NB_TRACK - 2; track++)
+ {
+ L_index = quant_5p_5N(&ind[k], 4);
+ _index[track] = (Word16)((L_index >> 10) & 0x03FF);
+ _index[track + NB_TRACK] = (Word16)(L_index & 0x03FF);
+ k += NPMAXPT;
+ }
+ for (track = 2; track < NB_TRACK; track++)
+ {
+ L_index = quant_4p_4N(&ind[k], 4);
+ _index[track] = (Word16)((L_index >> 14) & 3);
+ _index[track + NB_TRACK] = (Word16)(L_index & 0x3FFF);
+ k += NPMAXPT;
+ }
+ } else if(nbbits == 88)
+ {
+ for (track = 0; track < NB_TRACK; track++)
+ {
+ L_index = quant_6p_6N_2(&ind[k], 4);
+ _index[track] = (Word16)((L_index >> 11) & 0x07FF);
+ _index[track + NB_TRACK] = (Word16)(L_index & 0x07FF);
+ k += NPMAXPT;
+ }
+ }
+ return;
}
@@ -824,135 +832,135 @@
* Compute correlations of h[] with vec[] for the specified track. *
*-------------------------------------------------------------------*/
void cor_h_vec_30(
- Word16 h[], /* (i) scaled impulse response */
- Word16 vec[], /* (i) scaled vector (/8) to correlate with h[] */
- Word16 track, /* (i) track to use */
- Word16 sign[], /* (i) sign vector */
- Word16 rrixix[][NB_POS], /* (i) correlation of h[x] with h[x] */
- Word16 cor_1[], /* (o) result of correlation (NB_POS elements) */
- Word16 cor_2[] /* (o) result of correlation (NB_POS elements) */
- )
+ Word16 h[], /* (i) scaled impulse response */
+ Word16 vec[], /* (i) scaled vector (/8) to correlate with h[] */
+ Word16 track, /* (i) track to use */
+ Word16 sign[], /* (i) sign vector */
+ Word16 rrixix[][NB_POS], /* (i) correlation of h[x] with h[x] */
+ Word16 cor_1[], /* (o) result of correlation (NB_POS elements) */
+ Word16 cor_2[] /* (o) result of correlation (NB_POS elements) */
+ )
{
- Word32 i, j, pos, corr;
- Word16 *p0, *p1, *p2,*p3,*cor_x,*cor_y;
- Word32 L_sum1,L_sum2;
- cor_x = cor_1;
- cor_y = cor_2;
- p0 = rrixix[track];
- p3 = rrixix[0];
- pos = track;
+ Word32 i, j, pos, corr;
+ Word16 *p0, *p1, *p2,*p3,*cor_x,*cor_y;
+ Word32 L_sum1,L_sum2;
+ cor_x = cor_1;
+ cor_y = cor_2;
+ p0 = rrixix[track];
+ p3 = rrixix[0];
+ pos = track;
- for (i = 0; i < NB_POS; i+=2)
- {
- L_sum1 = L_sum2 = 0L;
- p1 = h;
- p2 = &vec[pos];
- for (j=pos;j < L_SUBFR; j++)
- {
- L_sum1 += *p1 * *p2;
- p2-=3;
- L_sum2 += *p1++ * *p2;
- p2+=4;
- }
- p2-=3;
- L_sum2 += *p1++ * *p2++;
- L_sum2 += *p1++ * *p2++;
- L_sum2 += *p1++ * *p2++;
+ for (i = 0; i < NB_POS; i+=2)
+ {
+ L_sum1 = L_sum2 = 0L;
+ p1 = h;
+ p2 = &vec[pos];
+ for (j=pos;j < L_SUBFR; j++)
+ {
+ L_sum1 += *p1 * *p2;
+ p2-=3;
+ L_sum2 += *p1++ * *p2;
+ p2+=4;
+ }
+ p2-=3;
+ L_sum2 += *p1++ * *p2++;
+ L_sum2 += *p1++ * *p2++;
+ L_sum2 += *p1++ * *p2++;
- L_sum1 = (L_sum1 << 2);
- L_sum2 = (L_sum2 << 2);
+ L_sum1 = (L_sum1 << 2);
+ L_sum2 = (L_sum2 << 2);
- corr = vo_round(L_sum1);
- *cor_x++ = vo_mult(corr, sign[pos]) + (*p0++);
- corr = vo_round(L_sum2);
- *cor_y++ = vo_mult(corr, sign[pos-3]) + (*p3++);
- pos += STEP;
+ corr = vo_round(L_sum1);
+ *cor_x++ = vo_mult(corr, sign[pos]) + (*p0++);
+ corr = vo_round(L_sum2);
+ *cor_y++ = vo_mult(corr, sign[pos-3]) + (*p3++);
+ pos += STEP;
- L_sum1 = L_sum2 = 0L;
- p1 = h;
- p2 = &vec[pos];
- for (j=pos;j < L_SUBFR; j++)
- {
- L_sum1 += *p1 * *p2;
- p2-=3;
- L_sum2 += *p1++ * *p2;
- p2+=4;
- }
- p2-=3;
- L_sum2 += *p1++ * *p2++;
- L_sum2 += *p1++ * *p2++;
- L_sum2 += *p1++ * *p2++;
+ L_sum1 = L_sum2 = 0L;
+ p1 = h;
+ p2 = &vec[pos];
+ for (j=pos;j < L_SUBFR; j++)
+ {
+ L_sum1 += *p1 * *p2;
+ p2-=3;
+ L_sum2 += *p1++ * *p2;
+ p2+=4;
+ }
+ p2-=3;
+ L_sum2 += *p1++ * *p2++;
+ L_sum2 += *p1++ * *p2++;
+ L_sum2 += *p1++ * *p2++;
- L_sum1 = (L_sum1 << 2);
- L_sum2 = (L_sum2 << 2);
+ L_sum1 = (L_sum1 << 2);
+ L_sum2 = (L_sum2 << 2);
- corr = vo_round(L_sum1);
- *cor_x++ = vo_mult(corr, sign[pos]) + (*p0++);
- corr = vo_round(L_sum2);
- *cor_y++ = vo_mult(corr, sign[pos-3]) + (*p3++);
- pos += STEP;
- }
- return;
+ corr = vo_round(L_sum1);
+ *cor_x++ = vo_mult(corr, sign[pos]) + (*p0++);
+ corr = vo_round(L_sum2);
+ *cor_y++ = vo_mult(corr, sign[pos-3]) + (*p3++);
+ pos += STEP;
+ }
+ return;
}
void cor_h_vec_012(
- Word16 h[], /* (i) scaled impulse response */
- Word16 vec[], /* (i) scaled vector (/8) to correlate with h[] */
- Word16 track, /* (i) track to use */
- Word16 sign[], /* (i) sign vector */
- Word16 rrixix[][NB_POS], /* (i) correlation of h[x] with h[x] */
- Word16 cor_1[], /* (o) result of correlation (NB_POS elements) */
- Word16 cor_2[] /* (o) result of correlation (NB_POS elements) */
- )
+ Word16 h[], /* (i) scaled impulse response */
+ Word16 vec[], /* (i) scaled vector (/8) to correlate with h[] */
+ Word16 track, /* (i) track to use */
+ Word16 sign[], /* (i) sign vector */
+ Word16 rrixix[][NB_POS], /* (i) correlation of h[x] with h[x] */
+ Word16 cor_1[], /* (o) result of correlation (NB_POS elements) */
+ Word16 cor_2[] /* (o) result of correlation (NB_POS elements) */
+ )
{
- Word32 i, j, pos, corr;
- Word16 *p0, *p1, *p2,*p3,*cor_x,*cor_y;
- Word32 L_sum1,L_sum2;
- cor_x = cor_1;
- cor_y = cor_2;
- p0 = rrixix[track];
- p3 = rrixix[track+1];
- pos = track;
+ Word32 i, j, pos, corr;
+ Word16 *p0, *p1, *p2,*p3,*cor_x,*cor_y;
+ Word32 L_sum1,L_sum2;
+ cor_x = cor_1;
+ cor_y = cor_2;
+ p0 = rrixix[track];
+ p3 = rrixix[track+1];
+ pos = track;
- for (i = 0; i < NB_POS; i+=2)
- {
- L_sum1 = L_sum2 = 0L;
- p1 = h;
- p2 = &vec[pos];
- for (j=62-pos ;j >= 0; j--)
- {
- L_sum1 += *p1 * *p2++;
- L_sum2 += *p1++ * *p2;
- }
- L_sum1 += *p1 * *p2;
- L_sum1 = (L_sum1 << 2);
- L_sum2 = (L_sum2 << 2);
+ for (i = 0; i < NB_POS; i+=2)
+ {
+ L_sum1 = L_sum2 = 0L;
+ p1 = h;
+ p2 = &vec[pos];
+ for (j=62-pos ;j >= 0; j--)
+ {
+ L_sum1 += *p1 * *p2++;
+ L_sum2 += *p1++ * *p2;
+ }
+ L_sum1 += *p1 * *p2;
+ L_sum1 = (L_sum1 << 2);
+ L_sum2 = (L_sum2 << 2);
- corr = (L_sum1 + 0x8000) >> 16;
- cor_x[i] = vo_mult(corr, sign[pos]) + (*p0++);
- corr = (L_sum2 + 0x8000) >> 16;
- cor_y[i] = vo_mult(corr, sign[pos + 1]) + (*p3++);
- pos += STEP;
+ corr = (L_sum1 + 0x8000) >> 16;
+ cor_x[i] = vo_mult(corr, sign[pos]) + (*p0++);
+ corr = (L_sum2 + 0x8000) >> 16;
+ cor_y[i] = vo_mult(corr, sign[pos + 1]) + (*p3++);
+ pos += STEP;
- L_sum1 = L_sum2 = 0L;
- p1 = h;
- p2 = &vec[pos];
- for (j= 62-pos;j >= 0; j--)
- {
- L_sum1 += *p1 * *p2++;
- L_sum2 += *p1++ * *p2;
- }
- L_sum1 += *p1 * *p2;
- L_sum1 = (L_sum1 << 2);
- L_sum2 = (L_sum2 << 2);
+ L_sum1 = L_sum2 = 0L;
+ p1 = h;
+ p2 = &vec[pos];
+ for (j= 62-pos;j >= 0; j--)
+ {
+ L_sum1 += *p1 * *p2++;
+ L_sum2 += *p1++ * *p2;
+ }
+ L_sum1 += *p1 * *p2;
+ L_sum1 = (L_sum1 << 2);
+ L_sum2 = (L_sum2 << 2);
- corr = (L_sum1 + 0x8000) >> 16;
- cor_x[i+1] = vo_mult(corr, sign[pos]) + (*p0++);
- corr = (L_sum2 + 0x8000) >> 16;
- cor_y[i+1] = vo_mult(corr, sign[pos + 1]) + (*p3++);
- pos += STEP;
- }
- return;
+ corr = (L_sum1 + 0x8000) >> 16;
+ cor_x[i+1] = vo_mult(corr, sign[pos]) + (*p0++);
+ corr = (L_sum2 + 0x8000) >> 16;
+ cor_y[i+1] = vo_mult(corr, sign[pos + 1]) + (*p3++);
+ pos += STEP;
+ }
+ return;
}
/*-------------------------------------------------------------------*
@@ -962,80 +970,80 @@
*-------------------------------------------------------------------*/
void search_ixiy(
- Word16 nb_pos_ix, /* (i) nb of pos for pulse 1 (1..8) */
- Word16 track_x, /* (i) track of pulse 1 */
- Word16 track_y, /* (i) track of pulse 2 */
- Word16 * ps, /* (i/o) correlation of all fixed pulses */
- Word16 * alp, /* (i/o) energy of all fixed pulses */
- Word16 * ix, /* (o) position of pulse 1 */
- Word16 * iy, /* (o) position of pulse 2 */
- Word16 dn[], /* (i) corr. between target and h[] */
- Word16 dn2[], /* (i) vector of selected positions */
- Word16 cor_x[], /* (i) corr. of pulse 1 with fixed pulses */
- Word16 cor_y[], /* (i) corr. of pulse 2 with fixed pulses */
- Word16 rrixiy[][MSIZE] /* (i) corr. of pulse 1 with pulse 2 */
- )
+ Word16 nb_pos_ix, /* (i) nb of pos for pulse 1 (1..8) */
+ Word16 track_x, /* (i) track of pulse 1 */
+ Word16 track_y, /* (i) track of pulse 2 */
+ Word16 * ps, /* (i/o) correlation of all fixed pulses */
+ Word16 * alp, /* (i/o) energy of all fixed pulses */
+ Word16 * ix, /* (o) position of pulse 1 */
+ Word16 * iy, /* (o) position of pulse 2 */
+ Word16 dn[], /* (i) corr. between target and h[] */
+ Word16 dn2[], /* (i) vector of selected positions */
+ Word16 cor_x[], /* (i) corr. of pulse 1 with fixed pulses */
+ Word16 cor_y[], /* (i) corr. of pulse 2 with fixed pulses */
+ Word16 rrixiy[][MSIZE] /* (i) corr. of pulse 1 with pulse 2 */
+ )
{
- Word32 x, y, pos, thres_ix;
- Word16 ps1, ps2, sq, sqk;
- Word16 alp_16, alpk;
- Word16 *p0, *p1, *p2;
- Word32 s, alp0, alp1, alp2;
+ Word32 x, y, pos, thres_ix;
+ Word16 ps1, ps2, sq, sqk;
+ Word16 alp_16, alpk;
+ Word16 *p0, *p1, *p2;
+ Word32 s, alp0, alp1, alp2;
- p0 = cor_x;
- p1 = cor_y;
- p2 = rrixiy[track_x];
+ p0 = cor_x;
+ p1 = cor_y;
+ p2 = rrixiy[track_x];
- thres_ix = nb_pos_ix - NB_MAX;
+ thres_ix = nb_pos_ix - NB_MAX;
- alp0 = L_deposit_h(*alp);
- alp0 = (alp0 + 0x00008000L); /* for rounding */
+ alp0 = L_deposit_h(*alp);
+ alp0 = (alp0 + 0x00008000L); /* for rounding */
- sqk = -1;
- alpk = 1;
+ sqk = -1;
+ alpk = 1;
- for (x = track_x; x < L_SUBFR; x += STEP)
- {
- ps1 = *ps + dn[x];
- alp1 = alp0 + ((*p0++)<<13);
+ for (x = track_x; x < L_SUBFR; x += STEP)
+ {
+ ps1 = *ps + dn[x];
+ alp1 = L_add(alp0, ((*p0++)<<13));
- if (dn2[x] < thres_ix)
- {
- pos = -1;
- for (y = track_y; y < L_SUBFR; y += STEP)
- {
- ps2 = add1(ps1, dn[y]);
+ if (dn2[x] < thres_ix)
+ {
+ pos = -1;
+ for (y = track_y; y < L_SUBFR; y += STEP)
+ {
+ ps2 = add1(ps1, dn[y]);
- alp2 = alp1 + ((*p1++)<<13);
- alp2 = alp2 + ((*p2++)<<14);
- alp_16 = extract_h(alp2);
- sq = vo_mult(ps2, ps2);
- s = vo_L_mult(alpk, sq) - ((sqk * alp_16)<<1);
+ alp2 = L_add(alp1, ((*p1++)<<13));
+ alp2 = L_add(alp2, ((*p2++)<<14));
+ alp_16 = extract_h(alp2);
+ sq = vo_mult(ps2, ps2);
+ s = L_sub(vo_L_mult(alpk, sq), L_mult(sqk, alp_16));
- if (s > 0)
- {
- sqk = sq;
- alpk = alp_16;
- pos = y;
- }
- }
- p1 -= NB_POS;
+ if (s > 0)
+ {
+ sqk = sq;
+ alpk = alp_16;
+ pos = y;
+ }
+ }
+ p1 -= NB_POS;
- if (pos >= 0)
- {
- *ix = x;
- *iy = pos;
- }
- } else
- {
- p2 += NB_POS;
- }
- }
+ if (pos >= 0)
+ {
+ *ix = x;
+ *iy = pos;
+ }
+ } else
+ {
+ p2 += NB_POS;
+ }
+ }
- *ps = add1(*ps, add1(dn[*ix], dn[*iy]));
- *alp = alpk;
+ *ps = add1(*ps, add1(dn[*ix], dn[*iy]));
+ *alp = alpk;
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/convolve.c b/media/libstagefright/codecs/amrwbenc/src/convolve.c
index 4c1f7d4..9b8b3aa 100644
--- a/media/libstagefright/codecs/amrwbenc/src/convolve.c
+++ b/media/libstagefright/codecs/amrwbenc/src/convolve.c
@@ -17,8 +17,8 @@
/***********************************************************************
File: convolve.c
- Description:Perform the convolution between two vectors x[] and h[]
- and write the result in the vector y[]
+ Description:Perform the convolution between two vectors x[] and h[]
+ and write the result in the vector y[]
************************************************************************/
@@ -28,85 +28,85 @@
#define UNUSED(x) (void)(x)
void Convolve (
- Word16 x[], /* (i) : input vector */
- Word16 h[], /* (i) : impulse response */
- Word16 y[], /* (o) : output vector */
- Word16 L /* (i) : vector size */
- )
+ Word16 x[], /* (i) : input vector */
+ Word16 h[], /* (i) : impulse response */
+ Word16 y[], /* (o) : output vector */
+ Word16 L /* (i) : vector size */
+ )
{
- Word32 i, n;
- Word16 *tmpH,*tmpX;
- Word32 s;
+ Word32 i, n;
+ Word16 *tmpH,*tmpX;
+ Word32 s;
UNUSED(L);
- for (n = 0; n < 64;)
- {
- tmpH = h+n;
- tmpX = x;
- i=n+1;
- s = vo_mult32((*tmpX++), (*tmpH--));i--;
- while(i>0)
- {
- s += vo_mult32((*tmpX++), (*tmpH--));
- s += vo_mult32((*tmpX++), (*tmpH--));
- s += vo_mult32((*tmpX++), (*tmpH--));
- s += vo_mult32((*tmpX++), (*tmpH--));
- i -= 4;
- }
- y[n] = ((s<<1) + 0x8000)>>16;
- n++;
+ for (n = 0; n < 64;)
+ {
+ tmpH = h+n;
+ tmpX = x;
+ i=n+1;
+ s = vo_mult32((*tmpX++), (*tmpH--));i--;
+ while(i>0)
+ {
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ i -= 4;
+ }
+ y[n] = ((s<<1) + 0x8000)>>16;
+ n++;
- tmpH = h+n;
- tmpX = x;
- i=n+1;
- s = vo_mult32((*tmpX++), (*tmpH--));i--;
- s += vo_mult32((*tmpX++), (*tmpH--));i--;
+ tmpH = h+n;
+ tmpX = x;
+ i=n+1;
+ s = vo_mult32((*tmpX++), (*tmpH--));i--;
+ s += vo_mult32((*tmpX++), (*tmpH--));i--;
- while(i>0)
- {
- s += vo_mult32((*tmpX++), (*tmpH--));
- s += vo_mult32((*tmpX++), (*tmpH--));
- s += vo_mult32((*tmpX++), (*tmpH--));
- s += vo_mult32((*tmpX++), (*tmpH--));
- i -= 4;
- }
- y[n] = ((s<<1) + 0x8000)>>16;
- n++;
+ while(i>0)
+ {
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ i -= 4;
+ }
+ y[n] = ((s<<1) + 0x8000)>>16;
+ n++;
- tmpH = h+n;
- tmpX = x;
- i=n+1;
- s = vo_mult32((*tmpX++), (*tmpH--));i--;
- s += vo_mult32((*tmpX++), (*tmpH--));i--;
- s += vo_mult32((*tmpX++), (*tmpH--));i--;
+ tmpH = h+n;
+ tmpX = x;
+ i=n+1;
+ s = vo_mult32((*tmpX++), (*tmpH--));i--;
+ s += vo_mult32((*tmpX++), (*tmpH--));i--;
+ s += vo_mult32((*tmpX++), (*tmpH--));i--;
- while(i>0)
- {
- s += vo_mult32((*tmpX++), (*tmpH--));
- s += vo_mult32((*tmpX++), (*tmpH--));
- s += vo_mult32((*tmpX++), (*tmpH--));
- s += vo_mult32((*tmpX++), (*tmpH--));
- i -= 4;
- }
- y[n] = ((s<<1) + 0x8000)>>16;
- n++;
+ while(i>0)
+ {
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ i -= 4;
+ }
+ y[n] = ((s<<1) + 0x8000)>>16;
+ n++;
- s = 0;
- tmpH = h+n;
- tmpX = x;
- i=n+1;
- while(i>0)
- {
- s += vo_mult32((*tmpX++), (*tmpH--));
- s += vo_mult32((*tmpX++), (*tmpH--));
- s += vo_mult32((*tmpX++), (*tmpH--));
- s += vo_mult32((*tmpX++), (*tmpH--));
- i -= 4;
- }
- y[n] = ((s<<1) + 0x8000)>>16;
- n++;
- }
- return;
+ s = 0;
+ tmpH = h+n;
+ tmpX = x;
+ i=n+1;
+ while(i>0)
+ {
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ s += vo_mult32((*tmpX++), (*tmpH--));
+ i -= 4;
+ }
+ y[n] = ((s<<1) + 0x8000)>>16;
+ n++;
+ }
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/cor_h_x.c b/media/libstagefright/codecs/amrwbenc/src/cor_h_x.c
index d9245ed..e834396 100644
--- a/media/libstagefright/codecs/amrwbenc/src/cor_h_x.c
+++ b/media/libstagefright/codecs/amrwbenc/src/cor_h_x.c
@@ -17,10 +17,10 @@
/***********************************************************************
* File: cor_h_x.c *
* *
-* Description:Compute correlation between target "x[]" and "h[]" *
-* Designed for codebook search (24 pulses, 4 tracks, *
-* 4 pulses per track, 16 positions in each track) to *
-* avoid saturation. *
+* Description:Compute correlation between target "x[]" and "h[]" *
+* Designed for codebook search (24 pulses, 4 tracks, *
+* 4 pulses per track, 16 positions in each track) to *
+* avoid saturation. *
* *
************************************************************************/
@@ -33,94 +33,100 @@
#define STEP 4
void cor_h_x(
- Word16 h[], /* (i) Q12 : impulse response of weighted synthesis filter */
- Word16 x[], /* (i) Q0 : target vector */
- Word16 dn[] /* (o) <12bit : correlation between target and h[] */
- )
+ Word16 h[], /* (i) Q12 : impulse response of weighted synthesis filter */
+ Word16 x[], /* (i) Q0 : target vector */
+ Word16 dn[] /* (o) <12bit : correlation between target and h[] */
+ )
{
- Word32 i, j;
- Word32 L_tmp, y32[L_SUBFR], L_tot;
- Word16 *p1, *p2;
- Word32 *p3;
- Word32 L_max, L_max1, L_max2, L_max3;
- /* first keep the result on 32 bits and find absolute maximum */
- L_tot = 1;
- L_max = 0;
- L_max1 = 0;
- L_max2 = 0;
- L_max3 = 0;
- for (i = 0; i < L_SUBFR; i += STEP)
- {
- L_tmp = 1; /* 1 -> to avoid null dn[] */
- p1 = &x[i];
- p2 = &h[0];
- for (j = i; j < L_SUBFR; j++)
- L_tmp += vo_L_mult(*p1++, *p2++);
+ Word32 i, j;
+ Word32 L_tmp, y32[L_SUBFR], L_tot;
+ Word16 *p1, *p2;
+ Word32 *p3;
+ Word32 L_max, L_max1, L_max2, L_max3;
+ /* first keep the result on 32 bits and find absolute maximum */
+ L_tot = 1;
+ L_max = 0;
+ L_max1 = 0;
+ L_max2 = 0;
+ L_max3 = 0;
+ for (i = 0; i < L_SUBFR; i += STEP)
+ {
+ L_tmp = 1; /* 1 -> to avoid null dn[] */
+ p1 = &x[i];
+ p2 = &h[0];
+ for (j = i; j < L_SUBFR; j++)
+ L_tmp = L_add(L_tmp, vo_L_mult(*p1++, *p2++));
- y32[i] = L_tmp;
- L_tmp = (L_tmp > 0)? L_tmp:-L_tmp;
- if(L_tmp > L_max)
- {
- L_max = L_tmp;
- }
+ y32[i] = L_tmp;
+ L_tmp = (L_tmp > 0)? L_tmp: (L_tmp == INT_MIN ? INT_MAX : -L_tmp);
+ if(L_tmp > L_max)
+ {
+ L_max = L_tmp;
+ }
- L_tmp = 1L;
- p1 = &x[i+1];
- p2 = &h[0];
- for (j = i+1; j < L_SUBFR; j++)
- L_tmp += vo_L_mult(*p1++, *p2++);
+ L_tmp = 1L;
+ p1 = &x[i+1];
+ p2 = &h[0];
+ for (j = i+1; j < L_SUBFR; j++)
+ L_tmp = L_add(L_tmp, vo_L_mult(*p1++, *p2++));
- y32[i+1] = L_tmp;
- L_tmp = (L_tmp > 0)? L_tmp:-L_tmp;
- if(L_tmp > L_max1)
- {
- L_max1 = L_tmp;
- }
+ y32[i+1] = L_tmp;
+ L_tmp = (L_tmp > 0)? L_tmp: (L_tmp == INT_MIN ? INT_MAX : -L_tmp);
+ if(L_tmp > L_max1)
+ {
+ L_max1 = L_tmp;
+ }
- L_tmp = 1;
- p1 = &x[i+2];
- p2 = &h[0];
- for (j = i+2; j < L_SUBFR; j++)
- L_tmp += vo_L_mult(*p1++, *p2++);
+ L_tmp = 1;
+ p1 = &x[i+2];
+ p2 = &h[0];
+ for (j = i+2; j < L_SUBFR; j++)
+ L_tmp = L_add(L_tmp, vo_L_mult(*p1++, *p2++));
- y32[i+2] = L_tmp;
- L_tmp = (L_tmp > 0)? L_tmp:-L_tmp;
- if(L_tmp > L_max2)
- {
- L_max2 = L_tmp;
- }
+ y32[i+2] = L_tmp;
+ L_tmp = (L_tmp > 0)? L_tmp: (L_tmp == INT_MIN ? INT_MAX : -L_tmp);
+ if(L_tmp > L_max2)
+ {
+ L_max2 = L_tmp;
+ }
- L_tmp = 1;
- p1 = &x[i+3];
- p2 = &h[0];
- for (j = i+3; j < L_SUBFR; j++)
- L_tmp += vo_L_mult(*p1++, *p2++);
+ L_tmp = 1;
+ p1 = &x[i+3];
+ p2 = &h[0];
+ for (j = i+3; j < L_SUBFR; j++)
+ L_tmp = L_add(L_tmp, vo_L_mult(*p1++, *p2++));
- y32[i+3] = L_tmp;
- L_tmp = (L_tmp > 0)? L_tmp:-L_tmp;
- if(L_tmp > L_max3)
- {
- L_max3 = L_tmp;
- }
- }
- /* tot += 3*max / 8 */
- L_max = ((L_max + L_max1 + L_max2 + L_max3) >> 2);
- L_tot = vo_L_add(L_tot, L_max); /* +max/4 */
- L_tot = vo_L_add(L_tot, (L_max >> 1)); /* +max/8 */
+ y32[i+3] = L_tmp;
+ L_tmp = (L_tmp > 0)? L_tmp: (L_tmp == INT_MIN ? INT_MAX : -L_tmp);
+ if(L_tmp > L_max3)
+ {
+ L_max3 = L_tmp;
+ }
+ }
+ /* tot += 3*max / 8 */
+ if (L_max > INT_MAX - L_max1 ||
+ L_max + L_max1 > INT_MAX - L_max2 ||
+ L_max + L_max1 + L_max2 > INT_MAX - L_max3) {
+ L_max = INT_MAX >> 2;
+ } else {
+ L_max = ((L_max + L_max1 + L_max2 + L_max3) >> 2);
+ }
+ L_tot = vo_L_add(L_tot, L_max); /* +max/4 */
+ L_tot = vo_L_add(L_tot, (L_max >> 1)); /* +max/8 */
- /* Find the number of right shifts to do on y32[] so that */
- /* 6.0 x sumation of max of dn[] in each track not saturate. */
- j = norm_l(L_tot) - 4; /* 4 -> 16 x tot */
- p1 = dn;
- p3 = y32;
- for (i = 0; i < L_SUBFR; i+=4)
- {
- *p1++ = vo_round(L_shl(*p3++, j));
- *p1++ = vo_round(L_shl(*p3++, j));
- *p1++ = vo_round(L_shl(*p3++, j));
- *p1++ = vo_round(L_shl(*p3++, j));
- }
- return;
+ /* Find the number of right shifts to do on y32[] so that */
+ /* 6.0 x sumation of max of dn[] in each track not saturate. */
+ j = norm_l(L_tot) - 4; /* 4 -> 16 x tot */
+ p1 = dn;
+ p3 = y32;
+ for (i = 0; i < L_SUBFR; i+=4)
+ {
+ *p1++ = vo_round(L_shl(*p3++, j));
+ *p1++ = vo_round(L_shl(*p3++, j));
+ *p1++ = vo_round(L_shl(*p3++, j));
+ *p1++ = vo_round(L_shl(*p3++, j));
+ }
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/decim54.c b/media/libstagefright/codecs/amrwbenc/src/decim54.c
index 3b88514..e4c7940 100644
--- a/media/libstagefright/codecs/amrwbenc/src/decim54.c
+++ b/media/libstagefright/codecs/amrwbenc/src/decim54.c
@@ -17,7 +17,7 @@
/***********************************************************************
* File: decim54.c *
* *
-* Description:Decimation of 16kHz signal to 12.8kHz *
+* Description:Decimation of 16kHz signal to 12.8kHz *
* *
************************************************************************/
@@ -33,114 +33,114 @@
/* Local functions */
static void Down_samp(
- Word16 * sig, /* input: signal to downsampling */
- Word16 * sig_d, /* output: downsampled signal */
- Word16 L_frame_d /* input: length of output */
- );
+ Word16 * sig, /* input: signal to downsampling */
+ Word16 * sig_d, /* output: downsampled signal */
+ Word16 L_frame_d /* input: length of output */
+ );
/* 1/5 resolution interpolation filter (in Q14) */
/* -1.5dB @ 6kHz, -6dB @ 6.4kHz, -10dB @ 6.6kHz, -20dB @ 6.9kHz, -25dB @ 7kHz, -55dB @ 8kHz */
static Word16 fir_down1[4][30] =
{
- {-5, 24, -50, 54, 0, -128, 294, -408, 344, 0, -647, 1505, -2379, 3034, 13107, 3034, -2379, 1505, -647, 0, 344, -408,
- 294, -128, 0, 54, -50, 24, -5, 0},
+ {-5, 24, -50, 54, 0, -128, 294, -408, 344, 0, -647, 1505, -2379, 3034, 13107, 3034, -2379, 1505, -647, 0, 344, -408,
+ 294, -128, 0, 54, -50, 24, -5, 0},
- {-6, 19, -26, 0, 77, -188, 270, -233, 0, 434, -964, 1366, -1293, 0, 12254, 6575, -2746, 1030, 0, -507, 601, -441,
- 198, 0, -95, 99, -58, 18, 0, -1},
+ {-6, 19, -26, 0, 77, -188, 270, -233, 0, 434, -964, 1366, -1293, 0, 12254, 6575, -2746, 1030, 0, -507, 601, -441,
+ 198, 0, -95, 99, -58, 18, 0, -1},
- {-3, 9, 0, -41, 111, -170, 153, 0, -295, 649, -888, 770, 0, -1997, 9894, 9894, -1997, 0, 770, -888, 649, -295, 0,
- 153, -170, 111, -41, 0, 9, -3},
+ {-3, 9, 0, -41, 111, -170, 153, 0, -295, 649, -888, 770, 0, -1997, 9894, 9894, -1997, 0, 770, -888, 649, -295, 0,
+ 153, -170, 111, -41, 0, 9, -3},
- {-1, 0, 18, -58, 99, -95, 0, 198, -441, 601, -507, 0, 1030, -2746, 6575, 12254, 0, -1293, 1366, -964, 434, 0,
- -233, 270, -188, 77, 0, -26, 19, -6}
+ {-1, 0, 18, -58, 99, -95, 0, 198, -441, 601, -507, 0, 1030, -2746, 6575, 12254, 0, -1293, 1366, -964, 434, 0,
+ -233, 270, -188, 77, 0, -26, 19, -6}
};
void Init_Decim_12k8(
- Word16 mem[] /* output: memory (2*NB_COEF_DOWN) set to zeros */
- )
+ Word16 mem[] /* output: memory (2*NB_COEF_DOWN) set to zeros */
+ )
{
- Set_zero(mem, 2 * NB_COEF_DOWN);
- return;
+ Set_zero(mem, 2 * NB_COEF_DOWN);
+ return;
}
void Decim_12k8(
- Word16 sig16k[], /* input: signal to downsampling */
- Word16 lg, /* input: length of input */
- Word16 sig12k8[], /* output: decimated signal */
- Word16 mem[] /* in/out: memory (2*NB_COEF_DOWN) */
- )
+ Word16 sig16k[], /* input: signal to downsampling */
+ Word16 lg, /* input: length of input */
+ Word16 sig12k8[], /* output: decimated signal */
+ Word16 mem[] /* in/out: memory (2*NB_COEF_DOWN) */
+ )
{
- Word16 lg_down;
- Word16 signal[L_FRAME16k + (2 * NB_COEF_DOWN)];
+ Word16 lg_down;
+ Word16 signal[L_FRAME16k + (2 * NB_COEF_DOWN)];
- Copy(mem, signal, 2 * NB_COEF_DOWN);
+ Copy(mem, signal, 2 * NB_COEF_DOWN);
- Copy(sig16k, signal + (2 * NB_COEF_DOWN), lg);
+ Copy(sig16k, signal + (2 * NB_COEF_DOWN), lg);
- lg_down = (lg * DOWN_FAC)>>15;
+ lg_down = (lg * DOWN_FAC)>>15;
- Down_samp(signal + NB_COEF_DOWN, sig12k8, lg_down);
+ Down_samp(signal + NB_COEF_DOWN, sig12k8, lg_down);
- Copy(signal + lg, mem, 2 * NB_COEF_DOWN);
+ Copy(signal + lg, mem, 2 * NB_COEF_DOWN);
- return;
+ return;
}
static void Down_samp(
- Word16 * sig, /* input: signal to downsampling */
- Word16 * sig_d, /* output: downsampled signal */
- Word16 L_frame_d /* input: length of output */
- )
+ Word16 * sig, /* input: signal to downsampling */
+ Word16 * sig_d, /* output: downsampled signal */
+ Word16 L_frame_d /* input: length of output */
+ )
{
- Word32 i, j, frac, pos;
- Word16 *x, *y;
- Word32 L_sum;
+ Word32 i, j, frac, pos;
+ Word16 *x, *y;
+ Word32 L_sum;
- pos = 0; /* position is in Q2 -> 1/4 resolution */
- for (j = 0; j < L_frame_d; j++)
- {
- i = (pos >> 2); /* integer part */
- frac = pos & 3; /* fractional part */
- x = sig + i - NB_COEF_DOWN + 1;
- y = (Word16 *)(fir_down1 + frac);
+ pos = 0; /* position is in Q2 -> 1/4 resolution */
+ for (j = 0; j < L_frame_d; j++)
+ {
+ i = (pos >> 2); /* integer part */
+ frac = pos & 3; /* fractional part */
+ x = sig + i - NB_COEF_DOWN + 1;
+ y = (Word16 *)(fir_down1 + frac);
- L_sum = vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x++),(*y++));
- L_sum += vo_mult32((*x),(*y));
+ L_sum = vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x++),(*y++));
+ L_sum += vo_mult32((*x),(*y));
- L_sum = L_shl2(L_sum, 2);
- sig_d[j] = extract_h(L_add(L_sum, 0x8000));
- pos += FAC5; /* pos + 5/4 */
- }
- return;
+ L_sum = L_shl2(L_sum, 2);
+ sig_d[j] = extract_h(L_add(L_sum, 0x8000));
+ pos += FAC5; /* pos + 5/4 */
+ }
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/deemph.c b/media/libstagefright/codecs/amrwbenc/src/deemph.c
index 0c49d6b..cc27f6e 100644
--- a/media/libstagefright/codecs/amrwbenc/src/deemph.c
+++ b/media/libstagefright/codecs/amrwbenc/src/deemph.c
@@ -17,9 +17,9 @@
/***********************************************************************
* File: deemph.c *
* *
-* Description:filtering through 1/(1-mu z^ -1) *
-* Deemph2 --> signal is divided by 2 *
-* Deemph_32 --> for 32 bits signal. *
+* Description:filtering through 1/(1-mu z^ -1) *
+* Deemph2 --> signal is divided by 2 *
+* Deemph_32 --> for 32 bits signal. *
* *
************************************************************************/
@@ -28,89 +28,92 @@
#include "math_op.h"
void Deemph(
- Word16 x[], /* (i/o) : input signal overwritten by the output */
- Word16 mu, /* (i) Q15 : deemphasis factor */
- Word16 L, /* (i) : vector size */
- Word16 * mem /* (i/o) : memory (y[-1]) */
- )
+ Word16 x[], /* (i/o) : input signal overwritten by the output */
+ Word16 mu, /* (i) Q15 : deemphasis factor */
+ Word16 L, /* (i) : vector size */
+ Word16 * mem /* (i/o) : memory (y[-1]) */
+ )
{
- Word32 i;
- Word32 L_tmp;
+ Word32 i;
+ Word32 L_tmp;
- L_tmp = L_deposit_h(x[0]);
- L_tmp = L_mac(L_tmp, *mem, mu);
- x[0] = vo_round(L_tmp);
+ L_tmp = L_deposit_h(x[0]);
+ L_tmp = L_mac(L_tmp, *mem, mu);
+ x[0] = vo_round(L_tmp);
- for (i = 1; i < L; i++)
- {
- L_tmp = L_deposit_h(x[i]);
- L_tmp = L_mac(L_tmp, x[i - 1], mu);
- x[i] = voround(L_tmp);
- }
+ for (i = 1; i < L; i++)
+ {
+ L_tmp = L_deposit_h(x[i]);
+ L_tmp = L_mac(L_tmp, x[i - 1], mu);
+ x[i] = voround(L_tmp);
+ }
- *mem = x[L - 1];
+ *mem = x[L - 1];
- return;
+ return;
}
void Deemph2(
- Word16 x[], /* (i/o) : input signal overwritten by the output */
- Word16 mu, /* (i) Q15 : deemphasis factor */
- Word16 L, /* (i) : vector size */
- Word16 * mem /* (i/o) : memory (y[-1]) */
- )
+ Word16 x[], /* (i/o) : input signal overwritten by the output */
+ Word16 mu, /* (i) Q15 : deemphasis factor */
+ Word16 L, /* (i) : vector size */
+ Word16 * mem /* (i/o) : memory (y[-1]) */
+ )
{
- Word32 i;
- Word32 L_tmp;
- L_tmp = x[0] << 15;
- L_tmp += ((*mem) * mu)<<1;
- x[0] = (L_tmp + 0x8000)>>16;
- for (i = 1; i < L; i++)
- {
- L_tmp = x[i] << 15;
- L_tmp += (x[i - 1] * mu)<<1;
- x[i] = (L_tmp + 0x8000)>>16;
- }
- *mem = x[L - 1];
- return;
+ Word32 i;
+ Word32 L_tmp;
+ L_tmp = x[0] << 15;
+ i = L_mult(*mem, mu);
+ L_tmp = L_add(L_tmp, i);
+ x[0] = voround(L_tmp);
+ for (i = 1; i < L; i++)
+ {
+ Word32 tmp;
+ L_tmp = x[i] << 15;
+ tmp = (x[i - 1] * mu)<<1;
+ L_tmp = L_add(L_tmp, tmp);
+ x[i] = voround(L_tmp);
+ }
+ *mem = x[L - 1];
+ return;
}
void Deemph_32(
- Word16 x_hi[], /* (i) : input signal (bit31..16) */
- Word16 x_lo[], /* (i) : input signal (bit15..4) */
- Word16 y[], /* (o) : output signal (x16) */
- Word16 mu, /* (i) Q15 : deemphasis factor */
- Word16 L, /* (i) : vector size */
- Word16 * mem /* (i/o) : memory (y[-1]) */
- )
+ Word16 x_hi[], /* (i) : input signal (bit31..16) */
+ Word16 x_lo[], /* (i) : input signal (bit15..4) */
+ Word16 y[], /* (o) : output signal (x16) */
+ Word16 mu, /* (i) Q15 : deemphasis factor */
+ Word16 L, /* (i) : vector size */
+ Word16 * mem /* (i/o) : memory (y[-1]) */
+ )
{
- Word16 fac;
- Word32 i, L_tmp;
+ Word16 fac;
+ Word32 i, L_tmp;
- fac = mu >> 1; /* Q15 --> Q14 */
+ fac = mu >> 1; /* Q15 --> Q14 */
- L_tmp = L_deposit_h(x_hi[0]);
- L_tmp += (x_lo[0] * 8)<<1;
- L_tmp = (L_tmp << 3);
- L_tmp += ((*mem) * fac)<<1;
- L_tmp = (L_tmp << 1);
- y[0] = (L_tmp + 0x8000)>>16;
+ L_tmp = L_deposit_h(x_hi[0]);
+ L_tmp += (x_lo[0] * 8)<<1;
+ L_tmp = (L_tmp << 3);
+ L_tmp += ((*mem) * fac)<<1;
+ L_tmp = (L_tmp << 1);
+ y[0] = (L_tmp + 0x8000)>>16;
- for (i = 1; i < L; i++)
- {
- L_tmp = L_deposit_h(x_hi[i]);
- L_tmp += (x_lo[i] * 8)<<1;
- L_tmp = (L_tmp << 3);
- L_tmp += (y[i - 1] * fac)<<1;
- L_tmp = (L_tmp << 1);
- y[i] = (L_tmp + 0x8000)>>16;
- }
+ for (i = 1; i < L; i++)
+ {
+ L_tmp = L_deposit_h(x_hi[i]);
+ L_tmp += (x_lo[i] * 8)<<1;
+ L_tmp = (L_tmp << 3);
+ L_tmp += (y[i - 1] * fac)<<1;
+ L_tmp = (L_tmp << 1);
+ y[i] = (L_tmp + 0x8000)>>16;
+ }
- *mem = y[L - 1];
+ *mem = y[L - 1];
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/dtx.c b/media/libstagefright/codecs/amrwbenc/src/dtx.c
index 2cfaced0f..6be8683 100644
--- a/media/libstagefright/codecs/amrwbenc/src/dtx.c
+++ b/media/libstagefright/codecs/amrwbenc/src/dtx.c
@@ -17,7 +17,7 @@
/***********************************************************************
* File: dtx.c *
* *
-* Description:DTX functions *
+* Description:DTX functions *
* *
************************************************************************/
@@ -35,33 +35,33 @@
#include "mem_align.h"
static void aver_isf_history(
- Word16 isf_old[],
- Word16 indices[],
- Word32 isf_aver[]
- );
+ Word16 isf_old[],
+ Word16 indices[],
+ Word32 isf_aver[]
+ );
static void find_frame_indices(
- Word16 isf_old_tx[],
- Word16 indices[],
- dtx_encState * st
- );
+ Word16 isf_old_tx[],
+ Word16 indices[],
+ dtx_encState * st
+ );
static Word16 dithering_control(
- dtx_encState * st
- );
+ dtx_encState * st
+ );
/* excitation energy adjustment depending on speech coder mode used, Q7 */
static Word16 en_adjust[9] =
{
- 230, /* mode0 = 7k : -5.4dB */
- 179, /* mode1 = 9k : -4.2dB */
- 141, /* mode2 = 12k : -3.3dB */
- 128, /* mode3 = 14k : -3.0dB */
- 122, /* mode4 = 16k : -2.85dB */
- 115, /* mode5 = 18k : -2.7dB */
- 115, /* mode6 = 20k : -2.7dB */
- 115, /* mode7 = 23k : -2.7dB */
- 115 /* mode8 = 24k : -2.7dB */
+ 230, /* mode0 = 7k : -5.4dB */
+ 179, /* mode1 = 9k : -4.2dB */
+ 141, /* mode2 = 12k : -3.3dB */
+ 128, /* mode3 = 14k : -3.0dB */
+ 122, /* mode4 = 16k : -2.85dB */
+ 115, /* mode5 = 18k : -2.7dB */
+ 115, /* mode6 = 20k : -2.7dB */
+ 115, /* mode7 = 23k : -2.7dB */
+ 115 /* mode8 = 24k : -2.7dB */
};
/**************************************************************************
@@ -71,24 +71,24 @@
**************************************************************************/
Word16 dtx_enc_init(dtx_encState ** st, Word16 isf_init[], VO_MEM_OPERATOR *pMemOP)
{
- dtx_encState *s;
+ dtx_encState *s;
- if (st == (dtx_encState **) NULL)
- {
- fprintf(stderr, "dtx_enc_init: invalid parameter\n");
- return -1;
- }
- *st = NULL;
+ if (st == (dtx_encState **) NULL)
+ {
+ fprintf(stderr, "dtx_enc_init: invalid parameter\n");
+ return -1;
+ }
+ *st = NULL;
- /* allocate memory */
- if ((s = (dtx_encState *)mem_malloc(pMemOP, sizeof(dtx_encState), 32, VO_INDEX_ENC_AMRWB)) == NULL)
- {
- fprintf(stderr, "dtx_enc_init: can not malloc state structure\n");
- return -1;
- }
- dtx_enc_reset(s, isf_init);
- *st = s;
- return 0;
+ /* allocate memory */
+ if ((s = (dtx_encState *)mem_malloc(pMemOP, sizeof(dtx_encState), 32, VO_INDEX_ENC_AMRWB)) == NULL)
+ {
+ fprintf(stderr, "dtx_enc_init: can not malloc state structure\n");
+ return -1;
+ }
+ dtx_enc_reset(s, isf_init);
+ *st = s;
+ return 0;
}
/**************************************************************************
@@ -98,40 +98,40 @@
**************************************************************************/
Word16 dtx_enc_reset(dtx_encState * st, Word16 isf_init[])
{
- Word32 i;
+ Word32 i;
- if (st == (dtx_encState *) NULL)
- {
- fprintf(stderr, "dtx_enc_reset: invalid parameter\n");
- return -1;
- }
- st->hist_ptr = 0;
- st->log_en_index = 0;
+ if (st == (dtx_encState *) NULL)
+ {
+ fprintf(stderr, "dtx_enc_reset: invalid parameter\n");
+ return -1;
+ }
+ st->hist_ptr = 0;
+ st->log_en_index = 0;
- /* Init isf_hist[] */
- for (i = 0; i < DTX_HIST_SIZE; i++)
- {
- Copy(isf_init, &st->isf_hist[i * M], M);
- }
- st->cng_seed = RANDOM_INITSEED;
+ /* Init isf_hist[] */
+ for (i = 0; i < DTX_HIST_SIZE; i++)
+ {
+ Copy(isf_init, &st->isf_hist[i * M], M);
+ }
+ st->cng_seed = RANDOM_INITSEED;
- /* Reset energy history */
- Set_zero(st->log_en_hist, DTX_HIST_SIZE);
+ /* Reset energy history */
+ Set_zero(st->log_en_hist, DTX_HIST_SIZE);
- st->dtxHangoverCount = DTX_HANG_CONST;
- st->decAnaElapsedCount = 32767;
+ st->dtxHangoverCount = DTX_HANG_CONST;
+ st->decAnaElapsedCount = 32767;
- for (i = 0; i < 28; i++)
- {
- st->D[i] = 0;
- }
+ for (i = 0; i < 28; i++)
+ {
+ st->D[i] = 0;
+ }
- for (i = 0; i < DTX_HIST_SIZE - 1; i++)
- {
- st->sumD[i] = 0;
- }
+ for (i = 0; i < DTX_HIST_SIZE - 1; i++)
+ {
+ st->sumD[i] = 0;
+ }
- return 1;
+ return 1;
}
/**************************************************************************
@@ -141,12 +141,12 @@
**************************************************************************/
void dtx_enc_exit(dtx_encState ** st, VO_MEM_OPERATOR *pMemOP)
{
- if (st == NULL || *st == NULL)
- return;
- /* deallocate memory */
- mem_free(pMemOP, *st, VO_INDEX_ENC_AMRWB);
- *st = NULL;
- return;
+ if (st == NULL || *st == NULL)
+ return;
+ /* deallocate memory */
+ mem_free(pMemOP, *st, VO_INDEX_ENC_AMRWB);
+ *st = NULL;
+ return;
}
@@ -156,133 +156,133 @@
*
**************************************************************************/
Word16 dtx_enc(
- dtx_encState * st, /* i/o : State struct */
- Word16 isf[M], /* o : CN ISF vector */
- Word16 * exc2, /* o : CN excitation */
- Word16 ** prms
- )
+ dtx_encState * st, /* i/o : State struct */
+ Word16 isf[M], /* o : CN ISF vector */
+ Word16 * exc2, /* o : CN excitation */
+ Word16 ** prms
+ )
{
- Word32 i, j;
- Word16 indice[7];
- Word16 log_en, gain, level, exp, exp0, tmp;
- Word16 log_en_int_e, log_en_int_m;
- Word32 L_isf[M], ener32, level32;
- Word16 isf_order[3];
- Word16 CN_dith;
+ Word32 i, j;
+ Word16 indice[7];
+ Word16 log_en, gain, level, exp, exp0, tmp;
+ Word16 log_en_int_e, log_en_int_m;
+ Word32 L_isf[M], ener32, level32;
+ Word16 isf_order[3];
+ Word16 CN_dith;
- /* VOX mode computation of SID parameters */
- log_en = 0;
- for (i = 0; i < M; i++)
- {
- L_isf[i] = 0;
- }
- /* average energy and isf */
- for (i = 0; i < DTX_HIST_SIZE; i++)
- {
- /* Division by DTX_HIST_SIZE = 8 has been done in dtx_buffer. log_en is in Q10 */
- log_en = add(log_en, st->log_en_hist[i]);
+ /* VOX mode computation of SID parameters */
+ log_en = 0;
+ for (i = 0; i < M; i++)
+ {
+ L_isf[i] = 0;
+ }
+ /* average energy and isf */
+ for (i = 0; i < DTX_HIST_SIZE; i++)
+ {
+ /* Division by DTX_HIST_SIZE = 8 has been done in dtx_buffer. log_en is in Q10 */
+ log_en = add(log_en, st->log_en_hist[i]);
- }
- find_frame_indices(st->isf_hist, isf_order, st);
- aver_isf_history(st->isf_hist, isf_order, L_isf);
+ }
+ find_frame_indices(st->isf_hist, isf_order, st);
+ aver_isf_history(st->isf_hist, isf_order, L_isf);
- for (j = 0; j < M; j++)
- {
- isf[j] = (Word16)(L_isf[j] >> 3); /* divide by 8 */
- }
+ for (j = 0; j < M; j++)
+ {
+ isf[j] = (Word16)(L_isf[j] >> 3); /* divide by 8 */
+ }
- /* quantize logarithmic energy to 6 bits (-6 : 66 dB) which corresponds to -2:22 in log2(E). */
- /* st->log_en_index = (short)( (log_en + 2.0) * 2.625 ); */
+ /* quantize logarithmic energy to 6 bits (-6 : 66 dB) which corresponds to -2:22 in log2(E). */
+ /* st->log_en_index = (short)( (log_en + 2.0) * 2.625 ); */
- /* increase dynamics to 7 bits (Q8) */
- log_en = (log_en >> 2);
+ /* increase dynamics to 7 bits (Q8) */
+ log_en = (log_en >> 2);
- /* Add 2 in Q8 = 512 to get log2(E) between 0:24 */
- log_en = add(log_en, 512);
+ /* Add 2 in Q8 = 512 to get log2(E) between 0:24 */
+ log_en = add(log_en, 512);
- /* Multiply by 2.625 to get full 6 bit range. 2.625 = 21504 in Q13. The result is in Q6 */
- log_en = mult(log_en, 21504);
+ /* Multiply by 2.625 to get full 6 bit range. 2.625 = 21504 in Q13. The result is in Q6 */
+ log_en = mult(log_en, 21504);
- /* Quantize Energy */
- st->log_en_index = shr(log_en, 6);
+ /* Quantize Energy */
+ st->log_en_index = shr(log_en, 6);
- if(st->log_en_index > 63)
- {
- st->log_en_index = 63;
- }
- if (st->log_en_index < 0)
- {
- st->log_en_index = 0;
- }
- /* Quantize ISFs */
- Qisf_ns(isf, isf, indice);
+ if(st->log_en_index > 63)
+ {
+ st->log_en_index = 63;
+ }
+ if (st->log_en_index < 0)
+ {
+ st->log_en_index = 0;
+ }
+ /* Quantize ISFs */
+ Qisf_ns(isf, isf, indice);
- Parm_serial(indice[0], 6, prms);
- Parm_serial(indice[1], 6, prms);
- Parm_serial(indice[2], 6, prms);
- Parm_serial(indice[3], 5, prms);
- Parm_serial(indice[4], 5, prms);
+ Parm_serial(indice[0], 6, prms);
+ Parm_serial(indice[1], 6, prms);
+ Parm_serial(indice[2], 6, prms);
+ Parm_serial(indice[3], 5, prms);
+ Parm_serial(indice[4], 5, prms);
- Parm_serial((st->log_en_index), 6, prms);
+ Parm_serial((st->log_en_index), 6, prms);
- CN_dith = dithering_control(st);
- Parm_serial(CN_dith, 1, prms);
+ CN_dith = dithering_control(st);
+ Parm_serial(CN_dith, 1, prms);
- /* level = (float)( pow( 2.0f, (float)st->log_en_index / 2.625 - 2.0 ) ); */
- /* log2(E) in Q9 (log2(E) lies in between -2:22) */
- log_en = shl(st->log_en_index, 15 - 6);
+ /* level = (float)( pow( 2.0f, (float)st->log_en_index / 2.625 - 2.0 ) ); */
+ /* log2(E) in Q9 (log2(E) lies in between -2:22) */
+ log_en = shl(st->log_en_index, 15 - 6);
- /* Divide by 2.625; log_en will be between 0:24 */
- log_en = mult(log_en, 12483);
- /* the result corresponds to log2(gain) in Q10 */
+ /* Divide by 2.625; log_en will be between 0:24 */
+ log_en = mult(log_en, 12483);
+ /* the result corresponds to log2(gain) in Q10 */
- /* Find integer part */
- log_en_int_e = (log_en >> 10);
+ /* Find integer part */
+ log_en_int_e = (log_en >> 10);
- /* Find fractional part */
- log_en_int_m = (Word16) (log_en & 0x3ff);
- log_en_int_m = shl(log_en_int_m, 5);
+ /* Find fractional part */
+ log_en_int_m = (Word16) (log_en & 0x3ff);
+ log_en_int_m = shl(log_en_int_m, 5);
- /* Subtract 2 from log_en in Q9, i.e divide the gain by 2 (energy by 4) */
- /* Add 16 in order to have the result of pow2 in Q16 */
- log_en_int_e = add(log_en_int_e, 16 - 1);
+ /* Subtract 2 from log_en in Q9, i.e divide the gain by 2 (energy by 4) */
+ /* Add 16 in order to have the result of pow2 in Q16 */
+ log_en_int_e = add(log_en_int_e, 16 - 1);
- level32 = Pow2(log_en_int_e, log_en_int_m); /* Q16 */
- exp0 = norm_l(level32);
- level32 = (level32 << exp0); /* level in Q31 */
- exp0 = (15 - exp0);
- level = extract_h(level32); /* level in Q15 */
+ level32 = Pow2(log_en_int_e, log_en_int_m); /* Q16 */
+ exp0 = norm_l(level32);
+ level32 = (level32 << exp0); /* level in Q31 */
+ exp0 = (15 - exp0);
+ level = extract_h(level32); /* level in Q15 */
- /* generate white noise vector */
- for (i = 0; i < L_FRAME; i++)
- {
- exc2[i] = (Random(&(st->cng_seed)) >> 4);
- }
+ /* generate white noise vector */
+ for (i = 0; i < L_FRAME; i++)
+ {
+ exc2[i] = (Random(&(st->cng_seed)) >> 4);
+ }
- /* gain = level / sqrt(ener) * sqrt(L_FRAME) */
+ /* gain = level / sqrt(ener) * sqrt(L_FRAME) */
- /* energy of generated excitation */
- ener32 = Dot_product12(exc2, exc2, L_FRAME, &exp);
+ /* energy of generated excitation */
+ ener32 = Dot_product12(exc2, exc2, L_FRAME, &exp);
- Isqrt_n(&ener32, &exp);
+ Isqrt_n(&ener32, &exp);
- gain = extract_h(ener32);
+ gain = extract_h(ener32);
- gain = mult(level, gain); /* gain in Q15 */
+ gain = mult(level, gain); /* gain in Q15 */
- exp = add(exp0, exp);
+ exp = add(exp0, exp);
- /* Multiply by sqrt(L_FRAME)=16, i.e. shift left by 4 */
- exp += 4;
+ /* Multiply by sqrt(L_FRAME)=16, i.e. shift left by 4 */
+ exp += 4;
- for (i = 0; i < L_FRAME; i++)
- {
- tmp = mult(exc2[i], gain); /* Q0 * Q15 */
- exc2[i] = shl(tmp, exp);
- }
+ for (i = 0; i < L_FRAME; i++)
+ {
+ tmp = mult(exc2[i], gain); /* Q0 * Q15 */
+ exc2[i] = shl(tmp, exp);
+ }
- return 0;
+ return 0;
}
/**************************************************************************
@@ -291,45 +291,45 @@
*
**************************************************************************/
Word16 dtx_buffer(
- dtx_encState * st, /* i/o : State struct */
- Word16 isf_new[], /* i : isf vector */
- Word32 enr, /* i : residual energy (in L_FRAME) */
- Word16 codec_mode
- )
+ dtx_encState * st, /* i/o : State struct */
+ Word16 isf_new[], /* i : isf vector */
+ Word32 enr, /* i : residual energy (in L_FRAME) */
+ Word16 codec_mode
+ )
{
- Word16 log_en;
+ Word16 log_en;
- Word16 log_en_e;
- Word16 log_en_m;
- st->hist_ptr = add(st->hist_ptr, 1);
- if(st->hist_ptr == DTX_HIST_SIZE)
- {
- st->hist_ptr = 0;
- }
- /* copy lsp vector into buffer */
- Copy(isf_new, &st->isf_hist[st->hist_ptr * M], M);
+ Word16 log_en_e;
+ Word16 log_en_m;
+ st->hist_ptr = add(st->hist_ptr, 1);
+ if(st->hist_ptr == DTX_HIST_SIZE)
+ {
+ st->hist_ptr = 0;
+ }
+ /* copy lsp vector into buffer */
+ Copy(isf_new, &st->isf_hist[st->hist_ptr * M], M);
- /* log_en = (float)log10(enr*0.0059322)/(float)log10(2.0f); */
- Log2(enr, &log_en_e, &log_en_m);
+ /* log_en = (float)log10(enr*0.0059322)/(float)log10(2.0f); */
+ Log2(enr, &log_en_e, &log_en_m);
- /* convert exponent and mantissa to Word16 Q7. Q7 is used to simplify averaging in dtx_enc */
- log_en = shl(log_en_e, 7); /* Q7 */
- log_en = add(log_en, shr(log_en_m, 15 - 7));
+ /* convert exponent and mantissa to Word16 Q7. Q7 is used to simplify averaging in dtx_enc */
+ log_en = shl(log_en_e, 7); /* Q7 */
+ log_en = add(log_en, shr(log_en_m, 15 - 7));
- /* Find energy per sample by multiplying with 0.0059322, i.e subtract log2(1/0.0059322) = 7.39722 The
- * constant 0.0059322 takes into account windowings and analysis length from autocorrelation
- * computations; 7.39722 in Q7 = 947 */
- /* Subtract 3 dB = 0.99658 in log2(E) = 127 in Q7. */
- /* log_en = sub( log_en, 947 + en_adjust[codec_mode] ); */
+ /* Find energy per sample by multiplying with 0.0059322, i.e subtract log2(1/0.0059322) = 7.39722 The
+ * constant 0.0059322 takes into account windowings and analysis length from autocorrelation
+ * computations; 7.39722 in Q7 = 947 */
+ /* Subtract 3 dB = 0.99658 in log2(E) = 127 in Q7. */
+ /* log_en = sub( log_en, 947 + en_adjust[codec_mode] ); */
- /* Find energy per sample (divide by L_FRAME=256), i.e subtract log2(256) = 8.0 (1024 in Q7) */
- /* Subtract 3 dB = 0.99658 in log2(E) = 127 in Q7. */
+ /* Find energy per sample (divide by L_FRAME=256), i.e subtract log2(256) = 8.0 (1024 in Q7) */
+ /* Subtract 3 dB = 0.99658 in log2(E) = 127 in Q7. */
- log_en = sub(log_en, add(1024, en_adjust[codec_mode]));
+ log_en = sub(log_en, add(1024, en_adjust[codec_mode]));
- /* Insert into the buffer */
- st->log_en_hist[st->hist_ptr] = log_en;
- return 0;
+ /* Insert into the buffer */
+ st->log_en_hist[st->hist_ptr] = log_en;
+ return 0;
}
/**************************************************************************
@@ -339,267 +339,267 @@
* the decoding side.
**************************************************************************/
void tx_dtx_handler(dtx_encState * st, /* i/o : State struct */
- Word16 vad_flag, /* i : vad decision */
- Word16 * usedMode /* i/o : mode changed or not */
- )
+ Word16 vad_flag, /* i : vad decision */
+ Word16 * usedMode /* i/o : mode changed or not */
+ )
{
- /* this state machine is in synch with the GSMEFR txDtx machine */
- st->decAnaElapsedCount = add(st->decAnaElapsedCount, 1);
+ /* this state machine is in synch with the GSMEFR txDtx machine */
+ st->decAnaElapsedCount = add(st->decAnaElapsedCount, 1);
- if (vad_flag != 0)
- {
- st->dtxHangoverCount = DTX_HANG_CONST;
- } else
- { /* non-speech */
- if (st->dtxHangoverCount == 0)
- { /* out of decoder analysis hangover */
- st->decAnaElapsedCount = 0;
- *usedMode = MRDTX;
- } else
- { /* in possible analysis hangover */
- st->dtxHangoverCount = sub(st->dtxHangoverCount, 1);
+ if (vad_flag != 0)
+ {
+ st->dtxHangoverCount = DTX_HANG_CONST;
+ } else
+ { /* non-speech */
+ if (st->dtxHangoverCount == 0)
+ { /* out of decoder analysis hangover */
+ st->decAnaElapsedCount = 0;
+ *usedMode = MRDTX;
+ } else
+ { /* in possible analysis hangover */
+ st->dtxHangoverCount = sub(st->dtxHangoverCount, 1);
- /* decAnaElapsedCount + dtxHangoverCount < DTX_ELAPSED_FRAMES_THRESH */
- if (sub(add(st->decAnaElapsedCount, st->dtxHangoverCount),
- DTX_ELAPSED_FRAMES_THRESH) < 0)
- {
- *usedMode = MRDTX;
- /* if short time since decoder update, do not add extra HO */
- }
- /* else override VAD and stay in speech mode *usedMode and add extra hangover */
- }
- }
+ /* decAnaElapsedCount + dtxHangoverCount < DTX_ELAPSED_FRAMES_THRESH */
+ if (sub(add(st->decAnaElapsedCount, st->dtxHangoverCount),
+ DTX_ELAPSED_FRAMES_THRESH) < 0)
+ {
+ *usedMode = MRDTX;
+ /* if short time since decoder update, do not add extra HO */
+ }
+ /* else override VAD and stay in speech mode *usedMode and add extra hangover */
+ }
+ }
- return;
+ return;
}
static void aver_isf_history(
- Word16 isf_old[],
- Word16 indices[],
- Word32 isf_aver[]
- )
+ Word16 isf_old[],
+ Word16 indices[],
+ Word32 isf_aver[]
+ )
{
- Word32 i, j, k;
- Word16 isf_tmp[2 * M];
- Word32 L_tmp;
+ Word32 i, j, k;
+ Word16 isf_tmp[2 * M];
+ Word32 L_tmp;
- /* Memorize in isf_tmp[][] the ISF vectors to be replaced by */
- /* the median ISF vector prior to the averaging */
- for (k = 0; k < 2; k++)
- {
- if ((indices[k] + 1) != 0)
- {
- for (i = 0; i < M; i++)
- {
- isf_tmp[k * M + i] = isf_old[indices[k] * M + i];
- isf_old[indices[k] * M + i] = isf_old[indices[2] * M + i];
- }
- }
- }
+ /* Memorize in isf_tmp[][] the ISF vectors to be replaced by */
+ /* the median ISF vector prior to the averaging */
+ for (k = 0; k < 2; k++)
+ {
+ if ((indices[k] + 1) != 0)
+ {
+ for (i = 0; i < M; i++)
+ {
+ isf_tmp[k * M + i] = isf_old[indices[k] * M + i];
+ isf_old[indices[k] * M + i] = isf_old[indices[2] * M + i];
+ }
+ }
+ }
- /* Perform the ISF averaging */
- for (j = 0; j < M; j++)
- {
- L_tmp = 0;
+ /* Perform the ISF averaging */
+ for (j = 0; j < M; j++)
+ {
+ L_tmp = 0;
- for (i = 0; i < DTX_HIST_SIZE; i++)
- {
- L_tmp = L_add(L_tmp, L_deposit_l(isf_old[i * M + j]));
- }
- isf_aver[j] = L_tmp;
- }
+ for (i = 0; i < DTX_HIST_SIZE; i++)
+ {
+ L_tmp = L_add(L_tmp, L_deposit_l(isf_old[i * M + j]));
+ }
+ isf_aver[j] = L_tmp;
+ }
- /* Retrieve from isf_tmp[][] the ISF vectors saved prior to averaging */
- for (k = 0; k < 2; k++)
- {
- if ((indices[k] + 1) != 0)
- {
- for (i = 0; i < M; i++)
- {
- isf_old[indices[k] * M + i] = isf_tmp[k * M + i];
- }
- }
- }
+ /* Retrieve from isf_tmp[][] the ISF vectors saved prior to averaging */
+ for (k = 0; k < 2; k++)
+ {
+ if ((indices[k] + 1) != 0)
+ {
+ for (i = 0; i < M; i++)
+ {
+ isf_old[indices[k] * M + i] = isf_tmp[k * M + i];
+ }
+ }
+ }
- return;
+ return;
}
static void find_frame_indices(
- Word16 isf_old_tx[],
- Word16 indices[],
- dtx_encState * st
- )
+ Word16 isf_old_tx[],
+ Word16 indices[],
+ dtx_encState * st
+ )
{
- Word32 L_tmp, summin, summax, summax2nd;
- Word16 i, j, tmp;
- Word16 ptr;
+ Word32 L_tmp, summin, summax, summax2nd;
+ Word16 i, j, tmp;
+ Word16 ptr;
- /* Remove the effect of the oldest frame from the column */
- /* sum sumD[0..DTX_HIST_SIZE-1]. sumD[DTX_HIST_SIZE] is */
- /* not updated since it will be removed later. */
+ /* Remove the effect of the oldest frame from the column */
+ /* sum sumD[0..DTX_HIST_SIZE-1]. sumD[DTX_HIST_SIZE] is */
+ /* not updated since it will be removed later. */
- tmp = DTX_HIST_SIZE_MIN_ONE;
- j = -1;
- for (i = 0; i < DTX_HIST_SIZE_MIN_ONE; i++)
- {
- j = add(j, tmp);
- st->sumD[i] = L_sub(st->sumD[i], st->D[j]);
- tmp = sub(tmp, 1);
- }
+ tmp = DTX_HIST_SIZE_MIN_ONE;
+ j = -1;
+ for (i = 0; i < DTX_HIST_SIZE_MIN_ONE; i++)
+ {
+ j = add(j, tmp);
+ st->sumD[i] = L_sub(st->sumD[i], st->D[j]);
+ tmp = sub(tmp, 1);
+ }
- /* Shift the column sum sumD. The element sumD[DTX_HIST_SIZE-1] */
- /* corresponding to the oldest frame is removed. The sum of */
- /* the distances between the latest isf and other isfs, */
- /* i.e. the element sumD[0], will be computed during this call. */
- /* Hence this element is initialized to zero. */
+ /* Shift the column sum sumD. The element sumD[DTX_HIST_SIZE-1] */
+ /* corresponding to the oldest frame is removed. The sum of */
+ /* the distances between the latest isf and other isfs, */
+ /* i.e. the element sumD[0], will be computed during this call. */
+ /* Hence this element is initialized to zero. */
- for (i = DTX_HIST_SIZE_MIN_ONE; i > 0; i--)
- {
- st->sumD[i] = st->sumD[i - 1];
- }
- st->sumD[0] = 0;
+ for (i = DTX_HIST_SIZE_MIN_ONE; i > 0; i--)
+ {
+ st->sumD[i] = st->sumD[i - 1];
+ }
+ st->sumD[0] = 0;
- /* Remove the oldest frame from the distance matrix. */
- /* Note that the distance matrix is replaced by a one- */
- /* dimensional array to save static memory. */
+ /* Remove the oldest frame from the distance matrix. */
+ /* Note that the distance matrix is replaced by a one- */
+ /* dimensional array to save static memory. */
- tmp = 0;
- for (i = 27; i >= 12; i = (Word16) (i - tmp))
- {
- tmp = add(tmp, 1);
- for (j = tmp; j > 0; j--)
- {
- st->D[i - j + 1] = st->D[i - j - tmp];
- }
- }
+ tmp = 0;
+ for (i = 27; i >= 12; i = (Word16) (i - tmp))
+ {
+ tmp = add(tmp, 1);
+ for (j = tmp; j > 0; j--)
+ {
+ st->D[i - j + 1] = st->D[i - j - tmp];
+ }
+ }
- /* Compute the first column of the distance matrix D */
- /* (squared Euclidean distances from isf1[] to isf_old_tx[][]). */
+ /* Compute the first column of the distance matrix D */
+ /* (squared Euclidean distances from isf1[] to isf_old_tx[][]). */
- ptr = st->hist_ptr;
- for (i = 1; i < DTX_HIST_SIZE; i++)
- {
- /* Compute the distance between the latest isf and the other isfs. */
- ptr = sub(ptr, 1);
- if (ptr < 0)
- {
- ptr = DTX_HIST_SIZE_MIN_ONE;
- }
- L_tmp = 0;
- for (j = 0; j < M; j++)
- {
- tmp = sub(isf_old_tx[st->hist_ptr * M + j], isf_old_tx[ptr * M + j]);
- L_tmp = L_mac(L_tmp, tmp, tmp);
- }
- st->D[i - 1] = L_tmp;
+ ptr = st->hist_ptr;
+ for (i = 1; i < DTX_HIST_SIZE; i++)
+ {
+ /* Compute the distance between the latest isf and the other isfs. */
+ ptr = sub(ptr, 1);
+ if (ptr < 0)
+ {
+ ptr = DTX_HIST_SIZE_MIN_ONE;
+ }
+ L_tmp = 0;
+ for (j = 0; j < M; j++)
+ {
+ tmp = sub(isf_old_tx[st->hist_ptr * M + j], isf_old_tx[ptr * M + j]);
+ L_tmp = L_mac(L_tmp, tmp, tmp);
+ }
+ st->D[i - 1] = L_tmp;
- /* Update also the column sums. */
- st->sumD[0] = L_add(st->sumD[0], st->D[i - 1]);
- st->sumD[i] = L_add(st->sumD[i], st->D[i - 1]);
- }
+ /* Update also the column sums. */
+ st->sumD[0] = L_add(st->sumD[0], st->D[i - 1]);
+ st->sumD[i] = L_add(st->sumD[i], st->D[i - 1]);
+ }
- /* Find the minimum and maximum distances */
- summax = st->sumD[0];
- summin = st->sumD[0];
- indices[0] = 0;
- indices[2] = 0;
- for (i = 1; i < DTX_HIST_SIZE; i++)
- {
- if (L_sub(st->sumD[i], summax) > 0)
- {
- indices[0] = i;
- summax = st->sumD[i];
- }
- if (L_sub(st->sumD[i], summin) < 0)
- {
- indices[2] = i;
- summin = st->sumD[i];
- }
- }
+ /* Find the minimum and maximum distances */
+ summax = st->sumD[0];
+ summin = st->sumD[0];
+ indices[0] = 0;
+ indices[2] = 0;
+ for (i = 1; i < DTX_HIST_SIZE; i++)
+ {
+ if (L_sub(st->sumD[i], summax) > 0)
+ {
+ indices[0] = i;
+ summax = st->sumD[i];
+ }
+ if (L_sub(st->sumD[i], summin) < 0)
+ {
+ indices[2] = i;
+ summin = st->sumD[i];
+ }
+ }
- /* Find the second largest distance */
- summax2nd = -2147483647L;
- indices[1] = -1;
- for (i = 0; i < DTX_HIST_SIZE; i++)
- {
- if ((L_sub(st->sumD[i], summax2nd) > 0) && (sub(i, indices[0]) != 0))
- {
- indices[1] = i;
- summax2nd = st->sumD[i];
- }
- }
+ /* Find the second largest distance */
+ summax2nd = -2147483647L;
+ indices[1] = -1;
+ for (i = 0; i < DTX_HIST_SIZE; i++)
+ {
+ if ((L_sub(st->sumD[i], summax2nd) > 0) && (sub(i, indices[0]) != 0))
+ {
+ indices[1] = i;
+ summax2nd = st->sumD[i];
+ }
+ }
- for (i = 0; i < 3; i++)
- {
- indices[i] = sub(st->hist_ptr, indices[i]);
- if (indices[i] < 0)
- {
- indices[i] = add(indices[i], DTX_HIST_SIZE);
- }
- }
+ for (i = 0; i < 3; i++)
+ {
+ indices[i] = sub(st->hist_ptr, indices[i]);
+ if (indices[i] < 0)
+ {
+ indices[i] = add(indices[i], DTX_HIST_SIZE);
+ }
+ }
- /* If maximum distance/MED_THRESH is smaller than minimum distance */
- /* then the median ISF vector replacement is not performed */
- tmp = norm_l(summax);
- summax = (summax << tmp);
- summin = (summin << tmp);
- L_tmp = L_mult(voround(summax), INV_MED_THRESH);
- if(L_tmp <= summin)
- {
- indices[0] = -1;
- }
- /* If second largest distance/MED_THRESH is smaller than */
- /* minimum distance then the median ISF vector replacement is */
- /* not performed */
- summax2nd = L_shl(summax2nd, tmp);
- L_tmp = L_mult(voround(summax2nd), INV_MED_THRESH);
- if(L_tmp <= summin)
- {
- indices[1] = -1;
- }
- return;
+ /* If maximum distance/MED_THRESH is smaller than minimum distance */
+ /* then the median ISF vector replacement is not performed */
+ tmp = norm_l(summax);
+ summax = (summax << tmp);
+ summin = (summin << tmp);
+ L_tmp = L_mult(voround(summax), INV_MED_THRESH);
+ if(L_tmp <= summin)
+ {
+ indices[0] = -1;
+ }
+ /* If second largest distance/MED_THRESH is smaller than */
+ /* minimum distance then the median ISF vector replacement is */
+ /* not performed */
+ summax2nd = L_shl(summax2nd, tmp);
+ L_tmp = L_mult(voround(summax2nd), INV_MED_THRESH);
+ if(L_tmp <= summin)
+ {
+ indices[1] = -1;
+ }
+ return;
}
static Word16 dithering_control(
- dtx_encState * st
- )
+ dtx_encState * st
+ )
{
- Word16 tmp, mean, CN_dith, gain_diff;
- Word32 i, ISF_diff;
+ Word16 tmp, mean, CN_dith, gain_diff;
+ Word32 i, ISF_diff;
- /* determine how stationary the spectrum of background noise is */
- ISF_diff = 0;
- for (i = 0; i < 8; i++)
- {
- ISF_diff = L_add(ISF_diff, st->sumD[i]);
- }
- if ((ISF_diff >> 26) > 0)
- {
- CN_dith = 1;
- } else
- {
- CN_dith = 0;
- }
+ /* determine how stationary the spectrum of background noise is */
+ ISF_diff = 0;
+ for (i = 0; i < 8; i++)
+ {
+ ISF_diff = L_add(ISF_diff, st->sumD[i]);
+ }
+ if ((ISF_diff >> 26) > 0)
+ {
+ CN_dith = 1;
+ } else
+ {
+ CN_dith = 0;
+ }
- /* determine how stationary the energy of background noise is */
- mean = 0;
- for (i = 0; i < DTX_HIST_SIZE; i++)
- {
- mean = add(mean, st->log_en_hist[i]);
- }
- mean = (mean >> 3);
- gain_diff = 0;
- for (i = 0; i < DTX_HIST_SIZE; i++)
- {
- tmp = abs_s(sub(st->log_en_hist[i], mean));
- gain_diff = add(gain_diff, tmp);
- }
- if (gain_diff > GAIN_THR)
- {
- CN_dith = 1;
- }
- return CN_dith;
+ /* determine how stationary the energy of background noise is */
+ mean = 0;
+ for (i = 0; i < DTX_HIST_SIZE; i++)
+ {
+ mean = add(mean, st->log_en_hist[i]);
+ }
+ mean = (mean >> 3);
+ gain_diff = 0;
+ for (i = 0; i < DTX_HIST_SIZE; i++)
+ {
+ tmp = abs_s(sub(st->log_en_hist[i], mean));
+ gain_diff = add(gain_diff, tmp);
+ }
+ if (gain_diff > GAIN_THR)
+ {
+ CN_dith = 1;
+ }
+ return CN_dith;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/g_pitch.c b/media/libstagefright/codecs/amrwbenc/src/g_pitch.c
index d681f2e..98ee87e 100644
--- a/media/libstagefright/codecs/amrwbenc/src/g_pitch.c
+++ b/media/libstagefright/codecs/amrwbenc/src/g_pitch.c
@@ -17,9 +17,9 @@
/***********************************************************************
* File: g_pitch.c *
* *
-* Description:Compute the gain of pitch. Result in Q12 *
-* if(gain < 0) gain = 0 *
-* if(gain > 1.2) gain = 1.2 *
+* Description:Compute the gain of pitch. Result in Q12 *
+* if(gain < 0) gain = 0 *
+* if(gain > 1.2) gain = 1.2 *
************************************************************************/
#include "typedef.h"
@@ -27,52 +27,52 @@
#include "math_op.h"
Word16 G_pitch( /* (o) Q14 : Gain of pitch lag saturated to 1.2 */
- Word16 xn[], /* (i) : Pitch target. */
- Word16 y1[], /* (i) : filtered adaptive codebook. */
- Word16 g_coeff[], /* : Correlations need for gain quantization. */
- Word16 L_subfr /* : Length of subframe. */
- )
+ Word16 xn[], /* (i) : Pitch target. */
+ Word16 y1[], /* (i) : filtered adaptive codebook. */
+ Word16 g_coeff[], /* : Correlations need for gain quantization. */
+ Word16 L_subfr /* : Length of subframe. */
+ )
{
- Word32 i;
- Word16 xy, yy, exp_xy, exp_yy, gain;
- /* Compute scalar product <y1[],y1[]> */
+ Word32 i;
+ Word16 xy, yy, exp_xy, exp_yy, gain;
+ /* Compute scalar product <y1[],y1[]> */
#ifdef ASM_OPT /* asm optimization branch */
- /* Compute scalar product <xn[],y1[]> */
- xy = extract_h(Dot_product12_asm(xn, y1, L_subfr, &exp_xy));
- yy = extract_h(Dot_product12_asm(y1, y1, L_subfr, &exp_yy));
+ /* Compute scalar product <xn[],y1[]> */
+ xy = extract_h(Dot_product12_asm(xn, y1, L_subfr, &exp_xy));
+ yy = extract_h(Dot_product12_asm(y1, y1, L_subfr, &exp_yy));
#else
- /* Compute scalar product <xn[],y1[]> */
- xy = extract_h(Dot_product12(xn, y1, L_subfr, &exp_xy));
- yy = extract_h(Dot_product12(y1, y1, L_subfr, &exp_yy));
+ /* Compute scalar product <xn[],y1[]> */
+ xy = extract_h(Dot_product12(xn, y1, L_subfr, &exp_xy));
+ yy = extract_h(Dot_product12(y1, y1, L_subfr, &exp_yy));
#endif
- g_coeff[0] = yy;
- g_coeff[1] = exp_yy;
- g_coeff[2] = xy;
- g_coeff[3] = exp_xy;
+ g_coeff[0] = yy;
+ g_coeff[1] = exp_yy;
+ g_coeff[2] = xy;
+ g_coeff[3] = exp_xy;
- /* If (xy < 0) gain = 0 */
- if (xy < 0)
- return ((Word16) 0);
+ /* If (xy < 0) gain = 0 */
+ if (xy < 0)
+ return ((Word16) 0);
- /* compute gain = xy/yy */
+ /* compute gain = xy/yy */
- xy >>= 1; /* Be sure xy < yy */
- gain = div_s(xy, yy);
+ xy >>= 1; /* Be sure xy < yy */
+ gain = div_s(xy, yy);
- i = exp_xy;
- i -= exp_yy;
+ i = exp_xy;
+ i -= exp_yy;
- gain = shl(gain, i);
+ gain = shl(gain, i);
- /* if (gain > 1.2) gain = 1.2 in Q14 */
- if(gain > 19661)
- {
- gain = 19661;
- }
- return (gain);
+ /* if (gain > 1.2) gain = 1.2 in Q14 */
+ if(gain > 19661)
+ {
+ gain = 19661;
+ }
+ return (gain);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/gpclip.c b/media/libstagefright/codecs/amrwbenc/src/gpclip.c
index 800b3f9..4ce3daa 100644
--- a/media/libstagefright/codecs/amrwbenc/src/gpclip.c
+++ b/media/libstagefright/codecs/amrwbenc/src/gpclip.c
@@ -35,75 +35,75 @@
void Init_gp_clip(
- Word16 mem[] /* (o) : memory of gain of pitch clipping algorithm */
- )
+ Word16 mem[] /* (o) : memory of gain of pitch clipping algorithm */
+ )
{
- mem[0] = DIST_ISF_MAX;
- mem[1] = GAIN_PIT_MIN;
+ mem[0] = DIST_ISF_MAX;
+ mem[1] = GAIN_PIT_MIN;
}
Word16 Gp_clip(
- Word16 mem[] /* (i/o) : memory of gain of pitch clipping algorithm */
- )
+ Word16 mem[] /* (i/o) : memory of gain of pitch clipping algorithm */
+ )
{
- Word16 clip = 0;
- if ((mem[0] < DIST_ISF_THRES) && (mem[1] > GAIN_PIT_THRES))
- clip = 1;
+ Word16 clip = 0;
+ if ((mem[0] < DIST_ISF_THRES) && (mem[1] > GAIN_PIT_THRES))
+ clip = 1;
- return (clip);
+ return (clip);
}
void Gp_clip_test_isf(
- Word16 isf[], /* (i) : isf values (in frequency domain) */
- Word16 mem[] /* (i/o) : memory of gain of pitch clipping algorithm */
- )
+ Word16 isf[], /* (i) : isf values (in frequency domain) */
+ Word16 mem[] /* (i/o) : memory of gain of pitch clipping algorithm */
+ )
{
- Word16 dist, dist_min;
- Word32 i;
+ Word16 dist, dist_min;
+ Word32 i;
- dist_min = vo_sub(isf[1], isf[0]);
+ dist_min = vo_sub(isf[1], isf[0]);
- for (i = 2; i < M - 1; i++)
- {
- dist = vo_sub(isf[i], isf[i - 1]);
- if(dist < dist_min)
- {
- dist_min = dist;
- }
- }
+ for (i = 2; i < M - 1; i++)
+ {
+ dist = vo_sub(isf[i], isf[i - 1]);
+ if(dist < dist_min)
+ {
+ dist_min = dist;
+ }
+ }
- dist = extract_h(L_mac(vo_L_mult(26214, mem[0]), 6554, dist_min));
+ dist = extract_h(L_mac(vo_L_mult(26214, mem[0]), 6554, dist_min));
- if (dist > DIST_ISF_MAX)
- {
- dist = DIST_ISF_MAX;
- }
- mem[0] = dist;
+ if (dist > DIST_ISF_MAX)
+ {
+ dist = DIST_ISF_MAX;
+ }
+ mem[0] = dist;
- return;
+ return;
}
void Gp_clip_test_gain_pit(
- Word16 gain_pit, /* (i) Q14 : gain of quantized pitch */
- Word16 mem[] /* (i/o) : memory of gain of pitch clipping algorithm */
- )
+ Word16 gain_pit, /* (i) Q14 : gain of quantized pitch */
+ Word16 mem[] /* (i/o) : memory of gain of pitch clipping algorithm */
+ )
{
- Word16 gain;
- Word32 L_tmp;
- L_tmp = (29491 * mem[1])<<1;
- L_tmp += (3277 * gain_pit)<<1;
+ Word16 gain;
+ Word32 L_tmp;
+ L_tmp = (29491 * mem[1])<<1;
+ L_tmp += (3277 * gain_pit)<<1;
- gain = extract_h(L_tmp);
+ gain = extract_h(L_tmp);
- if(gain < GAIN_PIT_MIN)
- {
- gain = GAIN_PIT_MIN;
- }
- mem[1] = gain;
- return;
+ if(gain < GAIN_PIT_MIN)
+ {
+ gain = GAIN_PIT_MIN;
+ }
+ mem[1] = gain;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/homing.c b/media/libstagefright/codecs/amrwbenc/src/homing.c
index 565040f..a96e7db 100644
--- a/media/libstagefright/codecs/amrwbenc/src/homing.c
+++ b/media/libstagefright/codecs/amrwbenc/src/homing.c
@@ -29,18 +29,18 @@
Word16 encoder_homing_frame_test(Word16 input_frame[])
{
- Word32 i;
- Word16 j = 0;
+ Word32 i;
+ Word16 j = 0;
- /* check 320 input samples for matching EHF_MASK: defined in e_homing.h */
- for (i = 0; i < L_FRAME16k; i++)
- {
- j = (Word16) (input_frame[i] ^ EHF_MASK);
+ /* check 320 input samples for matching EHF_MASK: defined in e_homing.h */
+ for (i = 0; i < L_FRAME16k; i++)
+ {
+ j = (Word16) (input_frame[i] ^ EHF_MASK);
- if (j)
- break;
- }
+ if (j)
+ break;
+ }
- return (Word16) (!j);
+ return (Word16) (!j);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/hp400.c b/media/libstagefright/codecs/amrwbenc/src/hp400.c
index a6f9701..c658a92 100644
--- a/media/libstagefright/codecs/amrwbenc/src/hp400.c
+++ b/media/libstagefright/codecs/amrwbenc/src/hp400.c
@@ -50,56 +50,56 @@
void Init_HP400_12k8(Word16 mem[])
{
- Set_zero(mem, 6);
+ Set_zero(mem, 6);
}
void HP400_12k8(
- Word16 signal[], /* input signal / output is divided by 16 */
- Word16 lg, /* lenght of signal */
- Word16 mem[] /* filter memory [6] */
- )
+ Word16 signal[], /* input signal / output is divided by 16 */
+ Word16 lg, /* lenght of signal */
+ Word16 mem[] /* filter memory [6] */
+ )
{
- Word16 x2;
- Word16 y2_hi, y2_lo, y1_hi, y1_lo, x0, x1;
- Word32 L_tmp;
- Word32 num;
- y2_hi = *mem++;
- y2_lo = *mem++;
- y1_hi = *mem++;
- y1_lo = *mem++;
- x0 = *mem++;
- x1 = *mem;
- num = (Word32)lg;
- do
- {
- x2 = x1;
- x1 = x0;
- x0 = *signal;
- /* y[i] = b[0]*x[i] + b[1]*x[i-1] + b140[2]*x[i-2] */
- /* + a[1]*y[i-1] + a[2] * y[i-2]; */
- L_tmp = 8192L; /* rounding to maximise precision */
- L_tmp += y1_lo * a[1];
- L_tmp += y2_lo * a[2];
- L_tmp = L_tmp >> 14;
- L_tmp += (y1_hi * a[1] + y2_hi * a[2] + (x0 + x2)* b[0] + x1 * b[1]) << 1;
- L_tmp <<= 1; /* coeff Q12 --> Q13 */
- y2_hi = y1_hi;
- y2_lo = y1_lo;
- y1_hi = (Word16)(L_tmp>>16);
- y1_lo = (Word16)((L_tmp & 0xffff)>>1);
+ Word16 x2;
+ Word16 y2_hi, y2_lo, y1_hi, y1_lo, x0, x1;
+ Word32 L_tmp;
+ Word32 num;
+ y2_hi = *mem++;
+ y2_lo = *mem++;
+ y1_hi = *mem++;
+ y1_lo = *mem++;
+ x0 = *mem++;
+ x1 = *mem;
+ num = (Word32)lg;
+ do
+ {
+ x2 = x1;
+ x1 = x0;
+ x0 = *signal;
+ /* y[i] = b[0]*x[i] + b[1]*x[i-1] + b140[2]*x[i-2] */
+ /* + a[1]*y[i-1] + a[2] * y[i-2]; */
+ L_tmp = 8192L; /* rounding to maximise precision */
+ L_tmp += y1_lo * a[1];
+ L_tmp += y2_lo * a[2];
+ L_tmp = L_tmp >> 14;
+ L_tmp += (y1_hi * a[1] + y2_hi * a[2] + (x0 + x2)* b[0] + x1 * b[1]) << 1;
+ L_tmp <<= 1; /* coeff Q12 --> Q13 */
+ y2_hi = y1_hi;
+ y2_lo = y1_lo;
+ y1_hi = (Word16)(L_tmp>>16);
+ y1_lo = (Word16)((L_tmp & 0xffff)>>1);
- /* signal is divided by 16 to avoid overflow in energy computation */
- *signal++ = (L_tmp + 0x8000) >> 16;
- }while(--num !=0);
+ /* signal is divided by 16 to avoid overflow in energy computation */
+ *signal++ = (L_tmp + 0x8000) >> 16;
+ }while(--num !=0);
- *mem-- = x1;
- *mem-- = x0;
- *mem-- = y1_lo;
- *mem-- = y1_hi;
- *mem-- = y2_lo;
- *mem = y2_hi;
- return;
+ *mem-- = x1;
+ *mem-- = x0;
+ *mem-- = y1_lo;
+ *mem-- = y1_hi;
+ *mem-- = y2_lo;
+ *mem = y2_hi;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/hp50.c b/media/libstagefright/codecs/amrwbenc/src/hp50.c
index c1c7b83..807d672 100644
--- a/media/libstagefright/codecs/amrwbenc/src/hp50.c
+++ b/media/libstagefright/codecs/amrwbenc/src/hp50.c
@@ -17,7 +17,7 @@
/***********************************************************************
* File: hp50.c *
* *
-* Description: *
+* Description: *
* 2nd order high pass filter with cut off frequency at 31 Hz. *
* Designed with cheby2 function in MATLAB. *
* Optimized for fixed-point to get the following frequency response: *
@@ -51,56 +51,56 @@
void Init_HP50_12k8(Word16 mem[])
{
- Set_zero(mem, 6);
+ Set_zero(mem, 6);
}
void HP50_12k8(
- Word16 signal[], /* input/output signal */
- Word16 lg, /* lenght of signal */
- Word16 mem[] /* filter memory [6] */
- )
+ Word16 signal[], /* input/output signal */
+ Word16 lg, /* lenght of signal */
+ Word16 mem[] /* filter memory [6] */
+ )
{
- Word16 x2;
- Word16 y2_hi, y2_lo, y1_hi, y1_lo, x0, x1;
- Word32 L_tmp;
- Word32 num;
+ Word16 x2;
+ Word16 y2_hi, y2_lo, y1_hi, y1_lo, x0, x1;
+ Word32 L_tmp;
+ Word32 num;
- y2_hi = *mem++;
- y2_lo = *mem++;
- y1_hi = *mem++;
- y1_lo = *mem++;
- x0 = *mem++;
- x1 = *mem;
- num = (Word32)lg;
- do
- {
- x2 = x1;
- x1 = x0;
- x0 = *signal;
- /* y[i] = b[0]*x[i] + b[1]*x[i-1] + b140[2]*x[i-2] */
- /* + a[1]*y[i-1] + a[2] * y[i-2]; */
- L_tmp = 8192 ; /* rounding to maximise precision */
- L_tmp += y1_lo * a[1];
- L_tmp += y2_lo * a[2];
- L_tmp = L_tmp >> 14;
- L_tmp += (y1_hi * a[1] + y2_hi * a[2] + (x0 + x2) * b[0] + x1 * b[1]) << 1;
- L_tmp <<= 2; /* coeff Q12 --> Q13 */
- y2_hi = y1_hi;
- y2_lo = y1_lo;
- y1_hi = (Word16)(L_tmp>>16);
- y1_lo = (Word16)((L_tmp & 0xffff)>>1);
- *signal++ = extract_h((L_add((L_tmp<<1), 0x8000)));
- }while(--num !=0);
+ y2_hi = *mem++;
+ y2_lo = *mem++;
+ y1_hi = *mem++;
+ y1_lo = *mem++;
+ x0 = *mem++;
+ x1 = *mem;
+ num = (Word32)lg;
+ do
+ {
+ x2 = x1;
+ x1 = x0;
+ x0 = *signal;
+ /* y[i] = b[0]*x[i] + b[1]*x[i-1] + b140[2]*x[i-2] */
+ /* + a[1]*y[i-1] + a[2] * y[i-2]; */
+ L_tmp = 8192 ; /* rounding to maximise precision */
+ L_tmp += y1_lo * a[1];
+ L_tmp += y2_lo * a[2];
+ L_tmp = L_tmp >> 14;
+ L_tmp += (y1_hi * a[1] + y2_hi * a[2] + (x0 + x2) * b[0] + x1 * b[1]) << 1;
+ L_tmp <<= 2; /* coeff Q12 --> Q13 */
+ y2_hi = y1_hi;
+ y2_lo = y1_lo;
+ y1_hi = (Word16)(L_tmp>>16);
+ y1_lo = (Word16)((L_tmp & 0xffff)>>1);
+ *signal++ = extract_h((L_add((L_tmp<<1), 0x8000)));
+ }while(--num !=0);
- *mem-- = x1;
- *mem-- = x0;
- *mem-- = y1_lo;
- *mem-- = y1_hi;
- *mem-- = y2_lo;
- *mem-- = y2_hi;
+ *mem-- = x1;
+ *mem-- = x0;
+ *mem-- = y1_lo;
+ *mem-- = y1_hi;
+ *mem-- = y2_lo;
+ *mem-- = y2_hi;
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/hp6k.c b/media/libstagefright/codecs/amrwbenc/src/hp6k.c
index 8e66eb0..0baf612 100644
--- a/media/libstagefright/codecs/amrwbenc/src/hp6k.c
+++ b/media/libstagefright/codecs/amrwbenc/src/hp6k.c
@@ -17,10 +17,10 @@
/***********************************************************************
* File: hp6k.c *
* *
-* Description:15th order band pass 6kHz to 7kHz FIR filter *
+* Description:15th order band pass 6kHz to 7kHz FIR filter *
* frequency: 4kHz 5kHz 5.5kHz 6kHz 6.5kHz 7kHz 7.5kHz 8kHz *
-* dB loss: -60dB -45dB -13dB -3dB 0dB -3dB -13dB -45dB *
-* *
+* dB loss: -60dB -45dB -13dB -3dB 0dB -3dB -13dB -45dB *
+* *
************************************************************************/
#include "typedef.h"
@@ -34,58 +34,58 @@
Word16 fir_6k_7k[L_FIR] =
{
- -32, 47, 32, -27, -369,
- 1122, -1421, 0, 3798, -8880,
- 12349, -10984, 3548, 7766, -18001,
- 22118, -18001, 7766, 3548, -10984,
- 12349, -8880, 3798, 0, -1421,
- 1122, -369, -27, 32, 47,
- -32
+ -32, 47, 32, -27, -369,
+ 1122, -1421, 0, 3798, -8880,
+ 12349, -10984, 3548, 7766, -18001,
+ 22118, -18001, 7766, 3548, -10984,
+ 12349, -8880, 3798, 0, -1421,
+ 1122, -369, -27, 32, 47,
+ -32
};
void Init_Filt_6k_7k(Word16 mem[]) /* mem[30] */
{
- Set_zero(mem, L_FIR - 1);
- return;
+ Set_zero(mem, L_FIR - 1);
+ return;
}
void Filt_6k_7k(
- Word16 signal[], /* input: signal */
- Word16 lg, /* input: length of input */
- Word16 mem[] /* in/out: memory (size=30) */
- )
+ Word16 signal[], /* input: signal */
+ Word16 lg, /* input: length of input */
+ Word16 mem[] /* in/out: memory (size=30) */
+ )
{
- Word16 x[L_SUBFR16k + (L_FIR - 1)];
- Word32 i, L_tmp;
+ Word16 x[L_SUBFR16k + (L_FIR - 1)];
+ Word32 i, L_tmp;
- Copy(mem, x, L_FIR - 1);
- for (i = lg - 1; i >= 0; i--)
- {
- x[i + L_FIR - 1] = signal[i] >> 2; /* gain of filter = 4 */
- }
- for (i = 0; i < lg; i++)
- {
- L_tmp = (x[i] + x[i+ 30]) * fir_6k_7k[0];
- L_tmp += (x[i+1] + x[i + 29]) * fir_6k_7k[1];
- L_tmp += (x[i+2] + x[i + 28]) * fir_6k_7k[2];
- L_tmp += (x[i+3] + x[i + 27]) * fir_6k_7k[3];
- L_tmp += (x[i+4] + x[i + 26]) * fir_6k_7k[4];
- L_tmp += (x[i+5] + x[i + 25]) * fir_6k_7k[5];
- L_tmp += (x[i+6] + x[i + 24]) * fir_6k_7k[6];
- L_tmp += (x[i+7] + x[i + 23]) * fir_6k_7k[7];
- L_tmp += (x[i+8] + x[i + 22]) * fir_6k_7k[8];
- L_tmp += (x[i+9] + x[i + 21]) * fir_6k_7k[9];
- L_tmp += (x[i+10] + x[i + 20]) * fir_6k_7k[10];
- L_tmp += (x[i+11] + x[i + 19]) * fir_6k_7k[11];
- L_tmp += (x[i+12] + x[i + 18]) * fir_6k_7k[12];
- L_tmp += (x[i+13] + x[i + 17]) * fir_6k_7k[13];
- L_tmp += (x[i+14] + x[i + 16]) * fir_6k_7k[14];
- L_tmp += (x[i+15]) * fir_6k_7k[15];
- signal[i] = (L_tmp + 0x4000) >> 15;
- }
+ Copy(mem, x, L_FIR - 1);
+ for (i = lg - 1; i >= 0; i--)
+ {
+ x[i + L_FIR - 1] = signal[i] >> 2; /* gain of filter = 4 */
+ }
+ for (i = 0; i < lg; i++)
+ {
+ L_tmp = (x[i] + x[i+ 30]) * fir_6k_7k[0];
+ L_tmp += (x[i+1] + x[i + 29]) * fir_6k_7k[1];
+ L_tmp += (x[i+2] + x[i + 28]) * fir_6k_7k[2];
+ L_tmp += (x[i+3] + x[i + 27]) * fir_6k_7k[3];
+ L_tmp += (x[i+4] + x[i + 26]) * fir_6k_7k[4];
+ L_tmp += (x[i+5] + x[i + 25]) * fir_6k_7k[5];
+ L_tmp += (x[i+6] + x[i + 24]) * fir_6k_7k[6];
+ L_tmp += (x[i+7] + x[i + 23]) * fir_6k_7k[7];
+ L_tmp += (x[i+8] + x[i + 22]) * fir_6k_7k[8];
+ L_tmp += (x[i+9] + x[i + 21]) * fir_6k_7k[9];
+ L_tmp += (x[i+10] + x[i + 20]) * fir_6k_7k[10];
+ L_tmp += (x[i+11] + x[i + 19]) * fir_6k_7k[11];
+ L_tmp += (x[i+12] + x[i + 18]) * fir_6k_7k[12];
+ L_tmp += (x[i+13] + x[i + 17]) * fir_6k_7k[13];
+ L_tmp += (x[i+14] + x[i + 16]) * fir_6k_7k[14];
+ L_tmp += (x[i+15]) * fir_6k_7k[15];
+ signal[i] = (L_tmp + 0x4000) >> 15;
+ }
- Copy(x + lg, mem, L_FIR - 1);
+ Copy(x + lg, mem, L_FIR - 1);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/hp_wsp.c b/media/libstagefright/codecs/amrwbenc/src/hp_wsp.c
index bc1ec49..f0347cb 100644
--- a/media/libstagefright/codecs/amrwbenc/src/hp_wsp.c
+++ b/media/libstagefright/codecs/amrwbenc/src/hp_wsp.c
@@ -48,101 +48,101 @@
/* Initialization of static values */
void Init_Hp_wsp(Word16 mem[])
{
- Set_zero(mem, 9);
+ Set_zero(mem, 9);
- return;
+ return;
}
void scale_mem_Hp_wsp(Word16 mem[], Word16 exp)
{
- Word32 i;
- Word32 L_tmp;
+ Word32 i;
+ Word32 L_tmp;
- for (i = 0; i < 6; i += 2)
- {
- L_tmp = ((mem[i] << 16) + (mem[i + 1]<<1));
- L_tmp = L_shl(L_tmp, exp);
- mem[i] = L_tmp >> 16;
- mem[i + 1] = (L_tmp & 0xffff)>>1;
- }
+ for (i = 0; i < 6; i += 2)
+ {
+ L_tmp = ((mem[i] << 16) + (mem[i + 1]<<1));
+ L_tmp = L_shl(L_tmp, exp);
+ mem[i] = L_tmp >> 16;
+ mem[i + 1] = (L_tmp & 0xffff)>>1;
+ }
- for (i = 6; i < 9; i++)
- {
- L_tmp = L_deposit_h(mem[i]); /* x[i] */
- L_tmp = L_shl(L_tmp, exp);
- mem[i] = vo_round(L_tmp);
- }
+ for (i = 6; i < 9; i++)
+ {
+ L_tmp = L_deposit_h(mem[i]); /* x[i] */
+ L_tmp = L_shl(L_tmp, exp);
+ mem[i] = vo_round(L_tmp);
+ }
- return;
+ return;
}
void Hp_wsp(
- Word16 wsp[], /* i : wsp[] signal */
- Word16 hp_wsp[], /* o : hypass wsp[] */
- Word16 lg, /* i : lenght of signal */
- Word16 mem[] /* i/o : filter memory [9] */
- )
+ Word16 wsp[], /* i : wsp[] signal */
+ Word16 hp_wsp[], /* o : hypass wsp[] */
+ Word16 lg, /* i : lenght of signal */
+ Word16 mem[] /* i/o : filter memory [9] */
+ )
{
- Word16 x0, x1, x2, x3;
- Word16 y3_hi, y3_lo, y2_hi, y2_lo, y1_hi, y1_lo;
- Word32 i, L_tmp;
+ Word16 x0, x1, x2, x3;
+ Word16 y3_hi, y3_lo, y2_hi, y2_lo, y1_hi, y1_lo;
+ Word32 i, L_tmp;
- y3_hi = mem[0];
- y3_lo = mem[1];
- y2_hi = mem[2];
- y2_lo = mem[3];
- y1_hi = mem[4];
- y1_lo = mem[5];
- x0 = mem[6];
- x1 = mem[7];
- x2 = mem[8];
+ y3_hi = mem[0];
+ y3_lo = mem[1];
+ y2_hi = mem[2];
+ y2_lo = mem[3];
+ y1_hi = mem[4];
+ y1_lo = mem[5];
+ x0 = mem[6];
+ x1 = mem[7];
+ x2 = mem[8];
- for (i = 0; i < lg; i++)
- {
- x3 = x2;
- x2 = x1;
- x1 = x0;
- x0 = wsp[i];
- /* y[i] = b[0]*x[i] + b[1]*x[i-1] + b140[2]*x[i-2] + b[3]*x[i-3] */
- /* + a[1]*y[i-1] + a[2] * y[i-2] + a[3]*y[i-3] */
+ for (i = 0; i < lg; i++)
+ {
+ x3 = x2;
+ x2 = x1;
+ x1 = x0;
+ x0 = wsp[i];
+ /* y[i] = b[0]*x[i] + b[1]*x[i-1] + b140[2]*x[i-2] + b[3]*x[i-3] */
+ /* + a[1]*y[i-1] + a[2] * y[i-2] + a[3]*y[i-3] */
- L_tmp = 16384L; /* rounding to maximise precision */
- L_tmp += (y1_lo * a[1])<<1;
- L_tmp += (y2_lo * a[2])<<1;
- L_tmp += (y3_lo * a[3])<<1;
- L_tmp = L_tmp >> 15;
- L_tmp += (y1_hi * a[1])<<1;
- L_tmp += (y2_hi * a[2])<<1;
- L_tmp += (y3_hi * a[3])<<1;
- L_tmp += (x0 * b[0])<<1;
- L_tmp += (x1 * b[1])<<1;
- L_tmp += (x2 * b[2])<<1;
- L_tmp += (x3 * b[3])<<1;
+ L_tmp = 16384L; /* rounding to maximise precision */
+ L_tmp += (y1_lo * a[1])<<1;
+ L_tmp += (y2_lo * a[2])<<1;
+ L_tmp += (y3_lo * a[3])<<1;
+ L_tmp = L_tmp >> 15;
+ L_tmp += (y1_hi * a[1])<<1;
+ L_tmp += (y2_hi * a[2])<<1;
+ L_tmp += (y3_hi * a[3])<<1;
+ L_tmp += (x0 * b[0])<<1;
+ L_tmp += (x1 * b[1])<<1;
+ L_tmp += (x2 * b[2])<<1;
+ L_tmp += (x3 * b[3])<<1;
- L_tmp = L_tmp << 2;
+ L_tmp = L_tmp << 2;
- y3_hi = y2_hi;
- y3_lo = y2_lo;
- y2_hi = y1_hi;
- y2_lo = y1_lo;
- y1_hi = L_tmp >> 16;
- y1_lo = (L_tmp & 0xffff) >>1;
+ y3_hi = y2_hi;
+ y3_lo = y2_lo;
+ y2_hi = y1_hi;
+ y2_lo = y1_lo;
+ y1_hi = L_tmp >> 16;
+ y1_lo = (L_tmp & 0xffff) >>1;
- hp_wsp[i] = (L_tmp + 0x4000)>>15;
- }
+ hp_wsp[i] = (L_tmp + 0x4000)>>15;
+ }
- mem[0] = y3_hi;
- mem[1] = y3_lo;
- mem[2] = y2_hi;
- mem[3] = y2_lo;
- mem[4] = y1_hi;
- mem[5] = y1_lo;
- mem[6] = x0;
- mem[7] = x1;
- mem[8] = x2;
+ mem[0] = y3_hi;
+ mem[1] = y3_lo;
+ mem[2] = y2_hi;
+ mem[3] = y2_lo;
+ mem[4] = y1_hi;
+ mem[5] = y1_lo;
+ mem[6] = x0;
+ mem[7] = x1;
+ mem[8] = x2;
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/int_lpc.c b/media/libstagefright/codecs/amrwbenc/src/int_lpc.c
index 1119bc7..3d8b8cb 100644
--- a/media/libstagefright/codecs/amrwbenc/src/int_lpc.c
+++ b/media/libstagefright/codecs/amrwbenc/src/int_lpc.c
@@ -30,36 +30,36 @@
void Int_isp(
- Word16 isp_old[], /* input : isps from past frame */
- Word16 isp_new[], /* input : isps from present frame */
- Word16 frac[], /* input : fraction for 3 first subfr (Q15) */
- Word16 Az[] /* output: LP coefficients in 4 subframes */
- )
+ Word16 isp_old[], /* input : isps from past frame */
+ Word16 isp_new[], /* input : isps from present frame */
+ Word16 frac[], /* input : fraction for 3 first subfr (Q15) */
+ Word16 Az[] /* output: LP coefficients in 4 subframes */
+ )
{
- Word32 i, k;
- Word16 fac_old, fac_new;
- Word16 isp[M];
- Word32 L_tmp;
+ Word32 i, k;
+ Word16 fac_old, fac_new;
+ Word16 isp[M];
+ Word32 L_tmp;
- for (k = 0; k < 3; k++)
- {
- fac_new = frac[k];
- fac_old = (32767 - fac_new) + 1; /* 1.0 - fac_new */
+ for (k = 0; k < 3; k++)
+ {
+ fac_new = frac[k];
+ fac_old = (32767 - fac_new) + 1; /* 1.0 - fac_new */
- for (i = 0; i < M; i++)
- {
- L_tmp = (isp_old[i] * fac_old)<<1;
- L_tmp += (isp_new[i] * fac_new)<<1;
- isp[i] = (L_tmp + 0x8000)>>16;
- }
- Isp_Az(isp, Az, M, 0);
- Az += MP1;
- }
+ for (i = 0; i < M; i++)
+ {
+ L_tmp = (isp_old[i] * fac_old)<<1;
+ L_tmp += (isp_new[i] * fac_new)<<1;
+ isp[i] = (L_tmp + 0x8000)>>16;
+ }
+ Isp_Az(isp, Az, M, 0);
+ Az += MP1;
+ }
- /* 4th subframe: isp_new (frac=1.0) */
- Isp_Az(isp_new, Az, M, 0);
+ /* 4th subframe: isp_new (frac=1.0) */
+ Isp_Az(isp_new, Az, M, 0);
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/isp_az.c b/media/libstagefright/codecs/amrwbenc/src/isp_az.c
index 30a8bbd..62e29e7 100644
--- a/media/libstagefright/codecs/amrwbenc/src/isp_az.c
+++ b/media/libstagefright/codecs/amrwbenc/src/isp_az.c
@@ -35,132 +35,132 @@
static void Get_isp_pol_16kHz(Word16 * isp, Word32 * f, Word16 n);
void Isp_Az(
- Word16 isp[], /* (i) Q15 : Immittance spectral pairs */
- Word16 a[], /* (o) Q12 : predictor coefficients (order = M) */
- Word16 m,
- Word16 adaptive_scaling /* (i) 0 : adaptive scaling disabled */
- /* 1 : adaptive scaling enabled */
- )
+ Word16 isp[], /* (i) Q15 : Immittance spectral pairs */
+ Word16 a[], /* (o) Q12 : predictor coefficients (order = M) */
+ Word16 m,
+ Word16 adaptive_scaling /* (i) 0 : adaptive scaling disabled */
+ /* 1 : adaptive scaling enabled */
+ )
{
- Word32 i, j;
- Word16 hi, lo;
- Word32 f1[NC16k + 1], f2[NC16k];
- Word16 nc;
- Word32 t0;
- Word16 q, q_sug;
- Word32 tmax;
+ Word32 i, j;
+ Word16 hi, lo;
+ Word32 f1[NC16k + 1], f2[NC16k];
+ Word16 nc;
+ Word32 t0;
+ Word16 q, q_sug;
+ Word32 tmax;
- nc = (m >> 1);
- if(nc > 8)
- {
- Get_isp_pol_16kHz(&isp[0], f1, nc);
- for (i = 0; i <= nc; i++)
- {
- f1[i] = f1[i] << 2;
- }
- } else
- Get_isp_pol(&isp[0], f1, nc);
+ nc = (m >> 1);
+ if(nc > 8)
+ {
+ Get_isp_pol_16kHz(&isp[0], f1, nc);
+ for (i = 0; i <= nc; i++)
+ {
+ f1[i] = f1[i] << 2;
+ }
+ } else
+ Get_isp_pol(&isp[0], f1, nc);
- if (nc > 8)
- {
- Get_isp_pol_16kHz(&isp[1], f2, (nc - 1));
- for (i = 0; i <= nc - 1; i++)
- {
- f2[i] = f2[i] << 2;
- }
- } else
- Get_isp_pol(&isp[1], f2, (nc - 1));
+ if (nc > 8)
+ {
+ Get_isp_pol_16kHz(&isp[1], f2, (nc - 1));
+ for (i = 0; i <= nc - 1; i++)
+ {
+ f2[i] = f2[i] << 2;
+ }
+ } else
+ Get_isp_pol(&isp[1], f2, (nc - 1));
- /*-----------------------------------------------------*
- * Multiply F2(z) by (1 - z^-2) *
- *-----------------------------------------------------*/
+ /*-----------------------------------------------------*
+ * Multiply F2(z) by (1 - z^-2) *
+ *-----------------------------------------------------*/
- for (i = (nc - 1); i > 1; i--)
- {
- f2[i] = vo_L_sub(f2[i], f2[i - 2]); /* f2[i] -= f2[i-2]; */
- }
+ for (i = (nc - 1); i > 1; i--)
+ {
+ f2[i] = vo_L_sub(f2[i], f2[i - 2]); /* f2[i] -= f2[i-2]; */
+ }
- /*----------------------------------------------------------*
- * Scale F1(z) by (1+isp[m-1]) and F2(z) by (1-isp[m-1]) *
- *----------------------------------------------------------*/
+ /*----------------------------------------------------------*
+ * Scale F1(z) by (1+isp[m-1]) and F2(z) by (1-isp[m-1]) *
+ *----------------------------------------------------------*/
- for (i = 0; i < nc; i++)
- {
- /* f1[i] *= (1.0 + isp[M-1]); */
+ for (i = 0; i < nc; i++)
+ {
+ /* f1[i] *= (1.0 + isp[M-1]); */
- hi = f1[i] >> 16;
- lo = (f1[i] & 0xffff)>>1;
+ hi = f1[i] >> 16;
+ lo = (f1[i] & 0xffff)>>1;
- t0 = Mpy_32_16(hi, lo, isp[m - 1]);
- f1[i] = vo_L_add(f1[i], t0);
+ t0 = Mpy_32_16(hi, lo, isp[m - 1]);
+ f1[i] = vo_L_add(f1[i], t0);
- /* f2[i] *= (1.0 - isp[M-1]); */
+ /* f2[i] *= (1.0 - isp[M-1]); */
- hi = f2[i] >> 16;
- lo = (f2[i] & 0xffff)>>1;
- t0 = Mpy_32_16(hi, lo, isp[m - 1]);
- f2[i] = vo_L_sub(f2[i], t0);
- }
+ hi = f2[i] >> 16;
+ lo = (f2[i] & 0xffff)>>1;
+ t0 = Mpy_32_16(hi, lo, isp[m - 1]);
+ f2[i] = vo_L_sub(f2[i], t0);
+ }
- /*-----------------------------------------------------*
- * A(z) = (F1(z)+F2(z))/2 *
- * F1(z) is symmetric and F2(z) is antisymmetric *
- *-----------------------------------------------------*/
+ /*-----------------------------------------------------*
+ * A(z) = (F1(z)+F2(z))/2 *
+ * F1(z) is symmetric and F2(z) is antisymmetric *
+ *-----------------------------------------------------*/
- /* a[0] = 1.0; */
- a[0] = 4096;
- tmax = 1;
- for (i = 1, j = m - 1; i < nc; i++, j--)
- {
- /* a[i] = 0.5*(f1[i] + f2[i]); */
+ /* a[0] = 1.0; */
+ a[0] = 4096;
+ tmax = 1;
+ for (i = 1, j = m - 1; i < nc; i++, j--)
+ {
+ /* a[i] = 0.5*(f1[i] + f2[i]); */
- t0 = vo_L_add(f1[i], f2[i]); /* f1[i] + f2[i] */
- tmax |= L_abs(t0);
- a[i] = (Word16)(vo_L_shr_r(t0, 12)); /* from Q23 to Q12 and * 0.5 */
+ t0 = vo_L_add(f1[i], f2[i]); /* f1[i] + f2[i] */
+ tmax |= L_abs(t0);
+ a[i] = (Word16)(vo_L_shr_r(t0, 12)); /* from Q23 to Q12 and * 0.5 */
- /* a[j] = 0.5*(f1[i] - f2[i]); */
+ /* a[j] = 0.5*(f1[i] - f2[i]); */
- t0 = vo_L_sub(f1[i], f2[i]); /* f1[i] - f2[i] */
- tmax |= L_abs(t0);
- a[j] = (Word16)(vo_L_shr_r(t0, 12)); /* from Q23 to Q12 and * 0.5 */
- }
+ t0 = vo_L_sub(f1[i], f2[i]); /* f1[i] - f2[i] */
+ tmax |= L_abs(t0);
+ a[j] = (Word16)(vo_L_shr_r(t0, 12)); /* from Q23 to Q12 and * 0.5 */
+ }
- /* rescale data if overflow has occured and reprocess the loop */
- if(adaptive_scaling == 1)
- q = 4 - norm_l(tmax); /* adaptive scaling enabled */
- else
- q = 0; /* adaptive scaling disabled */
+ /* rescale data if overflow has occured and reprocess the loop */
+ if(adaptive_scaling == 1)
+ q = 4 - norm_l(tmax); /* adaptive scaling enabled */
+ else
+ q = 0; /* adaptive scaling disabled */
- if (q > 0)
- {
- q_sug = (12 + q);
- for (i = 1, j = m - 1; i < nc; i++, j--)
- {
- /* a[i] = 0.5*(f1[i] + f2[i]); */
- t0 = vo_L_add(f1[i], f2[i]); /* f1[i] + f2[i] */
- a[i] = (Word16)(vo_L_shr_r(t0, q_sug)); /* from Q23 to Q12 and * 0.5 */
+ if (q > 0)
+ {
+ q_sug = (12 + q);
+ for (i = 1, j = m - 1; i < nc; i++, j--)
+ {
+ /* a[i] = 0.5*(f1[i] + f2[i]); */
+ t0 = vo_L_add(f1[i], f2[i]); /* f1[i] + f2[i] */
+ a[i] = (Word16)(vo_L_shr_r(t0, q_sug)); /* from Q23 to Q12 and * 0.5 */
- /* a[j] = 0.5*(f1[i] - f2[i]); */
- t0 = vo_L_sub(f1[i], f2[i]); /* f1[i] - f2[i] */
- a[j] = (Word16)(vo_L_shr_r(t0, q_sug)); /* from Q23 to Q12 and * 0.5 */
- }
- a[0] = shr(a[0], q);
- }
- else
- {
- q_sug = 12;
- q = 0;
- }
- /* a[NC] = 0.5*f1[NC]*(1.0 + isp[M-1]); */
- hi = f1[nc] >> 16;
- lo = (f1[nc] & 0xffff)>>1;
- t0 = Mpy_32_16(hi, lo, isp[m - 1]);
- t0 = vo_L_add(f1[nc], t0);
- a[nc] = (Word16)(L_shr_r(t0, q_sug)); /* from Q23 to Q12 and * 0.5 */
- /* a[m] = isp[m-1]; */
+ /* a[j] = 0.5*(f1[i] - f2[i]); */
+ t0 = vo_L_sub(f1[i], f2[i]); /* f1[i] - f2[i] */
+ a[j] = (Word16)(vo_L_shr_r(t0, q_sug)); /* from Q23 to Q12 and * 0.5 */
+ }
+ a[0] = shr(a[0], q);
+ }
+ else
+ {
+ q_sug = 12;
+ q = 0;
+ }
+ /* a[NC] = 0.5*f1[NC]*(1.0 + isp[M-1]); */
+ hi = f1[nc] >> 16;
+ lo = (f1[nc] & 0xffff)>>1;
+ t0 = Mpy_32_16(hi, lo, isp[m - 1]);
+ t0 = vo_L_add(f1[nc], t0);
+ a[nc] = (Word16)(L_shr_r(t0, q_sug)); /* from Q23 to Q12 and * 0.5 */
+ /* a[m] = isp[m-1]; */
- a[m] = vo_shr_r(isp[m - 1], (3 + q)); /* from Q15 to Q12 */
- return;
+ a[m] = vo_shr_r(isp[m - 1], (3 + q)); /* from Q15 to Q12 */
+ return;
}
/*-----------------------------------------------------------*
@@ -185,63 +185,63 @@
static void Get_isp_pol(Word16 * isp, Word32 * f, Word16 n)
{
- Word16 hi, lo;
- Word32 i, j, t0;
- /* All computation in Q23 */
+ Word16 hi, lo;
+ Word32 i, j, t0;
+ /* All computation in Q23 */
- f[0] = vo_L_mult(4096, 1024); /* f[0] = 1.0; in Q23 */
- f[1] = vo_L_mult(isp[0], -256); /* f[1] = -2.0*isp[0] in Q23 */
+ f[0] = vo_L_mult(4096, 1024); /* f[0] = 1.0; in Q23 */
+ f[1] = vo_L_mult(isp[0], -256); /* f[1] = -2.0*isp[0] in Q23 */
- f += 2; /* Advance f pointer */
- isp += 2; /* Advance isp pointer */
- for (i = 2; i <= n; i++)
- {
- *f = f[-2];
- for (j = 1; j < i; j++, f--)
- {
- hi = f[-1]>>16;
- lo = (f[-1] & 0xffff)>>1;
+ f += 2; /* Advance f pointer */
+ isp += 2; /* Advance isp pointer */
+ for (i = 2; i <= n; i++)
+ {
+ *f = f[-2];
+ for (j = 1; j < i; j++, f--)
+ {
+ hi = f[-1]>>16;
+ lo = (f[-1] & 0xffff)>>1;
- t0 = Mpy_32_16(hi, lo, *isp); /* t0 = f[-1] * isp */
- t0 = t0 << 1;
- *f = vo_L_sub(*f, t0); /* *f -= t0 */
- *f = vo_L_add(*f, f[-2]); /* *f += f[-2] */
- }
- *f -= (*isp << 9); /* *f -= isp<<8 */
- f += i; /* Advance f pointer */
- isp += 2; /* Advance isp pointer */
- }
- return;
+ t0 = Mpy_32_16(hi, lo, *isp); /* t0 = f[-1] * isp */
+ t0 = t0 << 1;
+ *f = vo_L_sub(*f, t0); /* *f -= t0 */
+ *f = vo_L_add(*f, f[-2]); /* *f += f[-2] */
+ }
+ *f -= (*isp << 9); /* *f -= isp<<8 */
+ f += i; /* Advance f pointer */
+ isp += 2; /* Advance isp pointer */
+ }
+ return;
}
static void Get_isp_pol_16kHz(Word16 * isp, Word32 * f, Word16 n)
{
- Word16 hi, lo;
- Word32 i, j, t0;
+ Word16 hi, lo;
+ Word32 i, j, t0;
- /* All computation in Q23 */
- f[0] = L_mult(4096, 256); /* f[0] = 1.0; in Q23 */
- f[1] = L_mult(isp[0], -64); /* f[1] = -2.0*isp[0] in Q23 */
+ /* All computation in Q23 */
+ f[0] = L_mult(4096, 256); /* f[0] = 1.0; in Q23 */
+ f[1] = L_mult(isp[0], -64); /* f[1] = -2.0*isp[0] in Q23 */
- f += 2; /* Advance f pointer */
- isp += 2; /* Advance isp pointer */
+ f += 2; /* Advance f pointer */
+ isp += 2; /* Advance isp pointer */
- for (i = 2; i <= n; i++)
- {
- *f = f[-2];
- for (j = 1; j < i; j++, f--)
- {
- VO_L_Extract(f[-1], &hi, &lo);
- t0 = Mpy_32_16(hi, lo, *isp); /* t0 = f[-1] * isp */
- t0 = L_shl2(t0, 1);
- *f = L_sub(*f, t0); /* *f -= t0 */
- *f = L_add(*f, f[-2]); /* *f += f[-2] */
- }
- *f = L_msu(*f, *isp, 64); /* *f -= isp<<8 */
- f += i; /* Advance f pointer */
- isp += 2; /* Advance isp pointer */
- }
- return;
+ for (i = 2; i <= n; i++)
+ {
+ *f = f[-2];
+ for (j = 1; j < i; j++, f--)
+ {
+ VO_L_Extract(f[-1], &hi, &lo);
+ t0 = Mpy_32_16(hi, lo, *isp); /* t0 = f[-1] * isp */
+ t0 = L_shl2(t0, 1);
+ *f = L_sub(*f, t0); /* *f -= t0 */
+ *f = L_add(*f, f[-2]); /* *f += f[-2] */
+ }
+ *f = L_msu(*f, *isp, 64); /* *f -= isp<<8 */
+ f += i; /* Advance f pointer */
+ isp += 2; /* Advance isp pointer */
+ }
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/isp_isf.c b/media/libstagefright/codecs/amrwbenc/src/isp_isf.c
index b4ba408..56798e0 100644
--- a/media/libstagefright/codecs/amrwbenc/src/isp_isf.c
+++ b/media/libstagefright/codecs/amrwbenc/src/isp_isf.c
@@ -18,11 +18,11 @@
* File: isp_isf.c *
* *
* Description: *
-* Isp_isf Transformation isp to isf *
-* Isf_isp Transformation isf to isp *
+* Isp_isf Transformation isp to isf *
+* Isf_isp Transformation isf to isp *
* *
-* The transformation from isp[i] to isf[i] and isf[i] to isp[i] *
-* are approximated by a look-up table and interpolation *
+* The transformation from isp[i] to isf[i] and isf[i] to isp[i] *
+* are approximated by a look-up table and interpolation *
* *
************************************************************************/
@@ -31,59 +31,59 @@
#include "isp_isf.tab" /* Look-up table for transformations */
void Isp_isf(
- Word16 isp[], /* (i) Q15 : isp[m] (range: -1<=val<1) */
- Word16 isf[], /* (o) Q15 : isf[m] normalized (range: 0.0<=val<=0.5) */
- Word16 m /* (i) : LPC order */
- )
+ Word16 isp[], /* (i) Q15 : isp[m] (range: -1<=val<1) */
+ Word16 isf[], /* (o) Q15 : isf[m] normalized (range: 0.0<=val<=0.5) */
+ Word16 m /* (i) : LPC order */
+ )
{
- Word32 i, ind;
- Word32 L_tmp;
- ind = 127; /* beging at end of table -1 */
- for (i = (m - 1); i >= 0; i--)
- {
- if (i >= (m - 2))
- { /* m-2 is a constant */
- ind = 127; /* beging at end of table -1 */
- }
- /* find value in table that is just greater than isp[i] */
- while (table[ind] < isp[i])
- ind--;
- /* acos(isp[i])= ind*128 + ( ( isp[i]-table[ind] ) * slope[ind] )/2048 */
- L_tmp = vo_L_mult(vo_sub(isp[i], table[ind]), slope[ind]);
- isf[i] = vo_round((L_tmp << 4)); /* (isp[i]-table[ind])*slope[ind])>>11 */
- isf[i] = add1(isf[i], (ind << 7));
- }
- isf[m - 1] = (isf[m - 1] >> 1);
- return;
+ Word32 i, ind;
+ Word32 L_tmp;
+ ind = 127; /* beging at end of table -1 */
+ for (i = (m - 1); i >= 0; i--)
+ {
+ if (i >= (m - 2))
+ { /* m-2 is a constant */
+ ind = 127; /* beging at end of table -1 */
+ }
+ /* find value in table that is just greater than isp[i] */
+ while (table[ind] < isp[i])
+ ind--;
+ /* acos(isp[i])= ind*128 + ( ( isp[i]-table[ind] ) * slope[ind] )/2048 */
+ L_tmp = vo_L_mult(vo_sub(isp[i], table[ind]), slope[ind]);
+ isf[i] = vo_round((L_tmp << 4)); /* (isp[i]-table[ind])*slope[ind])>>11 */
+ isf[i] = add1(isf[i], (ind << 7));
+ }
+ isf[m - 1] = (isf[m - 1] >> 1);
+ return;
}
void Isf_isp(
- Word16 isf[], /* (i) Q15 : isf[m] normalized (range: 0.0<=val<=0.5) */
- Word16 isp[], /* (o) Q15 : isp[m] (range: -1<=val<1) */
- Word16 m /* (i) : LPC order */
- )
+ Word16 isf[], /* (i) Q15 : isf[m] normalized (range: 0.0<=val<=0.5) */
+ Word16 isp[], /* (o) Q15 : isp[m] (range: -1<=val<1) */
+ Word16 m /* (i) : LPC order */
+ )
{
- Word16 offset;
- Word32 i, ind, L_tmp;
+ Word16 offset;
+ Word32 i, ind, L_tmp;
- for (i = 0; i < m - 1; i++)
- {
- isp[i] = isf[i];
- }
- isp[m - 1] = (isf[m - 1] << 1);
+ for (i = 0; i < m - 1; i++)
+ {
+ isp[i] = isf[i];
+ }
+ isp[m - 1] = (isf[m - 1] << 1);
- for (i = 0; i < m; i++)
- {
- ind = (isp[i] >> 7); /* ind = b7-b15 of isf[i] */
- offset = (Word16) (isp[i] & 0x007f); /* offset = b0-b6 of isf[i] */
+ for (i = 0; i < m; i++)
+ {
+ ind = (isp[i] >> 7); /* ind = b7-b15 of isf[i] */
+ offset = (Word16) (isp[i] & 0x007f); /* offset = b0-b6 of isf[i] */
- /* isp[i] = table[ind]+ ((table[ind+1]-table[ind])*offset) / 128 */
- L_tmp = vo_L_mult(vo_sub(table[ind + 1], table[ind]), offset);
- isp[i] = add1(table[ind], (Word16)((L_tmp >> 8)));
- }
+ /* isp[i] = table[ind]+ ((table[ind+1]-table[ind])*offset) / 128 */
+ L_tmp = vo_L_mult(vo_sub(table[ind + 1], table[ind]), offset);
+ isp[i] = add1(table[ind], (Word16)((L_tmp >> 8)));
+ }
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/lag_wind.c b/media/libstagefright/codecs/amrwbenc/src/lag_wind.c
index 49c622c..527430b 100644
--- a/media/libstagefright/codecs/amrwbenc/src/lag_wind.c
+++ b/media/libstagefright/codecs/amrwbenc/src/lag_wind.c
@@ -17,8 +17,8 @@
/***********************************************************************
* File: lag_wind.c *
* *
-* Description: Lag_windows on autocorrelations *
-* r[i] *= lag_wind[i] *
+* Description: Lag_windows on autocorrelations *
+* r[i] *= lag_wind[i] *
* *
************************************************************************/
@@ -29,20 +29,20 @@
void Lag_window(
- Word16 r_h[], /* (i/o) : Autocorrelations (msb) */
- Word16 r_l[] /* (i/o) : Autocorrelations (lsb) */
- )
+ Word16 r_h[], /* (i/o) : Autocorrelations (msb) */
+ Word16 r_l[] /* (i/o) : Autocorrelations (lsb) */
+ )
{
- Word32 i;
- Word32 x;
+ Word32 i;
+ Word32 x;
- for (i = 1; i <= M; i++)
- {
- x = Mpy_32(r_h[i], r_l[i], volag_h[i - 1], volag_l[i - 1]);
- r_h[i] = x >> 16;
- r_l[i] = (x & 0xffff)>>1;
- }
- return;
+ for (i = 1; i <= M; i++)
+ {
+ x = Mpy_32(r_h[i], r_l[i], volag_h[i - 1], volag_l[i - 1]);
+ r_h[i] = x >> 16;
+ r_l[i] = (x & 0xffff)>>1;
+ }
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/levinson.c b/media/libstagefright/codecs/amrwbenc/src/levinson.c
index 4b2f8ed..9d5a3bd 100644
--- a/media/libstagefright/codecs/amrwbenc/src/levinson.c
+++ b/media/libstagefright/codecs/amrwbenc/src/levinson.c
@@ -21,7 +21,7 @@
* *
************************************************************************/
/*---------------------------------------------------------------------------*
- * LEVINSON.C *
+ * LEVINSON.C *
*---------------------------------------------------------------------------*
* *
* LEVINSON-DURBIN algorithm in double precision *
@@ -96,154 +96,154 @@
#define NC (M/2)
void Init_Levinson(
- Word16 * mem /* output :static memory (18 words) */
- )
+ Word16 * mem /* output :static memory (18 words) */
+ )
{
- Set_zero(mem, 18); /* old_A[0..M-1] = 0, old_rc[0..1] = 0 */
- return;
+ Set_zero(mem, 18); /* old_A[0..M-1] = 0, old_rc[0..1] = 0 */
+ return;
}
void Levinson(
- Word16 Rh[], /* (i) : Rh[M+1] Vector of autocorrelations (msb) */
- Word16 Rl[], /* (i) : Rl[M+1] Vector of autocorrelations (lsb) */
- Word16 A[], /* (o) Q12 : A[M] LPC coefficients (m = 16) */
- Word16 rc[], /* (o) Q15 : rc[M] Reflection coefficients. */
- Word16 * mem /* (i/o) :static memory (18 words) */
- )
+ Word16 Rh[], /* (i) : Rh[M+1] Vector of autocorrelations (msb) */
+ Word16 Rl[], /* (i) : Rl[M+1] Vector of autocorrelations (lsb) */
+ Word16 A[], /* (o) Q12 : A[M] LPC coefficients (m = 16) */
+ Word16 rc[], /* (o) Q15 : rc[M] Reflection coefficients. */
+ Word16 * mem /* (i/o) :static memory (18 words) */
+ )
{
- Word32 i, j;
- Word16 hi, lo;
- Word16 Kh, Kl; /* reflection coefficient; hi and lo */
- Word16 alp_h, alp_l, alp_exp; /* Prediction gain; hi lo and exponent */
- Word16 Ah[M + 1], Al[M + 1]; /* LPC coef. in double prec. */
- Word16 Anh[M + 1], Anl[M + 1]; /* LPC coef.for next iteration in double prec. */
- Word32 t0, t1, t2; /* temporary variable */
- Word16 *old_A, *old_rc;
+ Word32 i, j;
+ Word16 hi, lo;
+ Word16 Kh, Kl; /* reflection coefficient; hi and lo */
+ Word16 alp_h, alp_l, alp_exp; /* Prediction gain; hi lo and exponent */
+ Word16 Ah[M + 1], Al[M + 1]; /* LPC coef. in double prec. */
+ Word16 Anh[M + 1], Anl[M + 1]; /* LPC coef.for next iteration in double prec. */
+ Word32 t0, t1, t2; /* temporary variable */
+ Word16 *old_A, *old_rc;
- /* Last A(z) for case of unstable filter */
- old_A = mem;
- old_rc = mem + M;
+ /* Last A(z) for case of unstable filter */
+ old_A = mem;
+ old_rc = mem + M;
- /* K = A[1] = -R[1] / R[0] */
+ /* K = A[1] = -R[1] / R[0] */
- t1 = ((Rh[1] << 16) + (Rl[1] << 1)); /* R[1] in Q31 */
- t2 = L_abs(t1); /* abs R[1] */
- t0 = Div_32(t2, Rh[0], Rl[0]); /* R[1]/R[0] in Q31 */
- if (t1 > 0)
- t0 = -t0; /* -R[1]/R[0] */
+ t1 = ((Rh[1] << 16) + (Rl[1] << 1)); /* R[1] in Q31 */
+ t2 = L_abs(t1); /* abs R[1] */
+ t0 = Div_32(t2, Rh[0], Rl[0]); /* R[1]/R[0] in Q31 */
+ if (t1 > 0)
+ t0 = -t0; /* -R[1]/R[0] */
- Kh = t0 >> 16;
- Kl = (t0 & 0xffff)>>1;
- rc[0] = Kh;
- t0 = (t0 >> 4); /* A[1] in Q27 */
+ Kh = t0 >> 16;
+ Kl = (t0 & 0xffff)>>1;
+ rc[0] = Kh;
+ t0 = (t0 >> 4); /* A[1] in Q27 */
- Ah[1] = t0 >> 16;
- Al[1] = (t0 & 0xffff)>>1;
+ Ah[1] = t0 >> 16;
+ Al[1] = (t0 & 0xffff)>>1;
- /* Alpha = R[0] * (1-K**2) */
- t0 = Mpy_32(Kh, Kl, Kh, Kl); /* K*K in Q31 */
- t0 = L_abs(t0); /* Some case <0 !! */
- t0 = vo_L_sub((Word32) 0x7fffffffL, t0); /* 1 - K*K in Q31 */
+ /* Alpha = R[0] * (1-K**2) */
+ t0 = Mpy_32(Kh, Kl, Kh, Kl); /* K*K in Q31 */
+ t0 = L_abs(t0); /* Some case <0 !! */
+ t0 = vo_L_sub((Word32) 0x7fffffffL, t0); /* 1 - K*K in Q31 */
- hi = t0 >> 16;
- lo = (t0 & 0xffff)>>1;
+ hi = t0 >> 16;
+ lo = (t0 & 0xffff)>>1;
- t0 = Mpy_32(Rh[0], Rl[0], hi, lo); /* Alpha in Q31 */
+ t0 = Mpy_32(Rh[0], Rl[0], hi, lo); /* Alpha in Q31 */
- /* Normalize Alpha */
- alp_exp = norm_l(t0);
- t0 = (t0 << alp_exp);
+ /* Normalize Alpha */
+ alp_exp = norm_l(t0);
+ t0 = (t0 << alp_exp);
- alp_h = t0 >> 16;
- alp_l = (t0 & 0xffff)>>1;
- /*--------------------------------------*
- * ITERATIONS I=2 to M *
- *--------------------------------------*/
- for (i = 2; i <= M; i++)
- {
- /* t0 = SUM ( R[j]*A[i-j] ,j=1,i-1 ) + R[i] */
- t0 = 0;
- for (j = 1; j < i; j++)
- t0 = vo_L_add(t0, Mpy_32(Rh[j], Rl[j], Ah[i - j], Al[i - j]));
+ alp_h = t0 >> 16;
+ alp_l = (t0 & 0xffff)>>1;
+ /*--------------------------------------*
+ * ITERATIONS I=2 to M *
+ *--------------------------------------*/
+ for (i = 2; i <= M; i++)
+ {
+ /* t0 = SUM ( R[j]*A[i-j] ,j=1,i-1 ) + R[i] */
+ t0 = 0;
+ for (j = 1; j < i; j++)
+ t0 = vo_L_add(t0, Mpy_32(Rh[j], Rl[j], Ah[i - j], Al[i - j]));
- t0 = t0 << 4; /* result in Q27 -> convert to Q31 */
- /* No overflow possible */
- t1 = ((Rh[i] << 16) + (Rl[i] << 1));
- t0 = vo_L_add(t0, t1); /* add R[i] in Q31 */
+ t0 = t0 << 4; /* result in Q27 -> convert to Q31 */
+ /* No overflow possible */
+ t1 = ((Rh[i] << 16) + (Rl[i] << 1));
+ t0 = vo_L_add(t0, t1); /* add R[i] in Q31 */
- /* K = -t0 / Alpha */
- t1 = L_abs(t0);
- t2 = Div_32(t1, alp_h, alp_l); /* abs(t0)/Alpha */
- if (t0 > 0)
- t2 = -t2; /* K =-t0/Alpha */
- t2 = (t2 << alp_exp); /* denormalize; compare to Alpha */
+ /* K = -t0 / Alpha */
+ t1 = L_abs(t0);
+ t2 = Div_32(t1, alp_h, alp_l); /* abs(t0)/Alpha */
+ if (t0 > 0)
+ t2 = -t2; /* K =-t0/Alpha */
+ t2 = (t2 << alp_exp); /* denormalize; compare to Alpha */
- Kh = t2 >> 16;
- Kl = (t2 & 0xffff)>>1;
+ Kh = t2 >> 16;
+ Kl = (t2 & 0xffff)>>1;
- rc[i - 1] = Kh;
- /* Test for unstable filter. If unstable keep old A(z) */
- if (abs_s(Kh) > 32750)
- {
- A[0] = 4096; /* Ai[0] not stored (always 1.0) */
- for (j = 0; j < M; j++)
- {
- A[j + 1] = old_A[j];
- }
- rc[0] = old_rc[0]; /* only two rc coefficients are needed */
- rc[1] = old_rc[1];
- return;
- }
- /*------------------------------------------*
- * Compute new LPC coeff. -> An[i] *
- * An[j]= A[j] + K*A[i-j] , j=1 to i-1 *
- * An[i]= K *
- *------------------------------------------*/
- for (j = 1; j < i; j++)
- {
- t0 = Mpy_32(Kh, Kl, Ah[i - j], Al[i - j]);
- t0 = vo_L_add(t0, ((Ah[j] << 16) + (Al[j] << 1)));
- Anh[j] = t0 >> 16;
- Anl[j] = (t0 & 0xffff)>>1;
- }
- t2 = (t2 >> 4); /* t2 = K in Q31 ->convert to Q27 */
+ rc[i - 1] = Kh;
+ /* Test for unstable filter. If unstable keep old A(z) */
+ if (abs_s(Kh) > 32750)
+ {
+ A[0] = 4096; /* Ai[0] not stored (always 1.0) */
+ for (j = 0; j < M; j++)
+ {
+ A[j + 1] = old_A[j];
+ }
+ rc[0] = old_rc[0]; /* only two rc coefficients are needed */
+ rc[1] = old_rc[1];
+ return;
+ }
+ /*------------------------------------------*
+ * Compute new LPC coeff. -> An[i] *
+ * An[j]= A[j] + K*A[i-j] , j=1 to i-1 *
+ * An[i]= K *
+ *------------------------------------------*/
+ for (j = 1; j < i; j++)
+ {
+ t0 = Mpy_32(Kh, Kl, Ah[i - j], Al[i - j]);
+ t0 = vo_L_add(t0, ((Ah[j] << 16) + (Al[j] << 1)));
+ Anh[j] = t0 >> 16;
+ Anl[j] = (t0 & 0xffff)>>1;
+ }
+ t2 = (t2 >> 4); /* t2 = K in Q31 ->convert to Q27 */
- VO_L_Extract(t2, &Anh[i], &Anl[i]); /* An[i] in Q27 */
+ VO_L_Extract(t2, &Anh[i], &Anl[i]); /* An[i] in Q27 */
- /* Alpha = Alpha * (1-K**2) */
- t0 = Mpy_32(Kh, Kl, Kh, Kl); /* K*K in Q31 */
- t0 = L_abs(t0); /* Some case <0 !! */
- t0 = vo_L_sub((Word32) 0x7fffffffL, t0); /* 1 - K*K in Q31 */
- hi = t0 >> 16;
- lo = (t0 & 0xffff)>>1;
- t0 = Mpy_32(alp_h, alp_l, hi, lo); /* Alpha in Q31 */
+ /* Alpha = Alpha * (1-K**2) */
+ t0 = Mpy_32(Kh, Kl, Kh, Kl); /* K*K in Q31 */
+ t0 = L_abs(t0); /* Some case <0 !! */
+ t0 = vo_L_sub((Word32) 0x7fffffffL, t0); /* 1 - K*K in Q31 */
+ hi = t0 >> 16;
+ lo = (t0 & 0xffff)>>1;
+ t0 = Mpy_32(alp_h, alp_l, hi, lo); /* Alpha in Q31 */
- /* Normalize Alpha */
- j = norm_l(t0);
- t0 = (t0 << j);
- alp_h = t0 >> 16;
- alp_l = (t0 & 0xffff)>>1;
- alp_exp += j; /* Add normalization to alp_exp */
+ /* Normalize Alpha */
+ j = norm_l(t0);
+ t0 = (t0 << j);
+ alp_h = t0 >> 16;
+ alp_l = (t0 & 0xffff)>>1;
+ alp_exp += j; /* Add normalization to alp_exp */
- /* A[j] = An[j] */
- for (j = 1; j <= i; j++)
- {
- Ah[j] = Anh[j];
- Al[j] = Anl[j];
- }
- }
- /* Truncate A[i] in Q27 to Q12 with rounding */
- A[0] = 4096;
- for (i = 1; i <= M; i++)
- {
- t0 = (Ah[i] << 16) + (Al[i] << 1);
- old_A[i - 1] = A[i] = vo_round((t0 << 1));
- }
- old_rc[0] = rc[0];
- old_rc[1] = rc[1];
+ /* A[j] = An[j] */
+ for (j = 1; j <= i; j++)
+ {
+ Ah[j] = Anh[j];
+ Al[j] = Anl[j];
+ }
+ }
+ /* Truncate A[i] in Q27 to Q12 with rounding */
+ A[0] = 4096;
+ for (i = 1; i <= M; i++)
+ {
+ t0 = (Ah[i] << 16) + (Al[i] << 1);
+ old_A[i - 1] = A[i] = vo_round((t0 << 1));
+ }
+ old_rc[0] = rc[0];
+ old_rc[1] = rc[1];
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/log2.c b/media/libstagefright/codecs/amrwbenc/src/log2.c
index 0f65541..f14058e 100644
--- a/media/libstagefright/codecs/amrwbenc/src/log2.c
+++ b/media/libstagefright/codecs/amrwbenc/src/log2.c
@@ -54,33 +54,33 @@
*************************************************************************/
void Log2_norm (
- Word32 L_x, /* (i) : input value (normalized) */
- Word16 exp, /* (i) : norm_l (L_x) */
- Word16 *exponent, /* (o) : Integer part of Log2. (range: 0<=val<=30) */
- Word16 *fraction /* (o) : Fractional part of Log2. (range: 0<=val<1) */
- )
+ Word32 L_x, /* (i) : input value (normalized) */
+ Word16 exp, /* (i) : norm_l (L_x) */
+ Word16 *exponent, /* (o) : Integer part of Log2. (range: 0<=val<=30) */
+ Word16 *fraction /* (o) : Fractional part of Log2. (range: 0<=val<1) */
+ )
{
- Word16 i, a, tmp;
- Word32 L_y;
- if (L_x <= (Word32) 0)
- {
- *exponent = 0;
- *fraction = 0;
- return;
- }
- *exponent = (30 - exp);
- L_x = (L_x >> 9);
- i = extract_h (L_x); /* Extract b25-b31 */
- L_x = (L_x >> 1);
- a = (Word16)(L_x); /* Extract b10-b24 of fraction */
- a = (Word16)(a & (Word16)0x7fff);
- i -= 32;
- L_y = L_deposit_h (table[i]); /* table[i] << 16 */
- tmp = vo_sub(table[i], table[i + 1]); /* table[i] - table[i+1] */
- L_y = vo_L_msu (L_y, tmp, a); /* L_y -= tmp*a*2 */
- *fraction = extract_h (L_y);
+ Word16 i, a, tmp;
+ Word32 L_y;
+ if (L_x <= (Word32) 0)
+ {
+ *exponent = 0;
+ *fraction = 0;
+ return;
+ }
+ *exponent = (30 - exp);
+ L_x = (L_x >> 9);
+ i = extract_h (L_x); /* Extract b25-b31 */
+ L_x = (L_x >> 1);
+ a = (Word16)(L_x); /* Extract b10-b24 of fraction */
+ a = (Word16)(a & (Word16)0x7fff);
+ i -= 32;
+ L_y = L_deposit_h (table[i]); /* table[i] << 16 */
+ tmp = vo_sub(table[i], table[i + 1]); /* table[i] - table[i+1] */
+ L_y = vo_L_msu (L_y, tmp, a); /* L_y -= tmp*a*2 */
+ *fraction = extract_h (L_y);
- return;
+ return;
}
/*************************************************************************
@@ -96,15 +96,15 @@
*************************************************************************/
void Log2 (
- Word32 L_x, /* (i) : input value */
- Word16 *exponent, /* (o) : Integer part of Log2. (range: 0<=val<=30) */
- Word16 *fraction /* (o) : Fractional part of Log2. (range: 0<=val<1) */
- )
+ Word32 L_x, /* (i) : input value */
+ Word16 *exponent, /* (o) : Integer part of Log2. (range: 0<=val<=30) */
+ Word16 *fraction /* (o) : Fractional part of Log2. (range: 0<=val<1) */
+ )
{
- Word16 exp;
+ Word16 exp;
- exp = norm_l(L_x);
- Log2_norm ((L_x << exp), exp, exponent, fraction);
+ exp = norm_l(L_x);
+ Log2_norm ((L_x << exp), exp, exponent, fraction);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/lp_dec2.c b/media/libstagefright/codecs/amrwbenc/src/lp_dec2.c
index 1d5d076..9a9dd34 100644
--- a/media/libstagefright/codecs/amrwbenc/src/lp_dec2.c
+++ b/media/libstagefright/codecs/amrwbenc/src/lp_dec2.c
@@ -17,7 +17,7 @@
/***********************************************************************
* File: lp_dec2.c *
* *
-* Description:Decimate a vector by 2 with 2nd order fir filter *
+* Description:Decimate a vector by 2 with 2nd order fir filter *
* *
************************************************************************/
@@ -33,36 +33,36 @@
static Word16 h_fir[L_FIR] = {4260, 7536, 9175, 7536, 4260};
void LP_Decim2(
- Word16 x[], /* in/out: signal to process */
- Word16 l, /* input : size of filtering */
- Word16 mem[] /* in/out: memory (size=3) */
- )
+ Word16 x[], /* in/out: signal to process */
+ Word16 l, /* input : size of filtering */
+ Word16 mem[] /* in/out: memory (size=3) */
+ )
{
- Word16 *p_x, x_buf[L_FRAME + L_MEM];
- Word32 i, j;
- Word32 L_tmp;
- /* copy initial filter states into buffer */
- p_x = x_buf;
- for (i = 0; i < L_MEM; i++)
- {
- *p_x++ = mem[i];
- mem[i] = x[l - L_MEM + i];
- }
- for (i = 0; i < l; i++)
- {
- *p_x++ = x[i];
- }
- for (i = 0, j = 0; i < l; i += 2, j++)
- {
- p_x = &x_buf[i];
- L_tmp = ((*p_x++) * h_fir[0]);
- L_tmp += ((*p_x++) * h_fir[1]);
- L_tmp += ((*p_x++) * h_fir[2]);
- L_tmp += ((*p_x++) * h_fir[3]);
- L_tmp += ((*p_x++) * h_fir[4]);
- x[j] = (L_tmp + 0x4000)>>15;
- }
- return;
+ Word16 *p_x, x_buf[L_FRAME + L_MEM];
+ Word32 i, j;
+ Word32 L_tmp;
+ /* copy initial filter states into buffer */
+ p_x = x_buf;
+ for (i = 0; i < L_MEM; i++)
+ {
+ *p_x++ = mem[i];
+ mem[i] = x[l - L_MEM + i];
+ }
+ for (i = 0; i < l; i++)
+ {
+ *p_x++ = x[i];
+ }
+ for (i = 0, j = 0; i < l; i += 2, j++)
+ {
+ p_x = &x_buf[i];
+ L_tmp = ((*p_x++) * h_fir[0]);
+ L_tmp += ((*p_x++) * h_fir[1]);
+ L_tmp += ((*p_x++) * h_fir[2]);
+ L_tmp += ((*p_x++) * h_fir[3]);
+ L_tmp += ((*p_x++) * h_fir[4]);
+ x[j] = (L_tmp + 0x4000)>>15;
+ }
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/math_op.c b/media/libstagefright/codecs/amrwbenc/src/math_op.c
index 7affbb2..9d7c74e 100644
--- a/media/libstagefright/codecs/amrwbenc/src/math_op.c
+++ b/media/libstagefright/codecs/amrwbenc/src/math_op.c
@@ -55,17 +55,17 @@
|___________________________________________________________________________|
*/
Word32 Isqrt( /* (o) Q31 : output value (range: 0<=val<1) */
- Word32 L_x /* (i) Q0 : input value (range: 0<=val<=7fffffff) */
- )
+ Word32 L_x /* (i) Q0 : input value (range: 0<=val<=7fffffff) */
+ )
{
- Word16 exp;
- Word32 L_y;
- exp = norm_l(L_x);
- L_x = (L_x << exp); /* L_x is normalized */
- exp = (31 - exp);
- Isqrt_n(&L_x, &exp);
- L_y = (L_x << exp); /* denormalization */
- return (L_y);
+ Word16 exp;
+ Word32 L_y;
+ exp = norm_l(L_x);
+ L_x = (L_x << exp); /* L_x is normalized */
+ exp = (31 - exp);
+ Isqrt_n(&L_x, &exp);
+ L_y = (L_x << exp); /* denormalization */
+ return (L_y);
}
/*___________________________________________________________________________
@@ -90,43 +90,43 @@
*/
static Word16 table_isqrt[49] =
{
- 32767, 31790, 30894, 30070, 29309, 28602, 27945, 27330, 26755, 26214,
- 25705, 25225, 24770, 24339, 23930, 23541, 23170, 22817, 22479, 22155,
- 21845, 21548, 21263, 20988, 20724, 20470, 20225, 19988, 19760, 19539,
- 19326, 19119, 18919, 18725, 18536, 18354, 18176, 18004, 17837, 17674,
- 17515, 17361, 17211, 17064, 16921, 16782, 16646, 16514, 16384
+ 32767, 31790, 30894, 30070, 29309, 28602, 27945, 27330, 26755, 26214,
+ 25705, 25225, 24770, 24339, 23930, 23541, 23170, 22817, 22479, 22155,
+ 21845, 21548, 21263, 20988, 20724, 20470, 20225, 19988, 19760, 19539,
+ 19326, 19119, 18919, 18725, 18536, 18354, 18176, 18004, 17837, 17674,
+ 17515, 17361, 17211, 17064, 16921, 16782, 16646, 16514, 16384
};
void Isqrt_n(
- Word32 * frac, /* (i/o) Q31: normalized value (1.0 < frac <= 0.5) */
- Word16 * exp /* (i/o) : exponent (value = frac x 2^exponent) */
- )
+ Word32 * frac, /* (i/o) Q31: normalized value (1.0 < frac <= 0.5) */
+ Word16 * exp /* (i/o) : exponent (value = frac x 2^exponent) */
+ )
{
- Word16 i, a, tmp;
+ Word16 i, a, tmp;
- if (*frac <= (Word32) 0)
- {
- *exp = 0;
- *frac = 0x7fffffffL;
- return;
- }
+ if (*frac <= (Word32) 0)
+ {
+ *exp = 0;
+ *frac = 0x7fffffffL;
+ return;
+ }
- if((*exp & 1) == 1) /*If exponant odd -> shift right */
- *frac = (*frac) >> 1;
+ if((*exp & 1) == 1) /*If exponant odd -> shift right */
+ *frac = (*frac) >> 1;
- *exp = negate((*exp - 1) >> 1);
+ *exp = negate((*exp - 1) >> 1);
- *frac = (*frac >> 9);
- i = extract_h(*frac); /* Extract b25-b31 */
- *frac = (*frac >> 1);
- a = (Word16)(*frac); /* Extract b10-b24 */
- a = (Word16) (a & (Word16) 0x7fff);
- i -= 16;
- *frac = L_deposit_h(table_isqrt[i]); /* table[i] << 16 */
- tmp = vo_sub(table_isqrt[i], table_isqrt[i + 1]); /* table[i] - table[i+1]) */
- *frac = vo_L_msu(*frac, tmp, a); /* frac -= tmp*a*2 */
+ *frac = (*frac >> 9);
+ i = extract_h(*frac); /* Extract b25-b31 */
+ *frac = (*frac >> 1);
+ a = (Word16)(*frac); /* Extract b10-b24 */
+ a = (Word16) (a & (Word16) 0x7fff);
+ i -= 16;
+ *frac = L_deposit_h(table_isqrt[i]); /* table[i] << 16 */
+ tmp = vo_sub(table_isqrt[i], table_isqrt[i + 1]); /* table[i] - table[i+1]) */
+ *frac = vo_L_msu(*frac, tmp, a); /* frac -= tmp*a*2 */
- return;
+ return;
}
/*___________________________________________________________________________
@@ -149,34 +149,34 @@
*/
static Word16 table_pow2[33] =
{
- 16384, 16743, 17109, 17484, 17867, 18258, 18658, 19066, 19484, 19911,
- 20347, 20792, 21247, 21713, 22188, 22674, 23170, 23678, 24196, 24726,
- 25268, 25821, 26386, 26964, 27554, 28158, 28774, 29405, 30048, 30706,
- 31379, 32066, 32767
+ 16384, 16743, 17109, 17484, 17867, 18258, 18658, 19066, 19484, 19911,
+ 20347, 20792, 21247, 21713, 22188, 22674, 23170, 23678, 24196, 24726,
+ 25268, 25821, 26386, 26964, 27554, 28158, 28774, 29405, 30048, 30706,
+ 31379, 32066, 32767
};
Word32 Pow2( /* (o) Q0 : result (range: 0<=val<=0x7fffffff) */
- Word16 exponant, /* (i) Q0 : Integer part. (range: 0<=val<=30) */
- Word16 fraction /* (i) Q15 : Fractionnal part. (range: 0.0<=val<1.0) */
- )
+ Word16 exponant, /* (i) Q0 : Integer part. (range: 0<=val<=30) */
+ Word16 fraction /* (i) Q15 : Fractionnal part. (range: 0.0<=val<1.0) */
+ )
{
- Word16 exp, i, a, tmp;
- Word32 L_x;
+ Word16 exp, i, a, tmp;
+ Word32 L_x;
- L_x = vo_L_mult(fraction, 32); /* L_x = fraction<<6 */
- i = extract_h(L_x); /* Extract b10-b16 of fraction */
- L_x =L_x >> 1;
- a = (Word16)(L_x); /* Extract b0-b9 of fraction */
- a = (Word16) (a & (Word16) 0x7fff);
+ L_x = vo_L_mult(fraction, 32); /* L_x = fraction<<6 */
+ i = extract_h(L_x); /* Extract b10-b16 of fraction */
+ L_x =L_x >> 1;
+ a = (Word16)(L_x); /* Extract b0-b9 of fraction */
+ a = (Word16) (a & (Word16) 0x7fff);
- L_x = L_deposit_h(table_pow2[i]); /* table[i] << 16 */
- tmp = vo_sub(table_pow2[i], table_pow2[i + 1]); /* table[i] - table[i+1] */
- L_x -= (tmp * a)<<1; /* L_x -= tmp*a*2 */
+ L_x = L_deposit_h(table_pow2[i]); /* table[i] << 16 */
+ tmp = vo_sub(table_pow2[i], table_pow2[i + 1]); /* table[i] - table[i+1] */
+ L_x -= (tmp * a)<<1; /* L_x -= tmp*a*2 */
- exp = vo_sub(30, exponant);
- L_x = vo_L_shr_r(L_x, exp);
+ exp = vo_sub(30, exponant);
+ L_x = vo_L_shr_r(L_x, exp);
- return (L_x);
+ return (L_x);
}
/*___________________________________________________________________________
@@ -194,25 +194,30 @@
*/
Word32 Dot_product12( /* (o) Q31: normalized result (1 < val <= -1) */
- Word16 x[], /* (i) 12bits: x vector */
- Word16 y[], /* (i) 12bits: y vector */
- Word16 lg, /* (i) : vector length */
- Word16 * exp /* (o) : exponent of result (0..+30) */
- )
+ Word16 x[], /* (i) 12bits: x vector */
+ Word16 y[], /* (i) 12bits: y vector */
+ Word16 lg, /* (i) : vector length */
+ Word16 * exp /* (o) : exponent of result (0..+30) */
+ )
{
- Word16 sft;
- Word32 i, L_sum;
- L_sum = 0;
- for (i = 0; i < lg; i++)
- {
- L_sum += x[i] * y[i];
- }
- L_sum = (L_sum << 1) + 1;
- /* Normalize acc in Q31 */
- sft = norm_l(L_sum);
- L_sum = L_sum << sft;
- *exp = 30 - sft; /* exponent = 0..30 */
- return (L_sum);
+ Word16 sft;
+ Word32 i, L_sum;
+ L_sum = 0;
+ for (i = 0; i < lg; i++)
+ {
+ Word32 tmp = (Word32) x[i] * (Word32) y[i];
+ if (tmp == (Word32) 0x40000000L) {
+ tmp = MAX_32;
+ }
+ L_sum = L_add(L_sum, tmp);
+ }
+ L_sum = L_shl2(L_sum, 1);
+ L_sum = L_add(L_sum, 1);
+ /* Normalize acc in Q31 */
+ sft = norm_l(L_sum);
+ L_sum = L_sum << sft;
+ *exp = 30 - sft; /* exponent = 0..30 */
+ return (L_sum);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/mem_align.c b/media/libstagefright/codecs/amrwbenc/src/mem_align.c
index 3b7853f..04e5976 100644
--- a/media/libstagefright/codecs/amrwbenc/src/mem_align.c
+++ b/media/libstagefright/codecs/amrwbenc/src/mem_align.c
@@ -15,18 +15,18 @@
*/
/*******************************************************************************
- File: mem_align.c
+ File: mem_align.c
- Content: Memory alloc alignments functions
+ Content: Memory alloc alignments functions
*******************************************************************************/
-#include "mem_align.h"
+#include "mem_align.h"
#ifdef _MSC_VER
-#include <stddef.h>
+#include <stddef.h>
#else
-#include <stdint.h>
+#include <stdint.h>
#endif
/*****************************************************************************
@@ -39,50 +39,50 @@
void *
mem_malloc(VO_MEM_OPERATOR *pMemop, unsigned int size, unsigned char alignment, unsigned int CodecID)
{
- int ret;
- unsigned char *mem_ptr;
- VO_MEM_INFO MemInfo;
+ int ret;
+ unsigned char *mem_ptr;
+ VO_MEM_INFO MemInfo;
- if (!alignment) {
+ if (!alignment) {
- MemInfo.Flag = 0;
- MemInfo.Size = size + 1;
- ret = pMemop->Alloc(CodecID, &MemInfo);
- if(ret != 0)
- return 0;
- mem_ptr = (unsigned char *)MemInfo.VBuffer;
+ MemInfo.Flag = 0;
+ MemInfo.Size = size + 1;
+ ret = pMemop->Alloc(CodecID, &MemInfo);
+ if(ret != 0)
+ return 0;
+ mem_ptr = (unsigned char *)MemInfo.VBuffer;
- pMemop->Set(CodecID, mem_ptr, 0, size + 1);
+ pMemop->Set(CodecID, mem_ptr, 0, size + 1);
- *mem_ptr = (unsigned char)1;
+ *mem_ptr = (unsigned char)1;
- return ((void *)(mem_ptr+1));
- } else {
- unsigned char *tmp;
+ return ((void *)(mem_ptr+1));
+ } else {
+ unsigned char *tmp;
- MemInfo.Flag = 0;
- MemInfo.Size = size + alignment;
- ret = pMemop->Alloc(CodecID, &MemInfo);
- if(ret != 0)
- return 0;
+ MemInfo.Flag = 0;
+ MemInfo.Size = size + alignment;
+ ret = pMemop->Alloc(CodecID, &MemInfo);
+ if(ret != 0)
+ return 0;
- tmp = (unsigned char *)MemInfo.VBuffer;
+ tmp = (unsigned char *)MemInfo.VBuffer;
- pMemop->Set(CodecID, tmp, 0, size + alignment);
+ pMemop->Set(CodecID, tmp, 0, size + alignment);
- mem_ptr =
- (unsigned char *) ((intptr_t) (tmp + alignment - 1) &
- (~((intptr_t) (alignment - 1))));
+ mem_ptr =
+ (unsigned char *) ((intptr_t) (tmp + alignment - 1) &
+ (~((intptr_t) (alignment - 1))));
- if (mem_ptr == tmp)
- mem_ptr += alignment;
+ if (mem_ptr == tmp)
+ mem_ptr += alignment;
- *(mem_ptr - 1) = (unsigned char) (mem_ptr - tmp);
+ *(mem_ptr - 1) = (unsigned char) (mem_ptr - tmp);
- return ((void *)mem_ptr);
- }
+ return ((void *)mem_ptr);
+ }
- return(0);
+ return(0);
}
@@ -96,16 +96,16 @@
mem_free(VO_MEM_OPERATOR *pMemop, void *mem_ptr, unsigned int CodecID)
{
- unsigned char *ptr;
+ unsigned char *ptr;
- if (mem_ptr == 0)
- return;
+ if (mem_ptr == 0)
+ return;
- ptr = mem_ptr;
+ ptr = mem_ptr;
- ptr -= *(ptr - 1);
+ ptr -= *(ptr - 1);
- pMemop->Free(CodecID, ptr);
+ pMemop->Free(CodecID, ptr);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/oper_32b.c b/media/libstagefright/codecs/amrwbenc/src/oper_32b.c
index 27cad76..e6f80d0 100644
--- a/media/libstagefright/codecs/amrwbenc/src/oper_32b.c
+++ b/media/libstagefright/codecs/amrwbenc/src/oper_32b.c
@@ -56,9 +56,9 @@
__inline void VO_L_Extract (Word32 L_32, Word16 *hi, Word16 *lo)
{
- *hi = (Word16)(L_32 >> 16);
- *lo = (Word16)((L_32 & 0xffff) >> 1);
- return;
+ *hi = (Word16)(L_32 >> 16);
+ *lo = (Word16)((L_32 & 0xffff) >> 1);
+ return;
}
/*****************************************************************************
@@ -84,11 +84,11 @@
Word32 L_Comp (Word16 hi, Word16 lo)
{
- Word32 L_32;
+ Word32 L_32;
- L_32 = L_deposit_h (hi);
+ L_32 = L_deposit_h (hi);
- return (L_mac (L_32, lo, 1)); /* = hi<<16 + lo<<1 */
+ return (L_mac (L_32, lo, 1)); /* = hi<<16 + lo<<1 */
}
/*****************************************************************************
@@ -113,13 +113,13 @@
__inline Word32 Mpy_32 (Word16 hi1, Word16 lo1, Word16 hi2, Word16 lo2)
{
- Word32 L_32;
- L_32 = (hi1 * hi2);
- L_32 += (hi1 * lo2) >> 15;
- L_32 += (lo1 * hi2) >> 15;
- L_32 <<= 1;
+ Word32 L_32;
+ L_32 = (hi1 * hi2);
+ L_32 += (hi1 * lo2) >> 15;
+ L_32 += (lo1 * hi2) >> 15;
+ L_32 <<= 1;
- return (L_32);
+ return (L_32);
}
/*****************************************************************************
@@ -142,12 +142,12 @@
__inline Word32 Mpy_32_16 (Word16 hi, Word16 lo, Word16 n)
{
- Word32 L_32;
+ Word32 L_32;
- L_32 = (hi * n)<<1;
- L_32 += (((lo * n)>>15)<<1);
+ L_32 = (hi * n)<<1;
+ L_32 += (((lo * n)>>15)<<1);
- return (L_32);
+ return (L_32);
}
/*****************************************************************************
@@ -194,30 +194,30 @@
Word32 Div_32 (Word32 L_num, Word16 denom_hi, Word16 denom_lo)
{
- Word16 approx, hi, lo, n_hi, n_lo;
- Word32 L_32;
+ Word16 approx, hi, lo, n_hi, n_lo;
+ Word32 L_32;
- /* First approximation: 1 / L_denom = 1/denom_hi */
+ /* First approximation: 1 / L_denom = 1/denom_hi */
- approx = div_s ((Word16) 0x3fff, denom_hi);
+ approx = div_s ((Word16) 0x3fff, denom_hi);
- /* 1/L_denom = approx * (2.0 - L_denom * approx) */
+ /* 1/L_denom = approx * (2.0 - L_denom * approx) */
- L_32 = Mpy_32_16 (denom_hi, denom_lo, approx);
+ L_32 = Mpy_32_16 (denom_hi, denom_lo, approx);
- L_32 = L_sub ((Word32) 0x7fffffffL, L_32);
- hi = L_32 >> 16;
- lo = (L_32 & 0xffff) >> 1;
+ L_32 = L_sub ((Word32) 0x7fffffffL, L_32);
+ hi = L_32 >> 16;
+ lo = (L_32 & 0xffff) >> 1;
- L_32 = Mpy_32_16 (hi, lo, approx);
+ L_32 = Mpy_32_16 (hi, lo, approx);
- /* L_num * (1/L_denom) */
- hi = L_32 >> 16;
- lo = (L_32 & 0xffff) >> 1;
- VO_L_Extract (L_num, &n_hi, &n_lo);
- L_32 = Mpy_32 (n_hi, n_lo, hi, lo);
- L_32 = L_shl2(L_32, 2);
+ /* L_num * (1/L_denom) */
+ hi = L_32 >> 16;
+ lo = (L_32 & 0xffff) >> 1;
+ VO_L_Extract (L_num, &n_hi, &n_lo);
+ L_32 = Mpy_32 (n_hi, n_lo, hi, lo);
+ L_32 = L_shl2(L_32, 2);
- return (L_32);
+ return (L_32);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/p_med_ol.c b/media/libstagefright/codecs/amrwbenc/src/p_med_ol.c
index b8174b9..5d2b4bd 100644
--- a/media/libstagefright/codecs/amrwbenc/src/p_med_ol.c
+++ b/media/libstagefright/codecs/amrwbenc/src/p_med_ol.c
@@ -18,7 +18,7 @@
* File: p_med_ol.c *
* *
* Description: Compute the open loop pitch lag *
-* output: open loop pitch lag *
+* output: open loop pitch lag *
************************************************************************/
#include "typedef.h"
@@ -29,131 +29,131 @@
#include "p_med_ol.tab"
Word16 Pitch_med_ol(
- Word16 wsp[], /* i: signal used to compute the open loop pitch*/
+ Word16 wsp[], /* i: signal used to compute the open loop pitch*/
/* wsp[-pit_max] to wsp[-1] should be known */
- Coder_State *st, /* i/o: codec global structure */
- Word16 L_frame /* i: length of frame to compute pitch */
- )
+ Coder_State *st, /* i/o: codec global structure */
+ Word16 L_frame /* i: length of frame to compute pitch */
+ )
{
- Word16 Tm;
- Word16 hi, lo;
- Word16 *ww, *we, *hp_wsp;
- Word16 exp_R0, exp_R1, exp_R2;
- Word32 i, j, max, R0, R1, R2;
- Word16 *p1, *p2;
- Word16 L_min = 17; /* minimum pitch lag: PIT_MIN / OPL_DECIM */
- Word16 L_max = 115; /* maximum pitch lag: PIT_MAX / OPL_DECIM */
- Word16 L_0 = st->old_T0_med; /* old open-loop pitch */
- Word16 *gain = &(st->ol_gain); /* normalize correlation of hp_wsp for the lag */
- Word16 *hp_wsp_mem = st->hp_wsp_mem; /* memory of the hypass filter for hp_wsp[] (lg = 9)*/
- Word16 *old_hp_wsp = st->old_hp_wsp; /* hypass wsp[] */
- Word16 wght_flg = st->ol_wght_flg; /* is weighting function used */
+ Word16 Tm;
+ Word16 hi, lo;
+ Word16 *ww, *we, *hp_wsp;
+ Word16 exp_R0, exp_R1, exp_R2;
+ Word32 i, j, max, R0, R1, R2;
+ Word16 *p1, *p2;
+ Word16 L_min = 17; /* minimum pitch lag: PIT_MIN / OPL_DECIM */
+ Word16 L_max = 115; /* maximum pitch lag: PIT_MAX / OPL_DECIM */
+ Word16 L_0 = st->old_T0_med; /* old open-loop pitch */
+ Word16 *gain = &(st->ol_gain); /* normalize correlation of hp_wsp for the lag */
+ Word16 *hp_wsp_mem = st->hp_wsp_mem; /* memory of the hypass filter for hp_wsp[] (lg = 9)*/
+ Word16 *old_hp_wsp = st->old_hp_wsp; /* hypass wsp[] */
+ Word16 wght_flg = st->ol_wght_flg; /* is weighting function used */
- ww = &corrweight[198];
- we = &corrweight[98 + L_max - L_0];
+ ww = &corrweight[198];
+ we = &corrweight[98 + L_max - L_0];
- max = MIN_32;
- Tm = 0;
- for (i = L_max; i > L_min; i--)
- {
- /* Compute the correlation */
- R0 = 0;
- p1 = wsp;
- p2 = &wsp[-i];
- for (j = 0; j < L_frame; j+=4)
- {
- R0 += vo_L_mult((*p1++), (*p2++));
- R0 += vo_L_mult((*p1++), (*p2++));
- R0 += vo_L_mult((*p1++), (*p2++));
- R0 += vo_L_mult((*p1++), (*p2++));
- }
- /* Weighting of the correlation function. */
- hi = R0>>16;
- lo = (R0 & 0xffff)>>1;
+ max = MIN_32;
+ Tm = 0;
+ for (i = L_max; i > L_min; i--)
+ {
+ /* Compute the correlation */
+ R0 = 0;
+ p1 = wsp;
+ p2 = &wsp[-i];
+ for (j = 0; j < L_frame; j+=4)
+ {
+ R0 += vo_L_mult((*p1++), (*p2++));
+ R0 += vo_L_mult((*p1++), (*p2++));
+ R0 += vo_L_mult((*p1++), (*p2++));
+ R0 += vo_L_mult((*p1++), (*p2++));
+ }
+ /* Weighting of the correlation function. */
+ hi = R0>>16;
+ lo = (R0 & 0xffff)>>1;
- R0 = Mpy_32_16(hi, lo, *ww);
- ww--;
+ R0 = Mpy_32_16(hi, lo, *ww);
+ ww--;
- if ((L_0 > 0) && (wght_flg > 0))
- {
- /* Weight the neighbourhood of the old lag. */
- hi = R0>>16;
- lo = (R0 & 0xffff)>>1;
- R0 = Mpy_32_16(hi, lo, *we);
- we--;
- }
- if(R0 >= max)
- {
- max = R0;
- Tm = i;
- }
- }
+ if ((L_0 > 0) && (wght_flg > 0))
+ {
+ /* Weight the neighbourhood of the old lag. */
+ hi = R0>>16;
+ lo = (R0 & 0xffff)>>1;
+ R0 = Mpy_32_16(hi, lo, *we);
+ we--;
+ }
+ if(R0 >= max)
+ {
+ max = R0;
+ Tm = i;
+ }
+ }
- /* Hypass the wsp[] vector */
- hp_wsp = old_hp_wsp + L_max;
- Hp_wsp(wsp, hp_wsp, L_frame, hp_wsp_mem);
+ /* Hypass the wsp[] vector */
+ hp_wsp = old_hp_wsp + L_max;
+ Hp_wsp(wsp, hp_wsp, L_frame, hp_wsp_mem);
- /* Compute normalize correlation at delay Tm */
- R0 = 0;
- R1 = 0;
- R2 = 0;
- p1 = hp_wsp;
- p2 = hp_wsp - Tm;
- for (j = 0; j < L_frame; j+=4)
- {
- R2 += vo_mult32(*p1, *p1);
- R1 += vo_mult32(*p2, *p2);
- R0 += vo_mult32(*p1++, *p2++);
- R2 += vo_mult32(*p1, *p1);
- R1 += vo_mult32(*p2, *p2);
- R0 += vo_mult32(*p1++, *p2++);
- R2 += vo_mult32(*p1, *p1);
- R1 += vo_mult32(*p2, *p2);
- R0 += vo_mult32(*p1++, *p2++);
- R2 += vo_mult32(*p1, *p1);
- R1 += vo_mult32(*p2, *p2);
- R0 += vo_mult32(*p1++, *p2++);
- }
- R0 = R0 <<1;
- R1 = (R1 <<1) + 1L;
- R2 = (R2 <<1) + 1L;
- /* gain = R0/ sqrt(R1*R2) */
+ /* Compute normalize correlation at delay Tm */
+ R0 = 0;
+ R1 = 0;
+ R2 = 0;
+ p1 = hp_wsp;
+ p2 = hp_wsp - Tm;
+ for (j = 0; j < L_frame; j+=4)
+ {
+ R2 += vo_mult32(*p1, *p1);
+ R1 += vo_mult32(*p2, *p2);
+ R0 += vo_mult32(*p1++, *p2++);
+ R2 += vo_mult32(*p1, *p1);
+ R1 += vo_mult32(*p2, *p2);
+ R0 += vo_mult32(*p1++, *p2++);
+ R2 += vo_mult32(*p1, *p1);
+ R1 += vo_mult32(*p2, *p2);
+ R0 += vo_mult32(*p1++, *p2++);
+ R2 += vo_mult32(*p1, *p1);
+ R1 += vo_mult32(*p2, *p2);
+ R0 += vo_mult32(*p1++, *p2++);
+ }
+ R0 = R0 <<1;
+ R1 = (R1 <<1) + 1L;
+ R2 = (R2 <<1) + 1L;
+ /* gain = R0/ sqrt(R1*R2) */
- exp_R0 = norm_l(R0);
- R0 = (R0 << exp_R0);
+ exp_R0 = norm_l(R0);
+ R0 = (R0 << exp_R0);
- exp_R1 = norm_l(R1);
- R1 = (R1 << exp_R1);
+ exp_R1 = norm_l(R1);
+ R1 = (R1 << exp_R1);
- exp_R2 = norm_l(R2);
- R2 = (R2 << exp_R2);
+ exp_R2 = norm_l(R2);
+ R2 = (R2 << exp_R2);
- R1 = vo_L_mult(vo_round(R1), vo_round(R2));
+ R1 = vo_L_mult(voround(R1), voround(R2));
- i = norm_l(R1);
- R1 = (R1 << i);
+ i = norm_l(R1);
+ R1 = (R1 << i);
- exp_R1 += exp_R2;
- exp_R1 += i;
- exp_R1 = 62 - exp_R1;
+ exp_R1 += exp_R2;
+ exp_R1 += i;
+ exp_R1 = 62 - exp_R1;
- Isqrt_n(&R1, &exp_R1);
+ Isqrt_n(&R1, &exp_R1);
- R0 = vo_L_mult(voround(R0), voround(R1));
- exp_R0 = 31 - exp_R0;
- exp_R0 += exp_R1;
+ R0 = vo_L_mult(voround(R0), voround(R1));
+ exp_R0 = 31 - exp_R0;
+ exp_R0 += exp_R1;
- *gain = vo_round(L_shl(R0, exp_R0));
+ *gain = vo_round(L_shl(R0, exp_R0));
- /* Shitf hp_wsp[] for next frame */
+ /* Shitf hp_wsp[] for next frame */
- for (i = 0; i < L_max; i++)
- {
- old_hp_wsp[i] = old_hp_wsp[i + L_frame];
- }
+ for (i = 0; i < L_max; i++)
+ {
+ old_hp_wsp[i] = old_hp_wsp[i + L_frame];
+ }
- return (Tm);
+ return (Tm);
}
/************************************************************************
@@ -171,84 +171,84 @@
Word16 median5(Word16 x[])
{
- Word16 x1, x2, x3, x4, x5;
- Word16 tmp;
+ Word16 x1, x2, x3, x4, x5;
+ Word16 tmp;
- x1 = x[-2];
- x2 = x[-1];
- x3 = x[0];
- x4 = x[1];
- x5 = x[2];
+ x1 = x[-2];
+ x2 = x[-1];
+ x3 = x[0];
+ x4 = x[1];
+ x5 = x[2];
- if (x2 < x1)
- {
- tmp = x1;
- x1 = x2;
- x2 = tmp;
- }
- if (x3 < x1)
- {
- tmp = x1;
- x1 = x3;
- x3 = tmp;
- }
- if (x4 < x1)
- {
- tmp = x1;
- x1 = x4;
- x4 = tmp;
- }
- if (x5 < x1)
- {
- x5 = x1;
- }
- if (x3 < x2)
- {
- tmp = x2;
- x2 = x3;
- x3 = tmp;
- }
- if (x4 < x2)
- {
- tmp = x2;
- x2 = x4;
- x4 = tmp;
- }
- if (x5 < x2)
- {
- x5 = x2;
- }
- if (x4 < x3)
- {
- x3 = x4;
- }
- if (x5 < x3)
- {
- x3 = x5;
- }
- return (x3);
+ if (x2 < x1)
+ {
+ tmp = x1;
+ x1 = x2;
+ x2 = tmp;
+ }
+ if (x3 < x1)
+ {
+ tmp = x1;
+ x1 = x3;
+ x3 = tmp;
+ }
+ if (x4 < x1)
+ {
+ tmp = x1;
+ x1 = x4;
+ x4 = tmp;
+ }
+ if (x5 < x1)
+ {
+ x5 = x1;
+ }
+ if (x3 < x2)
+ {
+ tmp = x2;
+ x2 = x3;
+ x3 = tmp;
+ }
+ if (x4 < x2)
+ {
+ tmp = x2;
+ x2 = x4;
+ x4 = tmp;
+ }
+ if (x5 < x2)
+ {
+ x5 = x2;
+ }
+ if (x4 < x3)
+ {
+ x3 = x4;
+ }
+ if (x5 < x3)
+ {
+ x3 = x5;
+ }
+ return (x3);
}
Word16 Med_olag( /* output : median of 5 previous open-loop lags */
- Word16 prev_ol_lag, /* input : previous open-loop lag */
- Word16 old_ol_lag[5]
- )
+ Word16 prev_ol_lag, /* input : previous open-loop lag */
+ Word16 old_ol_lag[5]
+ )
{
- Word32 i;
+ Word32 i;
- /* Use median of 5 previous open-loop lags as old lag */
+ /* Use median of 5 previous open-loop lags as old lag */
- for (i = 4; i > 0; i--)
- {
- old_ol_lag[i] = old_ol_lag[i - 1];
- }
+ for (i = 4; i > 0; i--)
+ {
+ old_ol_lag[i] = old_ol_lag[i - 1];
+ }
- old_ol_lag[0] = prev_ol_lag;
+ old_ol_lag[0] = prev_ol_lag;
- i = median5(&old_ol_lag[2]);
+ i = median5(&old_ol_lag[2]);
- return i;
+ return i;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/pit_shrp.c b/media/libstagefright/codecs/amrwbenc/src/pit_shrp.c
index 6f55b8f..f100253 100644
--- a/media/libstagefright/codecs/amrwbenc/src/pit_shrp.c
+++ b/media/libstagefright/codecs/amrwbenc/src/pit_shrp.c
@@ -25,24 +25,24 @@
#include "basic_op.h"
void Pit_shrp(
- Word16 * x, /* in/out: impulse response (or algebraic code) */
- Word16 pit_lag, /* input : pitch lag */
- Word16 sharp, /* input : pitch sharpening factor (Q15) */
- Word16 L_subfr /* input : subframe size */
- )
+ Word16 * x, /* in/out: impulse response (or algebraic code) */
+ Word16 pit_lag, /* input : pitch lag */
+ Word16 sharp, /* input : pitch sharpening factor (Q15) */
+ Word16 L_subfr /* input : subframe size */
+ )
{
- Word32 i;
- Word32 L_tmp;
- Word16 *x_ptr = x + pit_lag;
+ Word32 i;
+ Word32 L_tmp;
+ Word16 *x_ptr = x + pit_lag;
- for (i = pit_lag; i < L_subfr; i++)
- {
- L_tmp = (*x_ptr << 15);
- L_tmp += *x++ * sharp;
- *x_ptr++ = ((L_tmp + 0x4000)>>15);
- }
+ for (i = pit_lag; i < L_subfr; i++)
+ {
+ L_tmp = (*x_ptr << 15);
+ L_tmp += *x++ * sharp;
+ *x_ptr++ = ((L_tmp + 0x4000)>>15);
+ }
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c b/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c
index b66b55e..de2a221 100644
--- a/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c
+++ b/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c
@@ -18,7 +18,7 @@
* File: pitch_f4.c *
* *
* Description: Find the closed loop pitch period with *
-* 1/4 subsample resolution. *
+* 1/4 subsample resolution. *
* *
************************************************************************/
@@ -37,117 +37,117 @@
#ifdef ASM_OPT
void Norm_corr_asm(
- Word16 exc[], /* (i) : excitation buffer */
- Word16 xn[], /* (i) : target vector */
- Word16 h[], /* (i) Q15 : impulse response of synth/wgt filters */
- Word16 L_subfr,
- Word16 t_min, /* (i) : minimum value of pitch lag. */
- Word16 t_max, /* (i) : maximum value of pitch lag. */
- Word16 corr_norm[] /* (o) Q15 : normalized correlation */
- );
+ Word16 exc[], /* (i) : excitation buffer */
+ Word16 xn[], /* (i) : target vector */
+ Word16 h[], /* (i) Q15 : impulse response of synth/wgt filters */
+ Word16 L_subfr,
+ Word16 t_min, /* (i) : minimum value of pitch lag. */
+ Word16 t_max, /* (i) : maximum value of pitch lag. */
+ Word16 corr_norm[] /* (o) Q15 : normalized correlation */
+ );
#else
static void Norm_Corr(
- Word16 exc[], /* (i) : excitation buffer */
- Word16 xn[], /* (i) : target vector */
- Word16 h[], /* (i) Q15 : impulse response of synth/wgt filters */
- Word16 L_subfr,
- Word16 t_min, /* (i) : minimum value of pitch lag. */
- Word16 t_max, /* (i) : maximum value of pitch lag. */
- Word16 corr_norm[] /* (o) Q15 : normalized correlation */
- );
+ Word16 exc[], /* (i) : excitation buffer */
+ Word16 xn[], /* (i) : target vector */
+ Word16 h[], /* (i) Q15 : impulse response of synth/wgt filters */
+ Word16 L_subfr,
+ Word16 t_min, /* (i) : minimum value of pitch lag. */
+ Word16 t_max, /* (i) : maximum value of pitch lag. */
+ Word16 corr_norm[] /* (o) Q15 : normalized correlation */
+ );
#endif
static Word16 Interpol_4( /* (o) : interpolated value */
- Word16 * x, /* (i) : input vector */
- Word32 frac /* (i) : fraction (-4..+3) */
- );
+ Word16 * x, /* (i) : input vector */
+ Word32 frac /* (i) : fraction (-4..+3) */
+ );
Word16 Pitch_fr4( /* (o) : pitch period. */
- Word16 exc[], /* (i) : excitation buffer */
- Word16 xn[], /* (i) : target vector */
- Word16 h[], /* (i) Q15 : impulse response of synth/wgt filters */
- Word16 t0_min, /* (i) : minimum value in the searched range. */
- Word16 t0_max, /* (i) : maximum value in the searched range. */
- Word16 * pit_frac, /* (o) : chosen fraction (0, 1, 2 or 3). */
- Word16 i_subfr, /* (i) : indicator for first subframe. */
- Word16 t0_fr2, /* (i) : minimum value for resolution 1/2 */
- Word16 t0_fr1, /* (i) : minimum value for resolution 1 */
- Word16 L_subfr /* (i) : Length of subframe */
- )
+ Word16 exc[], /* (i) : excitation buffer */
+ Word16 xn[], /* (i) : target vector */
+ Word16 h[], /* (i) Q15 : impulse response of synth/wgt filters */
+ Word16 t0_min, /* (i) : minimum value in the searched range. */
+ Word16 t0_max, /* (i) : maximum value in the searched range. */
+ Word16 * pit_frac, /* (o) : chosen fraction (0, 1, 2 or 3). */
+ Word16 i_subfr, /* (i) : indicator for first subframe. */
+ Word16 t0_fr2, /* (i) : minimum value for resolution 1/2 */
+ Word16 t0_fr1, /* (i) : minimum value for resolution 1 */
+ Word16 L_subfr /* (i) : Length of subframe */
+ )
{
- Word32 fraction, i;
- Word16 t_min, t_max;
- Word16 max, t0, step, temp;
- Word16 *corr;
- Word16 corr_v[40]; /* Total length = t0_max-t0_min+1+2*L_inter */
+ Word32 fraction, i;
+ Word16 t_min, t_max;
+ Word16 max, t0, step, temp;
+ Word16 *corr;
+ Word16 corr_v[40]; /* Total length = t0_max-t0_min+1+2*L_inter */
- /* Find interval to compute normalized correlation */
+ /* Find interval to compute normalized correlation */
- t_min = t0_min - L_INTERPOL1;
- t_max = t0_max + L_INTERPOL1;
- corr = &corr_v[-t_min];
- /* Compute normalized correlation between target and filtered excitation */
+ t_min = t0_min - L_INTERPOL1;
+ t_max = t0_max + L_INTERPOL1;
+ corr = &corr_v[-t_min];
+ /* Compute normalized correlation between target and filtered excitation */
#ifdef ASM_OPT /* asm optimization branch */
Norm_corr_asm(exc, xn, h, L_subfr, t_min, t_max, corr);
#else
- Norm_Corr(exc, xn, h, L_subfr, t_min, t_max, corr);
+ Norm_Corr(exc, xn, h, L_subfr, t_min, t_max, corr);
#endif
- /* Find integer pitch */
+ /* Find integer pitch */
- max = corr[t0_min];
- t0 = t0_min;
- for (i = t0_min + 1; i <= t0_max; i++)
- {
- if (corr[i] >= max)
- {
- max = corr[i];
- t0 = i;
- }
- }
- /* If first subframe and t0 >= t0_fr1, do not search fractionnal pitch */
- if ((i_subfr == 0) && (t0 >= t0_fr1))
- {
- *pit_frac = 0;
- return (t0);
- }
- /*------------------------------------------------------------------*
- * Search fractionnal pitch with 1/4 subsample resolution. *
- * Test the fractions around t0 and choose the one which maximizes *
- * the interpolated normalized correlation. *
- *------------------------------------------------------------------*/
+ max = corr[t0_min];
+ t0 = t0_min;
+ for (i = t0_min + 1; i <= t0_max; i++)
+ {
+ if (corr[i] >= max)
+ {
+ max = corr[i];
+ t0 = i;
+ }
+ }
+ /* If first subframe and t0 >= t0_fr1, do not search fractionnal pitch */
+ if ((i_subfr == 0) && (t0 >= t0_fr1))
+ {
+ *pit_frac = 0;
+ return (t0);
+ }
+ /*------------------------------------------------------------------*
+ * Search fractionnal pitch with 1/4 subsample resolution. *
+ * Test the fractions around t0 and choose the one which maximizes *
+ * the interpolated normalized correlation. *
+ *------------------------------------------------------------------*/
- step = 1; /* 1/4 subsample resolution */
- fraction = -3;
- if ((t0_fr2 == PIT_MIN)||((i_subfr == 0) && (t0 >= t0_fr2)))
- {
- step = 2; /* 1/2 subsample resolution */
- fraction = -2;
- }
- if(t0 == t0_min)
- {
- fraction = 0;
- }
- max = Interpol_4(&corr[t0], fraction);
+ step = 1; /* 1/4 subsample resolution */
+ fraction = -3;
+ if ((t0_fr2 == PIT_MIN)||((i_subfr == 0) && (t0 >= t0_fr2)))
+ {
+ step = 2; /* 1/2 subsample resolution */
+ fraction = -2;
+ }
+ if(t0 == t0_min)
+ {
+ fraction = 0;
+ }
+ max = Interpol_4(&corr[t0], fraction);
- for (i = fraction + step; i <= 3; i += step)
- {
- temp = Interpol_4(&corr[t0], i);
- if(temp > max)
- {
- max = temp;
- fraction = i;
- }
- }
- /* limit the fraction value in the interval [0,1,2,3] */
- if (fraction < 0)
- {
- fraction += UP_SAMP;
- t0 -= 1;
- }
- *pit_frac = fraction;
- return (t0);
+ for (i = fraction + step; i <= 3; i += step)
+ {
+ temp = Interpol_4(&corr[t0], i);
+ if(temp > max)
+ {
+ max = temp;
+ fraction = i;
+ }
+ }
+ /* limit the fraction value in the interval [0,1,2,3] */
+ if (fraction < 0)
+ {
+ fraction += UP_SAMP;
+ t0 -= 1;
+ }
+ *pit_frac = fraction;
+ return (t0);
}
@@ -161,109 +161,109 @@
************************************************************************************/
#ifndef ASM_OPT
static void Norm_Corr(
- Word16 exc[], /* (i) : excitation buffer */
- Word16 xn[], /* (i) : target vector */
- Word16 h[], /* (i) Q15 : impulse response of synth/wgt filters */
- Word16 L_subfr,
- Word16 t_min, /* (i) : minimum value of pitch lag. */
- Word16 t_max, /* (i) : maximum value of pitch lag. */
- Word16 corr_norm[]) /* (o) Q15 : normalized correlation */
+ Word16 exc[], /* (i) : excitation buffer */
+ Word16 xn[], /* (i) : target vector */
+ Word16 h[], /* (i) Q15 : impulse response of synth/wgt filters */
+ Word16 L_subfr,
+ Word16 t_min, /* (i) : minimum value of pitch lag. */
+ Word16 t_max, /* (i) : maximum value of pitch lag. */
+ Word16 corr_norm[]) /* (o) Q15 : normalized correlation */
{
- Word32 i, k, t;
- Word32 corr, exp_corr, norm, exp, scale;
- Word16 exp_norm, excf[L_SUBFR], tmp;
- Word32 L_tmp, L_tmp1, L_tmp2;
+ Word32 i, k, t;
+ Word32 corr, exp_corr, norm, exp, scale;
+ Word16 exp_norm, excf[L_SUBFR], tmp;
+ Word32 L_tmp, L_tmp1, L_tmp2;
UNUSED(L_subfr);
- /* compute the filtered excitation for the first delay t_min */
- k = -t_min;
+ /* compute the filtered excitation for the first delay t_min */
+ k = -t_min;
#ifdef ASM_OPT /* asm optimization branch */
- Convolve_asm(&exc[k], h, excf, 64);
+ Convolve_asm(&exc[k], h, excf, 64);
#else
- Convolve(&exc[k], h, excf, 64);
+ Convolve(&exc[k], h, excf, 64);
#endif
- /* Compute rounded down 1/sqrt(energy of xn[]) */
- L_tmp = 0;
- for (i = 0; i < 64; i+=4)
- {
- L_tmp += (xn[i] * xn[i]);
- L_tmp += (xn[i+1] * xn[i+1]);
- L_tmp += (xn[i+2] * xn[i+2]);
- L_tmp += (xn[i+3] * xn[i+3]);
- }
+ /* Compute rounded down 1/sqrt(energy of xn[]) */
+ L_tmp = 0;
+ for (i = 0; i < 64; i+=4)
+ {
+ L_tmp += (xn[i] * xn[i]);
+ L_tmp += (xn[i+1] * xn[i+1]);
+ L_tmp += (xn[i+2] * xn[i+2]);
+ L_tmp += (xn[i+3] * xn[i+3]);
+ }
- L_tmp = (L_tmp << 1) + 1;
- exp = norm_l(L_tmp);
- exp = (32 - exp);
- //exp = exp + 2; /* energy of xn[] x 2 + rounded up */
- scale = -(exp >> 1); /* (1<<scale) < 1/sqrt(energy rounded) */
+ L_tmp = (L_tmp << 1) + 1;
+ exp = norm_l(L_tmp);
+ exp = (32 - exp);
+ //exp = exp + 2; /* energy of xn[] x 2 + rounded up */
+ scale = -(exp >> 1); /* (1<<scale) < 1/sqrt(energy rounded) */
- /* loop for every possible period */
+ /* loop for every possible period */
- for (t = t_min; t <= t_max; t++)
- {
- /* Compute correlation between xn[] and excf[] */
- L_tmp = 0;
- L_tmp1 = 0;
- for (i = 0; i < 64; i+=4)
- {
- L_tmp += (xn[i] * excf[i]);
- L_tmp1 += (excf[i] * excf[i]);
- L_tmp += (xn[i+1] * excf[i+1]);
- L_tmp1 += (excf[i+1] * excf[i+1]);
- L_tmp += (xn[i+2] * excf[i+2]);
- L_tmp1 += (excf[i+2] * excf[i+2]);
- L_tmp += (xn[i+3] * excf[i+3]);
- L_tmp1 += (excf[i+3] * excf[i+3]);
- }
+ for (t = t_min; t <= t_max; t++)
+ {
+ /* Compute correlation between xn[] and excf[] */
+ L_tmp = 0;
+ L_tmp1 = 0;
+ for (i = 0; i < 64; i+=4)
+ {
+ L_tmp += (xn[i] * excf[i]);
+ L_tmp1 += (excf[i] * excf[i]);
+ L_tmp += (xn[i+1] * excf[i+1]);
+ L_tmp1 += (excf[i+1] * excf[i+1]);
+ L_tmp += (xn[i+2] * excf[i+2]);
+ L_tmp1 += (excf[i+2] * excf[i+2]);
+ L_tmp += (xn[i+3] * excf[i+3]);
+ L_tmp1 += (excf[i+3] * excf[i+3]);
+ }
- L_tmp = (L_tmp << 1) + 1;
- L_tmp1 = (L_tmp1 << 1) + 1;
+ L_tmp = (L_tmp << 1) + 1;
+ L_tmp1 = (L_tmp1 << 1) + 1;
- exp = norm_l(L_tmp);
- L_tmp = (L_tmp << exp);
- exp_corr = (30 - exp);
- corr = extract_h(L_tmp);
+ exp = norm_l(L_tmp);
+ L_tmp = (L_tmp << exp);
+ exp_corr = (30 - exp);
+ corr = extract_h(L_tmp);
- exp = norm_l(L_tmp1);
- L_tmp = (L_tmp1 << exp);
- exp_norm = (30 - exp);
+ exp = norm_l(L_tmp1);
+ L_tmp = (L_tmp1 << exp);
+ exp_norm = (30 - exp);
- Isqrt_n(&L_tmp, &exp_norm);
- norm = extract_h(L_tmp);
+ Isqrt_n(&L_tmp, &exp_norm);
+ norm = extract_h(L_tmp);
- /* Normalize correlation = correlation * (1/sqrt(energy)) */
+ /* Normalize correlation = correlation * (1/sqrt(energy)) */
- L_tmp = vo_L_mult(corr, norm);
+ L_tmp = vo_L_mult(corr, norm);
- L_tmp2 = exp_corr + exp_norm + scale;
- if(L_tmp2 < 0)
- {
- L_tmp2 = -L_tmp2;
- L_tmp = L_tmp >> L_tmp2;
- }
- else
- {
- L_tmp = L_tmp << L_tmp2;
- }
+ L_tmp2 = exp_corr + exp_norm + scale;
+ if(L_tmp2 < 0)
+ {
+ L_tmp2 = -L_tmp2;
+ L_tmp = L_tmp >> L_tmp2;
+ }
+ else
+ {
+ L_tmp = L_tmp << L_tmp2;
+ }
- corr_norm[t] = vo_round(L_tmp);
- /* modify the filtered excitation excf[] for the next iteration */
+ corr_norm[t] = vo_round(L_tmp);
+ /* modify the filtered excitation excf[] for the next iteration */
- if(t != t_max)
- {
- k = -(t + 1);
- tmp = exc[k];
- for (i = 63; i > 0; i--)
- {
- excf[i] = add1(vo_mult(tmp, h[i]), excf[i - 1]);
- }
- excf[0] = vo_mult(tmp, h[0]);
- }
- }
- return;
+ if(t != t_max)
+ {
+ k = -(t + 1);
+ tmp = exc[k];
+ for (i = 63; i > 0; i--)
+ {
+ excf[i] = add1(vo_mult(tmp, h[i]), excf[i - 1]);
+ }
+ excf[0] = vo_mult(tmp, h[0]);
+ }
+ }
+ return;
}
#endif
@@ -276,10 +276,10 @@
/* 1/4 resolution interpolation filter (-3 dB at 0.791*fs/2) in Q14 */
static Word16 inter4_1[4][8] =
{
- {-12, 420, -1732, 5429, 13418, -1242, 73, 32},
- {-26, 455, -2142, 9910, 9910, -2142, 455, -26},
- {32, 73, -1242, 13418, 5429, -1732, 420, -12},
- {206, -766, 1376, 14746, 1376, -766, 206, 0}
+ {-12, 420, -1732, 5429, 13418, -1242, 73, 32},
+ {-26, 455, -2142, 9910, 9910, -2142, 455, -26},
+ {32, 73, -1242, 13418, 5429, -1732, 420, -12},
+ {206, -766, 1376, 14746, 1376, -766, 206, 0}
};
/*** Coefficients in floating point
@@ -292,34 +292,34 @@
***/
static Word16 Interpol_4( /* (o) : interpolated value */
- Word16 * x, /* (i) : input vector */
- Word32 frac /* (i) : fraction (-4..+3) */
- )
+ Word16 * x, /* (i) : input vector */
+ Word32 frac /* (i) : fraction (-4..+3) */
+ )
{
- Word16 sum;
- Word32 k, L_sum;
- Word16 *ptr;
+ Word16 sum;
+ Word32 k, L_sum;
+ Word16 *ptr;
- if (frac < 0)
- {
- frac += UP_SAMP;
- x--;
- }
- x = x - L_INTERPOL1 + 1;
- k = UP_SAMP - 1 - frac;
- ptr = &(inter4_1[k][0]);
+ if (frac < 0)
+ {
+ frac += UP_SAMP;
+ x--;
+ }
+ x = x - L_INTERPOL1 + 1;
+ k = UP_SAMP - 1 - frac;
+ ptr = &(inter4_1[k][0]);
- L_sum = vo_mult32(x[0], (*ptr++));
- L_sum += vo_mult32(x[1], (*ptr++));
- L_sum += vo_mult32(x[2], (*ptr++));
- L_sum += vo_mult32(x[3], (*ptr++));
- L_sum += vo_mult32(x[4], (*ptr++));
- L_sum += vo_mult32(x[5], (*ptr++));
- L_sum += vo_mult32(x[6], (*ptr++));
- L_sum += vo_mult32(x[7], (*ptr++));
+ L_sum = vo_mult32(x[0], (*ptr++));
+ L_sum += vo_mult32(x[1], (*ptr++));
+ L_sum += vo_mult32(x[2], (*ptr++));
+ L_sum += vo_mult32(x[3], (*ptr++));
+ L_sum += vo_mult32(x[4], (*ptr++));
+ L_sum += vo_mult32(x[5], (*ptr++));
+ L_sum += vo_mult32(x[6], (*ptr++));
+ L_sum += vo_mult32(x[7], (*ptr++));
- sum = extract_h(L_add(L_shl2(L_sum, 2), 0x8000));
- return (sum);
+ sum = extract_h(L_add(L_shl2(L_sum, 2), 0x8000));
+ return (sum);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/pred_lt4.c b/media/libstagefright/codecs/amrwbenc/src/pred_lt4.c
index 8404cf9..386cab3 100644
--- a/media/libstagefright/codecs/amrwbenc/src/pred_lt4.c
+++ b/media/libstagefright/codecs/amrwbenc/src/pred_lt4.c
@@ -34,86 +34,86 @@
Word16 inter4_2[4][32] =
{
- {0,-2,4,-2,-10,38,-88,165,-275,424,-619,871,-1207,1699,-2598,5531,14031,-2147,780,-249,
- -16,153,-213,226,-209,175,-133,91,-55,28,-10,2},
+ {0,-2,4,-2,-10,38,-88,165,-275,424,-619,871,-1207,1699,-2598,5531,14031,-2147,780,-249,
+ -16,153,-213,226,-209,175,-133,91,-55,28,-10,2},
- {1,-7,19,-33,47,-52,43,-9,-60,175,-355,626,-1044,1749,-3267,10359,10359,-3267,1749,-1044,
- 626,-355,175,-60,-9,43,-52,47,-33,19, -7, 1},
+ {1,-7,19,-33,47,-52,43,-9,-60,175,-355,626,-1044,1749,-3267,10359,10359,-3267,1749,-1044,
+ 626,-355,175,-60,-9,43,-52,47,-33,19, -7, 1},
- {2,-10,28,-55,91,-133,175,-209,226,-213,153,-16,-249,780,-2147,14031,5531,-2598,1699,-1207,
- 871,-619,424,-275,165,-88,38,-10,-2,4,-2,0},
+ {2,-10,28,-55,91,-133,175,-209,226,-213,153,-16,-249,780,-2147,14031,5531,-2598,1699,-1207,
+ 871,-619,424,-275,165,-88,38,-10,-2,4,-2,0},
- {1,-7,22,-49,92,-153,231,-325,431,-544,656,-762,853,-923,968,15401,968,-923,853,-762,
- 656,-544,431,-325,231,-153,92,-49,22,-7, 1, 0}
+ {1,-7,22,-49,92,-153,231,-325,431,-544,656,-762,853,-923,968,15401,968,-923,853,-762,
+ 656,-544,431,-325,231,-153,92,-49,22,-7, 1, 0}
};
void Pred_lt4(
- Word16 exc[], /* in/out: excitation buffer */
- Word16 T0, /* input : integer pitch lag */
- Word16 frac, /* input : fraction of lag */
- Word16 L_subfr /* input : subframe size */
- )
+ Word16 exc[], /* in/out: excitation buffer */
+ Word16 T0, /* input : integer pitch lag */
+ Word16 frac, /* input : fraction of lag */
+ Word16 L_subfr /* input : subframe size */
+ )
{
- Word16 j, k, *x;
- Word32 L_sum;
- Word16 *ptr, *ptr1;
- Word16 *ptr2;
+ Word16 j, k, *x;
+ Word32 L_sum;
+ Word16 *ptr, *ptr1;
+ Word16 *ptr2;
- x = exc - T0;
- frac = -frac;
- if (frac < 0)
- {
- frac += UP_SAMP;
- x--;
- }
- x -= 15; /* x = L_INTERPOL2 - 1 */
- k = 3 - frac; /* k = UP_SAMP - 1 - frac */
+ x = exc - T0;
+ frac = -frac;
+ if (frac < 0)
+ {
+ frac += UP_SAMP;
+ x--;
+ }
+ x -= 15; /* x = L_INTERPOL2 - 1 */
+ k = 3 - frac; /* k = UP_SAMP - 1 - frac */
- ptr2 = &(inter4_2[k][0]);
- for (j = 0; j < L_subfr; j++)
- {
- ptr = ptr2;
- ptr1 = x;
- L_sum = vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum += vo_mult32((*ptr1++), (*ptr++));
+ ptr2 = &(inter4_2[k][0]);
+ for (j = 0; j < L_subfr; j++)
+ {
+ ptr = ptr2;
+ ptr1 = x;
+ L_sum = vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
+ L_sum += vo_mult32((*ptr1++), (*ptr++));
- L_sum = L_shl2(L_sum, 2);
- exc[j] = extract_h(L_add(L_sum, 0x8000));
- x++;
- }
+ L_sum = L_shl2(L_sum, 2);
+ exc[j] = extract_h(L_add(L_sum, 0x8000));
+ x++;
+ }
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/preemph.c b/media/libstagefright/codecs/amrwbenc/src/preemph.c
index c867bf7..70c8650 100644
--- a/media/libstagefright/codecs/amrwbenc/src/preemph.c
+++ b/media/libstagefright/codecs/amrwbenc/src/preemph.c
@@ -18,7 +18,7 @@
* File: preemph.c *
* *
* Description: Preemphasis: filtering through 1 - g z^-1 *
-* Preemph2 --> signal is multiplied by 2 *
+* Preemph2 --> signal is multiplied by 2 *
* *
************************************************************************/
@@ -26,62 +26,74 @@
#include "basic_op.h"
void Preemph(
- Word16 x[], /* (i/o) : input signal overwritten by the output */
- Word16 mu, /* (i) Q15 : preemphasis coefficient */
- Word16 lg, /* (i) : lenght of filtering */
- Word16 * mem /* (i/o) : memory (x[-1]) */
- )
+ Word16 x[], /* (i/o) : input signal overwritten by the output */
+ Word16 mu, /* (i) Q15 : preemphasis coefficient */
+ Word16 lg, /* (i) : lenght of filtering */
+ Word16 * mem /* (i/o) : memory (x[-1]) */
+ )
{
- Word16 temp;
- Word32 i, L_tmp;
+ Word16 temp;
+ Word32 i, L_tmp;
- temp = x[lg - 1];
+ temp = x[lg - 1];
- for (i = lg - 1; i > 0; i--)
- {
- L_tmp = L_deposit_h(x[i]);
- L_tmp -= (x[i - 1] * mu)<<1;
- x[i] = (L_tmp + 0x8000)>>16;
- }
+ for (i = lg - 1; i > 0; i--)
+ {
+ L_tmp = L_deposit_h(x[i]);
+ L_tmp -= (x[i - 1] * mu)<<1;
+ x[i] = (L_tmp + 0x8000)>>16;
+ }
- L_tmp = L_deposit_h(x[0]);
- L_tmp -= ((*mem) * mu)<<1;
- x[0] = (L_tmp + 0x8000)>>16;
+ L_tmp = L_deposit_h(x[0]);
+ L_tmp -= ((*mem) * mu)<<1;
+ x[0] = (L_tmp + 0x8000)>>16;
- *mem = temp;
+ *mem = temp;
- return;
+ return;
}
void Preemph2(
- Word16 x[], /* (i/o) : input signal overwritten by the output */
- Word16 mu, /* (i) Q15 : preemphasis coefficient */
- Word16 lg, /* (i) : lenght of filtering */
- Word16 * mem /* (i/o) : memory (x[-1]) */
- )
+ Word16 x[], /* (i/o) : input signal overwritten by the output */
+ Word16 mu, /* (i) Q15 : preemphasis coefficient */
+ Word16 lg, /* (i) : lenght of filtering */
+ Word16 * mem /* (i/o) : memory (x[-1]) */
+ )
{
- Word16 temp;
- Word32 i, L_tmp;
+ Word16 temp;
+ Word32 i, L_tmp;
- temp = x[lg - 1];
+ temp = x[lg - 1];
- for (i = (Word16) (lg - 1); i > 0; i--)
- {
- L_tmp = L_deposit_h(x[i]);
- L_tmp -= (x[i - 1] * mu)<<1;
- L_tmp = (L_tmp << 1);
- x[i] = (L_tmp + 0x8000)>>16;
- }
+ for (i = (Word16) (lg - 1); i > 0; i--)
+ {
+ L_tmp = L_deposit_h(x[i]);
+ L_tmp -= (x[i - 1] * mu)<<1; // only called with mu == 22282, so this won't overflow
+ if (L_tmp > INT32_MAX / 2) {
+ L_tmp = INT32_MAX / 2;
+ }
+ L_tmp = (L_tmp << 1);
+ if (L_tmp > INT32_MAX - 0x8000) {
+ L_tmp = INT32_MAX - 0x8000;
+ }
+ x[i] = (L_tmp + 0x8000)>>16;
+ }
- L_tmp = L_deposit_h(x[0]);
- L_tmp -= ((*mem) * mu)<<1;
- L_tmp = (L_tmp << 1);
- x[0] = (L_tmp + 0x8000)>>16;
+ L_tmp = L_deposit_h(x[0]);
+ L_tmp -= ((*mem) * mu)<<1;
+ if (L_tmp > INT32_MAX / 2) {
+ L_tmp = INT32_MAX / 2;
+ }
+ L_tmp = (L_tmp << 1);
+ if (L_tmp > INT32_MAX - 0x8000) {
+ L_tmp = INT32_MAX - 0x8000;
+ }
+ x[0] = (L_tmp + 0x8000)>>16;
- *mem = temp;
+ *mem = temp;
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/q_gain2.c b/media/libstagefright/codecs/amrwbenc/src/q_gain2.c
index e8ca043..bb797d8 100644
--- a/media/libstagefright/codecs/amrwbenc/src/q_gain2.c
+++ b/media/libstagefright/codecs/amrwbenc/src/q_gain2.c
@@ -45,300 +45,300 @@
void Init_Q_gain2(
- Word16 * mem /* output :static memory (2 words) */
- )
+ Word16 * mem /* output :static memory (2 words) */
+ )
{
- Word32 i;
+ Word32 i;
- /* 4nd order quantizer energy predictor (init to -14.0 in Q10) */
- for (i = 0; i < PRED_ORDER; i++)
- {
- mem[i] = -14336; /* past_qua_en[i] */
- }
+ /* 4nd order quantizer energy predictor (init to -14.0 in Q10) */
+ for (i = 0; i < PRED_ORDER; i++)
+ {
+ mem[i] = -14336; /* past_qua_en[i] */
+ }
- return;
+ return;
}
Word16 Q_gain2( /* Return index of quantization. */
- Word16 xn[], /* (i) Q_xn: Target vector. */
- Word16 y1[], /* (i) Q_xn: Adaptive codebook. */
- Word16 Q_xn, /* (i) : xn and y1 format */
- Word16 y2[], /* (i) Q9 : Filtered innovative vector. */
- Word16 code[], /* (i) Q9 : Innovative vector. */
- Word16 g_coeff[], /* (i) : Correlations <xn y1> <y1 y1> */
- /* Compute in G_pitch(). */
- Word16 L_subfr, /* (i) : Subframe lenght. */
- Word16 nbits, /* (i) : number of bits (6 or 7) */
- Word16 * gain_pit, /* (i/o)Q14: Pitch gain. */
- Word32 * gain_cod, /* (o) Q16 : Code gain. */
- Word16 gp_clip, /* (i) : Gp Clipping flag */
- Word16 * mem /* (i/o) : static memory (2 words) */
- )
+ Word16 xn[], /* (i) Q_xn: Target vector. */
+ Word16 y1[], /* (i) Q_xn: Adaptive codebook. */
+ Word16 Q_xn, /* (i) : xn and y1 format */
+ Word16 y2[], /* (i) Q9 : Filtered innovative vector. */
+ Word16 code[], /* (i) Q9 : Innovative vector. */
+ Word16 g_coeff[], /* (i) : Correlations <xn y1> <y1 y1> */
+ /* Compute in G_pitch(). */
+ Word16 L_subfr, /* (i) : Subframe lenght. */
+ Word16 nbits, /* (i) : number of bits (6 or 7) */
+ Word16 * gain_pit, /* (i/o)Q14: Pitch gain. */
+ Word32 * gain_cod, /* (o) Q16 : Code gain. */
+ Word16 gp_clip, /* (i) : Gp Clipping flag */
+ Word16 * mem /* (i/o) : static memory (2 words) */
+ )
{
- Word16 index, *p, min_ind, size;
- Word16 exp, frac, gcode0, exp_gcode0, e_max, exp_code, qua_ener;
- Word16 g_pitch, g2_pitch, g_code, g_pit_cod, g2_code, g2_code_lo;
- Word16 coeff[5], coeff_lo[5], exp_coeff[5];
- Word16 exp_max[5];
- Word32 i, j, L_tmp, dist_min;
- Word16 *past_qua_en, *t_qua_gain;
+ Word16 index, *p, min_ind, size;
+ Word16 exp, frac, gcode0, exp_gcode0, e_max, exp_code, qua_ener;
+ Word16 g_pitch, g2_pitch, g_code, g_pit_cod, g2_code, g2_code_lo;
+ Word16 coeff[5], coeff_lo[5], exp_coeff[5];
+ Word16 exp_max[5];
+ Word32 i, j, L_tmp, dist_min;
+ Word16 *past_qua_en, *t_qua_gain;
- past_qua_en = mem;
+ past_qua_en = mem;
- /*-----------------------------------------------------------------*
- * - Find the initial quantization pitch index *
- * - Set gains search range *
- *-----------------------------------------------------------------*/
- if (nbits == 6)
- {
- t_qua_gain = t_qua_gain6b;
- min_ind = 0;
- size = RANGE;
+ /*-----------------------------------------------------------------*
+ * - Find the initial quantization pitch index *
+ * - Set gains search range *
+ *-----------------------------------------------------------------*/
+ if (nbits == 6)
+ {
+ t_qua_gain = t_qua_gain6b;
+ min_ind = 0;
+ size = RANGE;
- if(gp_clip == 1)
- {
- size = size - 16; /* limit gain pitch to 1.0 */
- }
- } else
- {
- t_qua_gain = t_qua_gain7b;
+ if(gp_clip == 1)
+ {
+ size = size - 16; /* limit gain pitch to 1.0 */
+ }
+ } else
+ {
+ t_qua_gain = t_qua_gain7b;
- p = t_qua_gain7b + RANGE; /* pt at 1/4th of table */
+ p = t_qua_gain7b + RANGE; /* pt at 1/4th of table */
- j = nb_qua_gain7b - RANGE;
+ j = nb_qua_gain7b - RANGE;
- if (gp_clip == 1)
- {
- j = j - 27; /* limit gain pitch to 1.0 */
- }
- min_ind = 0;
- g_pitch = *gain_pit;
+ if (gp_clip == 1)
+ {
+ j = j - 27; /* limit gain pitch to 1.0 */
+ }
+ min_ind = 0;
+ g_pitch = *gain_pit;
- for (i = 0; i < j; i++, p += 2)
- {
- if (g_pitch > *p)
- {
- min_ind = min_ind + 1;
- }
- }
- size = RANGE;
- }
+ for (i = 0; i < j; i++, p += 2)
+ {
+ if (g_pitch > *p)
+ {
+ min_ind = min_ind + 1;
+ }
+ }
+ size = RANGE;
+ }
- /*------------------------------------------------------------------*
- * Compute coefficient need for the quantization. *
- * *
- * coeff[0] = y1 y1 *
- * coeff[1] = -2 xn y1 *
- * coeff[2] = y2 y2 *
- * coeff[3] = -2 xn y2 *
- * coeff[4] = 2 y1 y2 *
- * *
- * Product <y1 y1> and <xn y1> have been compute in G_pitch() and *
- * are in vector g_coeff[]. *
- *------------------------------------------------------------------*/
+ /*------------------------------------------------------------------*
+ * Compute coefficient need for the quantization. *
+ * *
+ * coeff[0] = y1 y1 *
+ * coeff[1] = -2 xn y1 *
+ * coeff[2] = y2 y2 *
+ * coeff[3] = -2 xn y2 *
+ * coeff[4] = 2 y1 y2 *
+ * *
+ * Product <y1 y1> and <xn y1> have been compute in G_pitch() and *
+ * are in vector g_coeff[]. *
+ *------------------------------------------------------------------*/
- coeff[0] = g_coeff[0];
- exp_coeff[0] = g_coeff[1];
- coeff[1] = negate(g_coeff[2]); /* coeff[1] = -2 xn y1 */
- exp_coeff[1] = g_coeff[3] + 1;
+ coeff[0] = g_coeff[0];
+ exp_coeff[0] = g_coeff[1];
+ coeff[1] = negate(g_coeff[2]); /* coeff[1] = -2 xn y1 */
+ exp_coeff[1] = g_coeff[3] + 1;
- /* Compute scalar product <y2[],y2[]> */
+ /* Compute scalar product <y2[],y2[]> */
#ifdef ASM_OPT /* asm optimization branch */
- coeff[2] = extract_h(Dot_product12_asm(y2, y2, L_subfr, &exp));
+ coeff[2] = extract_h(Dot_product12_asm(y2, y2, L_subfr, &exp));
#else
- coeff[2] = extract_h(Dot_product12(y2, y2, L_subfr, &exp));
+ coeff[2] = extract_h(Dot_product12(y2, y2, L_subfr, &exp));
#endif
- exp_coeff[2] = (exp - 18) + (Q_xn << 1); /* -18 (y2 Q9) */
+ exp_coeff[2] = (exp - 18) + (Q_xn << 1); /* -18 (y2 Q9) */
- /* Compute scalar product -2*<xn[],y2[]> */
+ /* Compute scalar product -2*<xn[],y2[]> */
#ifdef ASM_OPT /* asm optimization branch */
- coeff[3] = extract_h(L_negate(Dot_product12_asm(xn, y2, L_subfr, &exp)));
+ coeff[3] = extract_h(L_negate(Dot_product12_asm(xn, y2, L_subfr, &exp)));
#else
- coeff[3] = extract_h(L_negate(Dot_product12(xn, y2, L_subfr, &exp)));
+ coeff[3] = extract_h(L_negate(Dot_product12(xn, y2, L_subfr, &exp)));
#endif
- exp_coeff[3] = (exp - 8) + Q_xn; /* -9 (y2 Q9), +1 (2 xn y2) */
+ exp_coeff[3] = (exp - 8) + Q_xn; /* -9 (y2 Q9), +1 (2 xn y2) */
- /* Compute scalar product 2*<y1[],y2[]> */
+ /* Compute scalar product 2*<y1[],y2[]> */
#ifdef ASM_OPT /* asm optimization branch */
- coeff[4] = extract_h(Dot_product12_asm(y1, y2, L_subfr, &exp));
+ coeff[4] = extract_h(Dot_product12_asm(y1, y2, L_subfr, &exp));
#else
- coeff[4] = extract_h(Dot_product12(y1, y2, L_subfr, &exp));
+ coeff[4] = extract_h(Dot_product12(y1, y2, L_subfr, &exp));
#endif
- exp_coeff[4] = (exp - 8) + Q_xn; /* -9 (y2 Q9), +1 (2 y1 y2) */
+ exp_coeff[4] = (exp - 8) + Q_xn; /* -9 (y2 Q9), +1 (2 y1 y2) */
- /*-----------------------------------------------------------------*
- * Find energy of code and compute: *
- * *
- * L_tmp = MEAN_ENER - 10log10(energy of code/ L_subfr) *
- * = MEAN_ENER - 3.0103*log2(energy of code/ L_subfr) *
- *-----------------------------------------------------------------*/
+ /*-----------------------------------------------------------------*
+ * Find energy of code and compute: *
+ * *
+ * L_tmp = MEAN_ENER - 10log10(energy of code/ L_subfr) *
+ * = MEAN_ENER - 3.0103*log2(energy of code/ L_subfr) *
+ *-----------------------------------------------------------------*/
#ifdef ASM_OPT /* asm optimization branch */
- L_tmp = Dot_product12_asm(code, code, L_subfr, &exp_code);
+ L_tmp = Dot_product12_asm(code, code, L_subfr, &exp_code);
#else
- L_tmp = Dot_product12(code, code, L_subfr, &exp_code);
+ L_tmp = Dot_product12(code, code, L_subfr, &exp_code);
#endif
- /* exp_code: -18 (code in Q9), -6 (/L_subfr), -31 (L_tmp Q31->Q0) */
- exp_code = (exp_code - (18 + 6 + 31));
+ /* exp_code: -18 (code in Q9), -6 (/L_subfr), -31 (L_tmp Q31->Q0) */
+ exp_code = (exp_code - (18 + 6 + 31));
- Log2(L_tmp, &exp, &frac);
- exp += exp_code;
- L_tmp = Mpy_32_16(exp, frac, -24660); /* x -3.0103(Q13) -> Q14 */
+ Log2(L_tmp, &exp, &frac);
+ exp += exp_code;
+ L_tmp = Mpy_32_16(exp, frac, -24660); /* x -3.0103(Q13) -> Q14 */
- L_tmp += (MEAN_ENER * 8192)<<1; /* + MEAN_ENER in Q14 */
+ L_tmp += (MEAN_ENER * 8192)<<1; /* + MEAN_ENER in Q14 */
- /*-----------------------------------------------------------------*
- * Compute gcode0. *
- * = Sum(i=0,1) pred[i]*past_qua_en[i] + mean_ener - ener_code *
- *-----------------------------------------------------------------*/
- L_tmp = (L_tmp << 10); /* From Q14 to Q24 */
- L_tmp += (pred[0] * past_qua_en[0])<<1; /* Q13*Q10 -> Q24 */
- L_tmp += (pred[1] * past_qua_en[1])<<1; /* Q13*Q10 -> Q24 */
- L_tmp += (pred[2] * past_qua_en[2])<<1; /* Q13*Q10 -> Q24 */
- L_tmp += (pred[3] * past_qua_en[3])<<1; /* Q13*Q10 -> Q24 */
+ /*-----------------------------------------------------------------*
+ * Compute gcode0. *
+ * = Sum(i=0,1) pred[i]*past_qua_en[i] + mean_ener - ener_code *
+ *-----------------------------------------------------------------*/
+ L_tmp = (L_tmp << 10); /* From Q14 to Q24 */
+ L_tmp += (pred[0] * past_qua_en[0])<<1; /* Q13*Q10 -> Q24 */
+ L_tmp += (pred[1] * past_qua_en[1])<<1; /* Q13*Q10 -> Q24 */
+ L_tmp += (pred[2] * past_qua_en[2])<<1; /* Q13*Q10 -> Q24 */
+ L_tmp += (pred[3] * past_qua_en[3])<<1; /* Q13*Q10 -> Q24 */
- gcode0 = extract_h(L_tmp); /* From Q24 to Q8 */
+ gcode0 = extract_h(L_tmp); /* From Q24 to Q8 */
- /*-----------------------------------------------------------------*
- * gcode0 = pow(10.0, gcode0/20) *
- * = pow(2, 3.321928*gcode0/20) *
- * = pow(2, 0.166096*gcode0) *
- *-----------------------------------------------------------------*/
+ /*-----------------------------------------------------------------*
+ * gcode0 = pow(10.0, gcode0/20) *
+ * = pow(2, 3.321928*gcode0/20) *
+ * = pow(2, 0.166096*gcode0) *
+ *-----------------------------------------------------------------*/
- L_tmp = vo_L_mult(gcode0, 5443); /* *0.166096 in Q15 -> Q24 */
- L_tmp = L_tmp >> 8; /* From Q24 to Q16 */
- VO_L_Extract(L_tmp, &exp_gcode0, &frac); /* Extract exponent of gcode0 */
+ L_tmp = vo_L_mult(gcode0, 5443); /* *0.166096 in Q15 -> Q24 */
+ L_tmp = L_tmp >> 8; /* From Q24 to Q16 */
+ VO_L_Extract(L_tmp, &exp_gcode0, &frac); /* Extract exponent of gcode0 */
- gcode0 = (Word16)(Pow2(14, frac)); /* Put 14 as exponent so that */
- /* output of Pow2() will be: */
- /* 16384 < Pow2() <= 32767 */
- exp_gcode0 -= 14;
+ gcode0 = (Word16)(Pow2(14, frac)); /* Put 14 as exponent so that */
+ /* output of Pow2() will be: */
+ /* 16384 < Pow2() <= 32767 */
+ exp_gcode0 -= 14;
- /*-------------------------------------------------------------------------*
- * Find the best quantizer *
- * ~~~~~~~~~~~~~~~~~~~~~~~ *
- * Before doing the computation we need to aling exponents of coeff[] *
- * to be sure to have the maximum precision. *
- * *
- * In the table the pitch gains are in Q14, the code gains are in Q11 and *
- * are multiply by gcode0 which have been multiply by 2^exp_gcode0. *
- * Also when we compute g_pitch*g_pitch, g_code*g_code and g_pitch*g_code *
- * we divide by 2^15. *
- * Considering all the scaling above we have: *
- * *
- * exp_code = exp_gcode0-11+15 = exp_gcode0+4 *
- * *
- * g_pitch*g_pitch = -14-14+15 *
- * g_pitch = -14 *
- * g_code*g_code = (2*exp_code)+15 *
- * g_code = exp_code *
- * g_pitch*g_code = -14 + exp_code +15 *
- * *
- * g_pitch*g_pitch * coeff[0] ;exp_max0 = exp_coeff[0] - 13 *
- * g_pitch * coeff[1] ;exp_max1 = exp_coeff[1] - 14 *
- * g_code*g_code * coeff[2] ;exp_max2 = exp_coeff[2] +15+(2*exp_code) *
- * g_code * coeff[3] ;exp_max3 = exp_coeff[3] + exp_code *
- * g_pitch*g_code * coeff[4] ;exp_max4 = exp_coeff[4] + 1 + exp_code *
- *-------------------------------------------------------------------------*/
+ /*-------------------------------------------------------------------------*
+ * Find the best quantizer *
+ * ~~~~~~~~~~~~~~~~~~~~~~~ *
+ * Before doing the computation we need to aling exponents of coeff[] *
+ * to be sure to have the maximum precision. *
+ * *
+ * In the table the pitch gains are in Q14, the code gains are in Q11 and *
+ * are multiply by gcode0 which have been multiply by 2^exp_gcode0. *
+ * Also when we compute g_pitch*g_pitch, g_code*g_code and g_pitch*g_code *
+ * we divide by 2^15. *
+ * Considering all the scaling above we have: *
+ * *
+ * exp_code = exp_gcode0-11+15 = exp_gcode0+4 *
+ * *
+ * g_pitch*g_pitch = -14-14+15 *
+ * g_pitch = -14 *
+ * g_code*g_code = (2*exp_code)+15 *
+ * g_code = exp_code *
+ * g_pitch*g_code = -14 + exp_code +15 *
+ * *
+ * g_pitch*g_pitch * coeff[0] ;exp_max0 = exp_coeff[0] - 13 *
+ * g_pitch * coeff[1] ;exp_max1 = exp_coeff[1] - 14 *
+ * g_code*g_code * coeff[2] ;exp_max2 = exp_coeff[2] +15+(2*exp_code) *
+ * g_code * coeff[3] ;exp_max3 = exp_coeff[3] + exp_code *
+ * g_pitch*g_code * coeff[4] ;exp_max4 = exp_coeff[4] + 1 + exp_code *
+ *-------------------------------------------------------------------------*/
- exp_code = (exp_gcode0 + 4);
- exp_max[0] = (exp_coeff[0] - 13);
- exp_max[1] = (exp_coeff[1] - 14);
- exp_max[2] = (exp_coeff[2] + (15 + (exp_code << 1)));
- exp_max[3] = (exp_coeff[3] + exp_code);
- exp_max[4] = (exp_coeff[4] + (1 + exp_code));
+ exp_code = (exp_gcode0 + 4);
+ exp_max[0] = (exp_coeff[0] - 13);
+ exp_max[1] = (exp_coeff[1] - 14);
+ exp_max[2] = (exp_coeff[2] + (15 + (exp_code << 1)));
+ exp_max[3] = (exp_coeff[3] + exp_code);
+ exp_max[4] = (exp_coeff[4] + (1 + exp_code));
- /* Find maximum exponant */
+ /* Find maximum exponant */
- e_max = exp_max[0];
- for (i = 1; i < 5; i++)
- {
- if(exp_max[i] > e_max)
- {
- e_max = exp_max[i];
- }
- }
+ e_max = exp_max[0];
+ for (i = 1; i < 5; i++)
+ {
+ if(exp_max[i] > e_max)
+ {
+ e_max = exp_max[i];
+ }
+ }
- /* align coeff[] and save in special 32 bit double precision */
+ /* align coeff[] and save in special 32 bit double precision */
- for (i = 0; i < 5; i++)
- {
- j = add1(vo_sub(e_max, exp_max[i]), 2);/* /4 to avoid overflow */
- L_tmp = L_deposit_h(coeff[i]);
- L_tmp = L_shr(L_tmp, j);
- VO_L_Extract(L_tmp, &coeff[i], &coeff_lo[i]);
- coeff_lo[i] = (coeff_lo[i] >> 3); /* lo >> 3 */
- }
+ for (i = 0; i < 5; i++)
+ {
+ j = add1(vo_sub(e_max, exp_max[i]), 2);/* /4 to avoid overflow */
+ L_tmp = L_deposit_h(coeff[i]);
+ L_tmp = L_shr(L_tmp, j);
+ VO_L_Extract(L_tmp, &coeff[i], &coeff_lo[i]);
+ coeff_lo[i] = (coeff_lo[i] >> 3); /* lo >> 3 */
+ }
- /* Codebook search */
- dist_min = MAX_32;
- p = &t_qua_gain[min_ind << 1];
+ /* Codebook search */
+ dist_min = MAX_32;
+ p = &t_qua_gain[min_ind << 1];
- index = 0;
- for (i = 0; i < size; i++)
- {
- g_pitch = *p++;
- g_code = *p++;
+ index = 0;
+ for (i = 0; i < size; i++)
+ {
+ g_pitch = *p++;
+ g_code = *p++;
- g_code = ((g_code * gcode0) + 0x4000)>>15;
- g2_pitch = ((g_pitch * g_pitch) + 0x4000)>>15;
- g_pit_cod = ((g_code * g_pitch) + 0x4000)>>15;
- L_tmp = (g_code * g_code)<<1;
- VO_L_Extract(L_tmp, &g2_code, &g2_code_lo);
+ g_code = ((g_code * gcode0) + 0x4000)>>15;
+ g2_pitch = ((g_pitch * g_pitch) + 0x4000)>>15;
+ g_pit_cod = ((g_code * g_pitch) + 0x4000)>>15;
+ L_tmp = (g_code * g_code)<<1;
+ VO_L_Extract(L_tmp, &g2_code, &g2_code_lo);
- L_tmp = (coeff[2] * g2_code_lo)<<1;
- L_tmp = (L_tmp >> 3);
- L_tmp += (coeff_lo[0] * g2_pitch)<<1;
- L_tmp += (coeff_lo[1] * g_pitch)<<1;
- L_tmp += (coeff_lo[2] * g2_code)<<1;
- L_tmp += (coeff_lo[3] * g_code)<<1;
- L_tmp += (coeff_lo[4] * g_pit_cod)<<1;
- L_tmp = (L_tmp >> 12);
- L_tmp += (coeff[0] * g2_pitch)<<1;
- L_tmp += (coeff[1] * g_pitch)<<1;
- L_tmp += (coeff[2] * g2_code)<<1;
- L_tmp += (coeff[3] * g_code)<<1;
- L_tmp += (coeff[4] * g_pit_cod)<<1;
+ L_tmp = (coeff[2] * g2_code_lo)<<1;
+ L_tmp = (L_tmp >> 3);
+ L_tmp += (coeff_lo[0] * g2_pitch)<<1;
+ L_tmp += (coeff_lo[1] * g_pitch)<<1;
+ L_tmp += (coeff_lo[2] * g2_code)<<1;
+ L_tmp += (coeff_lo[3] * g_code)<<1;
+ L_tmp += (coeff_lo[4] * g_pit_cod)<<1;
+ L_tmp = (L_tmp >> 12);
+ L_tmp += (coeff[0] * g2_pitch)<<1;
+ L_tmp += (coeff[1] * g_pitch)<<1;
+ L_tmp += (coeff[2] * g2_code)<<1;
+ L_tmp += (coeff[3] * g_code)<<1;
+ L_tmp += (coeff[4] * g_pit_cod)<<1;
- if(L_tmp < dist_min)
- {
- dist_min = L_tmp;
- index = i;
- }
- }
+ if(L_tmp < dist_min)
+ {
+ dist_min = L_tmp;
+ index = i;
+ }
+ }
- /* Read the quantized gains */
- index = index + min_ind;
- p = &t_qua_gain[(index + index)];
- *gain_pit = *p++; /* selected pitch gain in Q14 */
- g_code = *p++; /* selected code gain in Q11 */
+ /* Read the quantized gains */
+ index = index + min_ind;
+ p = &t_qua_gain[(index + index)];
+ *gain_pit = *p++; /* selected pitch gain in Q14 */
+ g_code = *p++; /* selected code gain in Q11 */
- L_tmp = vo_L_mult(g_code, gcode0); /* Q11*Q0 -> Q12 */
- L_tmp = L_shl(L_tmp, (exp_gcode0 + 4)); /* Q12 -> Q16 */
+ L_tmp = vo_L_mult(g_code, gcode0); /* Q11*Q0 -> Q12 */
+ L_tmp = L_shl(L_tmp, (exp_gcode0 + 4)); /* Q12 -> Q16 */
- *gain_cod = L_tmp; /* gain of code in Q16 */
+ *gain_cod = L_tmp; /* gain of code in Q16 */
- /*---------------------------------------------------*
- * qua_ener = 20*log10(g_code) *
- * = 6.0206*log2(g_code) *
- * = 6.0206*(log2(g_codeQ11) - 11) *
- *---------------------------------------------------*/
+ /*---------------------------------------------------*
+ * qua_ener = 20*log10(g_code) *
+ * = 6.0206*log2(g_code) *
+ * = 6.0206*(log2(g_codeQ11) - 11) *
+ *---------------------------------------------------*/
- L_tmp = L_deposit_l(g_code);
- Log2(L_tmp, &exp, &frac);
- exp -= 11;
- L_tmp = Mpy_32_16(exp, frac, 24660); /* x 6.0206 in Q12 */
+ L_tmp = L_deposit_l(g_code);
+ Log2(L_tmp, &exp, &frac);
+ exp -= 11;
+ L_tmp = Mpy_32_16(exp, frac, 24660); /* x 6.0206 in Q12 */
- qua_ener = (Word16)(L_tmp >> 3); /* result in Q10 */
+ qua_ener = (Word16)(L_tmp >> 3); /* result in Q10 */
- /* update table of past quantized energies */
+ /* update table of past quantized energies */
- past_qua_en[3] = past_qua_en[2];
- past_qua_en[2] = past_qua_en[1];
- past_qua_en[1] = past_qua_en[0];
- past_qua_en[0] = qua_ener;
+ past_qua_en[3] = past_qua_en[2];
+ past_qua_en[2] = past_qua_en[1];
+ past_qua_en[1] = past_qua_en[0];
+ past_qua_en[0] = qua_ener;
- return (index);
+ return (index);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/q_pulse.c b/media/libstagefright/codecs/amrwbenc/src/q_pulse.c
index d658602..fe0bdda 100644
--- a/media/libstagefright/codecs/amrwbenc/src/q_pulse.c
+++ b/media/libstagefright/codecs/amrwbenc/src/q_pulse.c
@@ -29,372 +29,372 @@
#define NB_POS 16 /* pos in track, mask for sign bit */
Word32 quant_1p_N1( /* (o) return N+1 bits */
- Word16 pos, /* (i) position of the pulse */
- Word16 N) /* (i) number of bits for position */
+ Word16 pos, /* (i) position of the pulse */
+ Word16 N) /* (i) number of bits for position */
{
- Word16 mask;
- Word32 index;
+ Word16 mask;
+ Word32 index;
- mask = (1 << N) - 1; /* mask = ((1<<N)-1); */
- /*-------------------------------------------------------*
- * Quantization of 1 pulse with N+1 bits: *
- *-------------------------------------------------------*/
- index = L_deposit_l((Word16) (pos & mask));
- if ((pos & NB_POS) != 0)
- {
- index = vo_L_add(index, L_deposit_l(1 << N)); /* index += 1 << N; */
- }
- return (index);
+ mask = (1 << N) - 1; /* mask = ((1<<N)-1); */
+ /*-------------------------------------------------------*
+ * Quantization of 1 pulse with N+1 bits: *
+ *-------------------------------------------------------*/
+ index = L_deposit_l((Word16) (pos & mask));
+ if ((pos & NB_POS) != 0)
+ {
+ index = vo_L_add(index, L_deposit_l(1 << N)); /* index += 1 << N; */
+ }
+ return (index);
}
Word32 quant_2p_2N1( /* (o) return (2*N)+1 bits */
- Word16 pos1, /* (i) position of the pulse 1 */
- Word16 pos2, /* (i) position of the pulse 2 */
- Word16 N) /* (i) number of bits for position */
+ Word16 pos1, /* (i) position of the pulse 1 */
+ Word16 pos2, /* (i) position of the pulse 2 */
+ Word16 N) /* (i) number of bits for position */
{
- Word16 mask, tmp;
- Word32 index;
- mask = (1 << N) - 1; /* mask = ((1<<N)-1); */
- /*-------------------------------------------------------*
- * Quantization of 2 pulses with 2*N+1 bits: *
- *-------------------------------------------------------*/
- if (((pos2 ^ pos1) & NB_POS) == 0)
- {
- /* sign of 1st pulse == sign of 2th pulse */
- if(pos1 <= pos2) /* ((pos1 - pos2) <= 0) */
- {
- /* index = ((pos1 & mask) << N) + (pos2 & mask); */
- index = L_deposit_l(add1((((Word16) (pos1 & mask)) << N), ((Word16) (pos2 & mask))));
- } else
- {
- /* ((pos2 & mask) << N) + (pos1 & mask); */
- index = L_deposit_l(add1((((Word16) (pos2 & mask)) << N), ((Word16) (pos1 & mask))));
- }
- if ((pos1 & NB_POS) != 0)
- {
- tmp = (N << 1);
- index = vo_L_add(index, (1L << tmp)); /* index += 1 << (2*N); */
- }
- } else
- {
- /* sign of 1st pulse != sign of 2th pulse */
- if (vo_sub((Word16) (pos1 & mask), (Word16) (pos2 & mask)) <= 0)
- {
- /* index = ((pos2 & mask) << N) + (pos1 & mask); */
- index = L_deposit_l(add1((((Word16) (pos2 & mask)) << N), ((Word16) (pos1 & mask))));
- if ((pos2 & NB_POS) != 0)
- {
- tmp = (N << 1); /* index += 1 << (2*N); */
- index = vo_L_add(index, (1L << tmp));
- }
- } else
- {
- /* index = ((pos1 & mask) << N) + (pos2 & mask); */
- index = L_deposit_l(add1((((Word16) (pos1 & mask)) << N), ((Word16) (pos2 & mask))));
- if ((pos1 & NB_POS) != 0)
- {
- tmp = (N << 1);
- index = vo_L_add(index, (1 << tmp)); /* index += 1 << (2*N); */
- }
- }
- }
- return (index);
+ Word16 mask, tmp;
+ Word32 index;
+ mask = (1 << N) - 1; /* mask = ((1<<N)-1); */
+ /*-------------------------------------------------------*
+ * Quantization of 2 pulses with 2*N+1 bits: *
+ *-------------------------------------------------------*/
+ if (((pos2 ^ pos1) & NB_POS) == 0)
+ {
+ /* sign of 1st pulse == sign of 2th pulse */
+ if(pos1 <= pos2) /* ((pos1 - pos2) <= 0) */
+ {
+ /* index = ((pos1 & mask) << N) + (pos2 & mask); */
+ index = L_deposit_l(add1((((Word16) (pos1 & mask)) << N), ((Word16) (pos2 & mask))));
+ } else
+ {
+ /* ((pos2 & mask) << N) + (pos1 & mask); */
+ index = L_deposit_l(add1((((Word16) (pos2 & mask)) << N), ((Word16) (pos1 & mask))));
+ }
+ if ((pos1 & NB_POS) != 0)
+ {
+ tmp = (N << 1);
+ index = vo_L_add(index, (1L << tmp)); /* index += 1 << (2*N); */
+ }
+ } else
+ {
+ /* sign of 1st pulse != sign of 2th pulse */
+ if (vo_sub((Word16) (pos1 & mask), (Word16) (pos2 & mask)) <= 0)
+ {
+ /* index = ((pos2 & mask) << N) + (pos1 & mask); */
+ index = L_deposit_l(add1((((Word16) (pos2 & mask)) << N), ((Word16) (pos1 & mask))));
+ if ((pos2 & NB_POS) != 0)
+ {
+ tmp = (N << 1); /* index += 1 << (2*N); */
+ index = vo_L_add(index, (1L << tmp));
+ }
+ } else
+ {
+ /* index = ((pos1 & mask) << N) + (pos2 & mask); */
+ index = L_deposit_l(add1((((Word16) (pos1 & mask)) << N), ((Word16) (pos2 & mask))));
+ if ((pos1 & NB_POS) != 0)
+ {
+ tmp = (N << 1);
+ index = vo_L_add(index, (1 << tmp)); /* index += 1 << (2*N); */
+ }
+ }
+ }
+ return (index);
}
Word32 quant_3p_3N1( /* (o) return (3*N)+1 bits */
- Word16 pos1, /* (i) position of the pulse 1 */
- Word16 pos2, /* (i) position of the pulse 2 */
- Word16 pos3, /* (i) position of the pulse 3 */
- Word16 N) /* (i) number of bits for position */
+ Word16 pos1, /* (i) position of the pulse 1 */
+ Word16 pos2, /* (i) position of the pulse 2 */
+ Word16 pos3, /* (i) position of the pulse 3 */
+ Word16 N) /* (i) number of bits for position */
{
- Word16 nb_pos;
- Word32 index;
+ Word16 nb_pos;
+ Word32 index;
- nb_pos =(1 <<(N - 1)); /* nb_pos = (1<<(N-1)); */
- /*-------------------------------------------------------*
- * Quantization of 3 pulses with 3*N+1 bits: *
- *-------------------------------------------------------*/
- if (((pos1 ^ pos2) & nb_pos) == 0)
- {
- index = quant_2p_2N1(pos1, pos2, sub(N, 1)); /* index = quant_2p_2N1(pos1, pos2, (N-1)); */
- /* index += (pos1 & nb_pos) << N; */
- index = vo_L_add(index, (L_deposit_l((Word16) (pos1 & nb_pos)) << N));
- /* index += quant_1p_N1(pos3, N) << (2*N); */
- index = vo_L_add(index, (quant_1p_N1(pos3, N)<<(N << 1)));
+ nb_pos =(1 <<(N - 1)); /* nb_pos = (1<<(N-1)); */
+ /*-------------------------------------------------------*
+ * Quantization of 3 pulses with 3*N+1 bits: *
+ *-------------------------------------------------------*/
+ if (((pos1 ^ pos2) & nb_pos) == 0)
+ {
+ index = quant_2p_2N1(pos1, pos2, sub(N, 1)); /* index = quant_2p_2N1(pos1, pos2, (N-1)); */
+ /* index += (pos1 & nb_pos) << N; */
+ index = vo_L_add(index, (L_deposit_l((Word16) (pos1 & nb_pos)) << N));
+ /* index += quant_1p_N1(pos3, N) << (2*N); */
+ index = vo_L_add(index, (quant_1p_N1(pos3, N)<<(N << 1)));
- } else if (((pos1 ^ pos3) & nb_pos) == 0)
- {
- index = quant_2p_2N1(pos1, pos3, sub(N, 1)); /* index = quant_2p_2N1(pos1, pos3, (N-1)); */
- index = vo_L_add(index, (L_deposit_l((Word16) (pos1 & nb_pos)) << N));
- /* index += (pos1 & nb_pos) << N; */
- index = vo_L_add(index, (quant_1p_N1(pos2, N) << (N << 1)));
- /* index += quant_1p_N1(pos2, N) <<
- * (2*N); */
- } else
- {
- index = quant_2p_2N1(pos2, pos3, (N - 1)); /* index = quant_2p_2N1(pos2, pos3, (N-1)); */
- /* index += (pos2 & nb_pos) << N; */
- index = vo_L_add(index, (L_deposit_l((Word16) (pos2 & nb_pos)) << N));
- /* index += quant_1p_N1(pos1, N) << (2*N); */
- index = vo_L_add(index, (quant_1p_N1(pos1, N) << (N << 1)));
- }
- return (index);
+ } else if (((pos1 ^ pos3) & nb_pos) == 0)
+ {
+ index = quant_2p_2N1(pos1, pos3, sub(N, 1)); /* index = quant_2p_2N1(pos1, pos3, (N-1)); */
+ index = vo_L_add(index, (L_deposit_l((Word16) (pos1 & nb_pos)) << N));
+ /* index += (pos1 & nb_pos) << N; */
+ index = vo_L_add(index, (quant_1p_N1(pos2, N) << (N << 1)));
+ /* index += quant_1p_N1(pos2, N) <<
+ * (2*N); */
+ } else
+ {
+ index = quant_2p_2N1(pos2, pos3, (N - 1)); /* index = quant_2p_2N1(pos2, pos3, (N-1)); */
+ /* index += (pos2 & nb_pos) << N; */
+ index = vo_L_add(index, (L_deposit_l((Word16) (pos2 & nb_pos)) << N));
+ /* index += quant_1p_N1(pos1, N) << (2*N); */
+ index = vo_L_add(index, (quant_1p_N1(pos1, N) << (N << 1)));
+ }
+ return (index);
}
Word32 quant_4p_4N1( /* (o) return (4*N)+1 bits */
- Word16 pos1, /* (i) position of the pulse 1 */
- Word16 pos2, /* (i) position of the pulse 2 */
- Word16 pos3, /* (i) position of the pulse 3 */
- Word16 pos4, /* (i) position of the pulse 4 */
- Word16 N) /* (i) number of bits for position */
+ Word16 pos1, /* (i) position of the pulse 1 */
+ Word16 pos2, /* (i) position of the pulse 2 */
+ Word16 pos3, /* (i) position of the pulse 3 */
+ Word16 pos4, /* (i) position of the pulse 4 */
+ Word16 N) /* (i) number of bits for position */
{
- Word16 nb_pos;
- Word32 index;
+ Word16 nb_pos;
+ Word32 index;
- nb_pos = 1 << (N - 1); /* nb_pos = (1<<(N-1)); */
- /*-------------------------------------------------------*
- * Quantization of 4 pulses with 4*N+1 bits: *
- *-------------------------------------------------------*/
- if (((pos1 ^ pos2) & nb_pos) == 0)
- {
- index = quant_2p_2N1(pos1, pos2, sub(N, 1)); /* index = quant_2p_2N1(pos1, pos2, (N-1)); */
- /* index += (pos1 & nb_pos) << N; */
- index = vo_L_add(index, (L_deposit_l((Word16) (pos1 & nb_pos)) << N));
- /* index += quant_2p_2N1(pos3, pos4, N) << (2*N); */
- index = vo_L_add(index, (quant_2p_2N1(pos3, pos4, N) << (N << 1)));
- } else if (((pos1 ^ pos3) & nb_pos) == 0)
- {
- index = quant_2p_2N1(pos1, pos3, (N - 1));
- /* index += (pos1 & nb_pos) << N; */
- index = vo_L_add(index, (L_deposit_l((Word16) (pos1 & nb_pos)) << N));
- /* index += quant_2p_2N1(pos2, pos4, N) << (2*N); */
- index = vo_L_add(index, (quant_2p_2N1(pos2, pos4, N) << (N << 1)));
- } else
- {
- index = quant_2p_2N1(pos2, pos3, (N - 1));
- /* index += (pos2 & nb_pos) << N; */
- index = vo_L_add(index, (L_deposit_l((Word16) (pos2 & nb_pos)) << N));
- /* index += quant_2p_2N1(pos1, pos4, N) << (2*N); */
- index = vo_L_add(index, (quant_2p_2N1(pos1, pos4, N) << (N << 1)));
- }
- return (index);
+ nb_pos = 1 << (N - 1); /* nb_pos = (1<<(N-1)); */
+ /*-------------------------------------------------------*
+ * Quantization of 4 pulses with 4*N+1 bits: *
+ *-------------------------------------------------------*/
+ if (((pos1 ^ pos2) & nb_pos) == 0)
+ {
+ index = quant_2p_2N1(pos1, pos2, sub(N, 1)); /* index = quant_2p_2N1(pos1, pos2, (N-1)); */
+ /* index += (pos1 & nb_pos) << N; */
+ index = vo_L_add(index, (L_deposit_l((Word16) (pos1 & nb_pos)) << N));
+ /* index += quant_2p_2N1(pos3, pos4, N) << (2*N); */
+ index = vo_L_add(index, (quant_2p_2N1(pos3, pos4, N) << (N << 1)));
+ } else if (((pos1 ^ pos3) & nb_pos) == 0)
+ {
+ index = quant_2p_2N1(pos1, pos3, (N - 1));
+ /* index += (pos1 & nb_pos) << N; */
+ index = vo_L_add(index, (L_deposit_l((Word16) (pos1 & nb_pos)) << N));
+ /* index += quant_2p_2N1(pos2, pos4, N) << (2*N); */
+ index = vo_L_add(index, (quant_2p_2N1(pos2, pos4, N) << (N << 1)));
+ } else
+ {
+ index = quant_2p_2N1(pos2, pos3, (N - 1));
+ /* index += (pos2 & nb_pos) << N; */
+ index = vo_L_add(index, (L_deposit_l((Word16) (pos2 & nb_pos)) << N));
+ /* index += quant_2p_2N1(pos1, pos4, N) << (2*N); */
+ index = vo_L_add(index, (quant_2p_2N1(pos1, pos4, N) << (N << 1)));
+ }
+ return (index);
}
Word32 quant_4p_4N( /* (o) return 4*N bits */
- Word16 pos[], /* (i) position of the pulse 1..4 */
- Word16 N) /* (i) number of bits for position */
+ Word16 pos[], /* (i) position of the pulse 1..4 */
+ Word16 N) /* (i) number of bits for position */
{
- Word16 nb_pos, mask __unused, n_1, tmp;
- Word16 posA[4], posB[4];
- Word32 i, j, k, index;
+ Word16 nb_pos, mask __unused, n_1, tmp;
+ Word16 posA[4], posB[4];
+ Word32 i, j, k, index;
- n_1 = (Word16) (N - 1);
- nb_pos = (1 << n_1); /* nb_pos = (1<<n_1); */
- mask = vo_sub((1 << N), 1); /* mask = ((1<<N)-1); */
+ n_1 = (Word16) (N - 1);
+ nb_pos = (1 << n_1); /* nb_pos = (1<<n_1); */
+ mask = vo_sub((1 << N), 1); /* mask = ((1<<N)-1); */
- i = 0;
- j = 0;
- for (k = 0; k < 4; k++)
- {
- if ((pos[k] & nb_pos) == 0)
- {
- posA[i++] = pos[k];
- } else
- {
- posB[j++] = pos[k];
- }
- }
+ i = 0;
+ j = 0;
+ for (k = 0; k < 4; k++)
+ {
+ if ((pos[k] & nb_pos) == 0)
+ {
+ posA[i++] = pos[k];
+ } else
+ {
+ posB[j++] = pos[k];
+ }
+ }
- switch (i)
- {
- case 0:
- tmp = vo_sub((N << 2), 3); /* index = 1 << ((4*N)-3); */
- index = (1L << tmp);
- /* index += quant_4p_4N1(posB[0], posB[1], posB[2], posB[3], n_1); */
- index = vo_L_add(index, quant_4p_4N1(posB[0], posB[1], posB[2], posB[3], n_1));
- break;
- case 1:
- /* index = quant_1p_N1(posA[0], n_1) << ((3*n_1)+1); */
- tmp = add1((Word16)((vo_L_mult(3, n_1) >> 1)), 1);
- index = L_shl(quant_1p_N1(posA[0], n_1), tmp);
- /* index += quant_3p_3N1(posB[0], posB[1], posB[2], n_1); */
- index = vo_L_add(index, quant_3p_3N1(posB[0], posB[1], posB[2], n_1));
- break;
- case 2:
- tmp = ((n_1 << 1) + 1); /* index = quant_2p_2N1(posA[0], posA[1], n_1) << ((2*n_1)+1); */
- index = L_shl(quant_2p_2N1(posA[0], posA[1], n_1), tmp);
- /* index += quant_2p_2N1(posB[0], posB[1], n_1); */
- index = vo_L_add(index, quant_2p_2N1(posB[0], posB[1], n_1));
- break;
- case 3:
- /* index = quant_3p_3N1(posA[0], posA[1], posA[2], n_1) << N; */
- index = L_shl(quant_3p_3N1(posA[0], posA[1], posA[2], n_1), N);
- index = vo_L_add(index, quant_1p_N1(posB[0], n_1)); /* index += quant_1p_N1(posB[0], n_1); */
- break;
- case 4:
- index = quant_4p_4N1(posA[0], posA[1], posA[2], posA[3], n_1);
- break;
- default:
- index = 0;
- fprintf(stderr, "Error in function quant_4p_4N\n");
- }
- tmp = ((N << 2) - 2); /* index += (i & 3) << ((4*N)-2); */
- index = vo_L_add(index, L_shl((L_deposit_l(i) & (3L)), tmp));
+ switch (i)
+ {
+ case 0:
+ tmp = vo_sub((N << 2), 3); /* index = 1 << ((4*N)-3); */
+ index = (1L << tmp);
+ /* index += quant_4p_4N1(posB[0], posB[1], posB[2], posB[3], n_1); */
+ index = vo_L_add(index, quant_4p_4N1(posB[0], posB[1], posB[2], posB[3], n_1));
+ break;
+ case 1:
+ /* index = quant_1p_N1(posA[0], n_1) << ((3*n_1)+1); */
+ tmp = add1((Word16)((vo_L_mult(3, n_1) >> 1)), 1);
+ index = L_shl(quant_1p_N1(posA[0], n_1), tmp);
+ /* index += quant_3p_3N1(posB[0], posB[1], posB[2], n_1); */
+ index = vo_L_add(index, quant_3p_3N1(posB[0], posB[1], posB[2], n_1));
+ break;
+ case 2:
+ tmp = ((n_1 << 1) + 1); /* index = quant_2p_2N1(posA[0], posA[1], n_1) << ((2*n_1)+1); */
+ index = L_shl(quant_2p_2N1(posA[0], posA[1], n_1), tmp);
+ /* index += quant_2p_2N1(posB[0], posB[1], n_1); */
+ index = vo_L_add(index, quant_2p_2N1(posB[0], posB[1], n_1));
+ break;
+ case 3:
+ /* index = quant_3p_3N1(posA[0], posA[1], posA[2], n_1) << N; */
+ index = L_shl(quant_3p_3N1(posA[0], posA[1], posA[2], n_1), N);
+ index = vo_L_add(index, quant_1p_N1(posB[0], n_1)); /* index += quant_1p_N1(posB[0], n_1); */
+ break;
+ case 4:
+ index = quant_4p_4N1(posA[0], posA[1], posA[2], posA[3], n_1);
+ break;
+ default:
+ index = 0;
+ fprintf(stderr, "Error in function quant_4p_4N\n");
+ }
+ tmp = ((N << 2) - 2); /* index += (i & 3) << ((4*N)-2); */
+ index = vo_L_add(index, L_shl((L_deposit_l(i) & (3L)), tmp));
- return (index);
+ return (index);
}
Word32 quant_5p_5N( /* (o) return 5*N bits */
- Word16 pos[], /* (i) position of the pulse 1..5 */
- Word16 N) /* (i) number of bits for position */
+ Word16 pos[], /* (i) position of the pulse 1..5 */
+ Word16 N) /* (i) number of bits for position */
{
- Word16 nb_pos, n_1, tmp;
- Word16 posA[5], posB[5];
- Word32 i, j, k, index, tmp2;
+ Word16 nb_pos, n_1, tmp;
+ Word16 posA[5], posB[5];
+ Word32 i, j, k, index, tmp2;
- n_1 = (Word16) (N - 1);
- nb_pos = (1 << n_1); /* nb_pos = (1<<n_1); */
+ n_1 = (Word16) (N - 1);
+ nb_pos = (1 << n_1); /* nb_pos = (1<<n_1); */
- i = 0;
- j = 0;
- for (k = 0; k < 5; k++)
- {
- if ((pos[k] & nb_pos) == 0)
- {
- posA[i++] = pos[k];
- } else
- {
- posB[j++] = pos[k];
- }
- }
+ i = 0;
+ j = 0;
+ for (k = 0; k < 5; k++)
+ {
+ if ((pos[k] & nb_pos) == 0)
+ {
+ posA[i++] = pos[k];
+ } else
+ {
+ posB[j++] = pos[k];
+ }
+ }
- switch (i)
- {
- case 0:
- tmp = vo_sub((Word16)((vo_L_mult(5, N) >> 1)), 1); /* ((5*N)-1)) */
- index = L_shl(1L, tmp); /* index = 1 << ((5*N)-1); */
- tmp = add1((N << 1), 1); /* index += quant_3p_3N1(posB[0], posB[1], posB[2], n_1) << ((2*N)+1);*/
- tmp2 = L_shl(quant_3p_3N1(posB[0], posB[1], posB[2], n_1), tmp);
- index = vo_L_add(index, tmp2);
- index = vo_L_add(index, quant_2p_2N1(posB[3], posB[4], N)); /* index += quant_2p_2N1(posB[3], posB[4], N); */
- break;
- case 1:
- tmp = vo_sub((Word16)((vo_L_mult(5, N) >> 1)), 1); /* index = 1 << ((5*N)-1); */
- index = L_shl(1L, tmp);
- tmp = add1((N << 1), 1); /* index += quant_3p_3N1(posB[0], posB[1], posB[2], n_1) <<((2*N)+1); */
- tmp2 = L_shl(quant_3p_3N1(posB[0], posB[1], posB[2], n_1), tmp);
- index = vo_L_add(index, tmp2);
- index = vo_L_add(index, quant_2p_2N1(posB[3], posA[0], N)); /* index += quant_2p_2N1(posB[3], posA[0], N); */
- break;
- case 2:
- tmp = vo_sub((Word16)((vo_L_mult(5, N) >> 1)), 1); /* ((5*N)-1)) */
- index = L_shl(1L, tmp); /* index = 1 << ((5*N)-1); */
- tmp = add1((N << 1), 1); /* index += quant_3p_3N1(posB[0], posB[1], posB[2], n_1) << ((2*N)+1); */
- tmp2 = L_shl(quant_3p_3N1(posB[0], posB[1], posB[2], n_1), tmp);
- index = vo_L_add(index, tmp2);
- index = vo_L_add(index, quant_2p_2N1(posA[0], posA[1], N)); /* index += quant_2p_2N1(posA[0], posA[1], N); */
- break;
- case 3:
- tmp = add1((N << 1), 1); /* index = quant_3p_3N1(posA[0], posA[1], posA[2], n_1) << ((2*N)+1); */
- index = L_shl(quant_3p_3N1(posA[0], posA[1], posA[2], n_1), tmp);
- index = vo_L_add(index, quant_2p_2N1(posB[0], posB[1], N)); /* index += quant_2p_2N1(posB[0], posB[1], N); */
- break;
- case 4:
- tmp = add1((N << 1), 1); /* index = quant_3p_3N1(posA[0], posA[1], posA[2], n_1) << ((2*N)+1); */
- index = L_shl(quant_3p_3N1(posA[0], posA[1], posA[2], n_1), tmp);
- index = vo_L_add(index, quant_2p_2N1(posA[3], posB[0], N)); /* index += quant_2p_2N1(posA[3], posB[0], N); */
- break;
- case 5:
- tmp = add1((N << 1), 1); /* index = quant_3p_3N1(posA[0], posA[1], posA[2], n_1) << ((2*N)+1); */
- index = L_shl(quant_3p_3N1(posA[0], posA[1], posA[2], n_1), tmp);
- index = vo_L_add(index, quant_2p_2N1(posA[3], posA[4], N)); /* index += quant_2p_2N1(posA[3], posA[4], N); */
- break;
- default:
- index = 0;
- fprintf(stderr, "Error in function quant_5p_5N\n");
- }
+ switch (i)
+ {
+ case 0:
+ tmp = vo_sub((Word16)((vo_L_mult(5, N) >> 1)), 1); /* ((5*N)-1)) */
+ index = L_shl(1L, tmp); /* index = 1 << ((5*N)-1); */
+ tmp = add1((N << 1), 1); /* index += quant_3p_3N1(posB[0], posB[1], posB[2], n_1) << ((2*N)+1);*/
+ tmp2 = L_shl(quant_3p_3N1(posB[0], posB[1], posB[2], n_1), tmp);
+ index = vo_L_add(index, tmp2);
+ index = vo_L_add(index, quant_2p_2N1(posB[3], posB[4], N)); /* index += quant_2p_2N1(posB[3], posB[4], N); */
+ break;
+ case 1:
+ tmp = vo_sub((Word16)((vo_L_mult(5, N) >> 1)), 1); /* index = 1 << ((5*N)-1); */
+ index = L_shl(1L, tmp);
+ tmp = add1((N << 1), 1); /* index += quant_3p_3N1(posB[0], posB[1], posB[2], n_1) <<((2*N)+1); */
+ tmp2 = L_shl(quant_3p_3N1(posB[0], posB[1], posB[2], n_1), tmp);
+ index = vo_L_add(index, tmp2);
+ index = vo_L_add(index, quant_2p_2N1(posB[3], posA[0], N)); /* index += quant_2p_2N1(posB[3], posA[0], N); */
+ break;
+ case 2:
+ tmp = vo_sub((Word16)((vo_L_mult(5, N) >> 1)), 1); /* ((5*N)-1)) */
+ index = L_shl(1L, tmp); /* index = 1 << ((5*N)-1); */
+ tmp = add1((N << 1), 1); /* index += quant_3p_3N1(posB[0], posB[1], posB[2], n_1) << ((2*N)+1); */
+ tmp2 = L_shl(quant_3p_3N1(posB[0], posB[1], posB[2], n_1), tmp);
+ index = vo_L_add(index, tmp2);
+ index = vo_L_add(index, quant_2p_2N1(posA[0], posA[1], N)); /* index += quant_2p_2N1(posA[0], posA[1], N); */
+ break;
+ case 3:
+ tmp = add1((N << 1), 1); /* index = quant_3p_3N1(posA[0], posA[1], posA[2], n_1) << ((2*N)+1); */
+ index = L_shl(quant_3p_3N1(posA[0], posA[1], posA[2], n_1), tmp);
+ index = vo_L_add(index, quant_2p_2N1(posB[0], posB[1], N)); /* index += quant_2p_2N1(posB[0], posB[1], N); */
+ break;
+ case 4:
+ tmp = add1((N << 1), 1); /* index = quant_3p_3N1(posA[0], posA[1], posA[2], n_1) << ((2*N)+1); */
+ index = L_shl(quant_3p_3N1(posA[0], posA[1], posA[2], n_1), tmp);
+ index = vo_L_add(index, quant_2p_2N1(posA[3], posB[0], N)); /* index += quant_2p_2N1(posA[3], posB[0], N); */
+ break;
+ case 5:
+ tmp = add1((N << 1), 1); /* index = quant_3p_3N1(posA[0], posA[1], posA[2], n_1) << ((2*N)+1); */
+ index = L_shl(quant_3p_3N1(posA[0], posA[1], posA[2], n_1), tmp);
+ index = vo_L_add(index, quant_2p_2N1(posA[3], posA[4], N)); /* index += quant_2p_2N1(posA[3], posA[4], N); */
+ break;
+ default:
+ index = 0;
+ fprintf(stderr, "Error in function quant_5p_5N\n");
+ }
- return (index);
+ return (index);
}
Word32 quant_6p_6N_2( /* (o) return (6*N)-2 bits */
- Word16 pos[], /* (i) position of the pulse 1..6 */
- Word16 N) /* (i) number of bits for position */
+ Word16 pos[], /* (i) position of the pulse 1..6 */
+ Word16 N) /* (i) number of bits for position */
{
- Word16 nb_pos, n_1;
- Word16 posA[6], posB[6];
- Word32 i, j, k, index;
+ Word16 nb_pos, n_1;
+ Word16 posA[6], posB[6];
+ Word32 i, j, k, index;
- /* !! N and n_1 are constants -> it doesn't need to be operated by Basic Operators */
- n_1 = (Word16) (N - 1);
- nb_pos = (1 << n_1); /* nb_pos = (1<<n_1); */
+ /* !! N and n_1 are constants -> it doesn't need to be operated by Basic Operators */
+ n_1 = (Word16) (N - 1);
+ nb_pos = (1 << n_1); /* nb_pos = (1<<n_1); */
- i = 0;
- j = 0;
- for (k = 0; k < 6; k++)
- {
- if ((pos[k] & nb_pos) == 0)
- {
- posA[i++] = pos[k];
- } else
- {
- posB[j++] = pos[k];
- }
- }
+ i = 0;
+ j = 0;
+ for (k = 0; k < 6; k++)
+ {
+ if ((pos[k] & nb_pos) == 0)
+ {
+ posA[i++] = pos[k];
+ } else
+ {
+ posB[j++] = pos[k];
+ }
+ }
- switch (i)
- {
- case 0:
- index = (1 << (Word16) (6 * N - 5)); /* index = 1 << ((6*N)-5); */
- index = vo_L_add(index, (quant_5p_5N(posB, n_1) << N)); /* index += quant_5p_5N(posB, n_1) << N; */
- index = vo_L_add(index, quant_1p_N1(posB[5], n_1)); /* index += quant_1p_N1(posB[5], n_1); */
- break;
- case 1:
- index = (1L << (Word16) (6 * N - 5)); /* index = 1 << ((6*N)-5); */
- index = vo_L_add(index, (quant_5p_5N(posB, n_1) << N)); /* index += quant_5p_5N(posB, n_1) << N; */
- index = vo_L_add(index, quant_1p_N1(posA[0], n_1)); /* index += quant_1p_N1(posA[0], n_1); */
- break;
- case 2:
- index = (1L << (Word16) (6 * N - 5)); /* index = 1 << ((6*N)-5); */
- /* index += quant_4p_4N(posB, n_1) << ((2*n_1)+1); */
- index = vo_L_add(index, (quant_4p_4N(posB, n_1) << (Word16) (2 * n_1 + 1)));
- index = vo_L_add(index, quant_2p_2N1(posA[0], posA[1], n_1)); /* index += quant_2p_2N1(posA[0], posA[1], n_1); */
- break;
- case 3:
- index = (quant_3p_3N1(posA[0], posA[1], posA[2], n_1) << (Word16) (3 * n_1 + 1));
- /* index = quant_3p_3N1(posA[0], posA[1], posA[2], n_1) << ((3*n_1)+1); */
- index =vo_L_add(index, quant_3p_3N1(posB[0], posB[1], posB[2], n_1));
- /* index += quant_3p_3N1(posB[0], posB[1], posB[2], n_1); */
- break;
- case 4:
- i = 2;
- index = (quant_4p_4N(posA, n_1) << (Word16) (2 * n_1 + 1)); /* index = quant_4p_4N(posA, n_1) << ((2*n_1)+1); */
- index = vo_L_add(index, quant_2p_2N1(posB[0], posB[1], n_1)); /* index += quant_2p_2N1(posB[0], posB[1], n_1); */
- break;
- case 5:
- i = 1;
- index = (quant_5p_5N(posA, n_1) << N); /* index = quant_5p_5N(posA, n_1) << N; */
- index = vo_L_add(index, quant_1p_N1(posB[0], n_1)); /* index += quant_1p_N1(posB[0], n_1); */
- break;
- case 6:
- i = 0;
- index = (quant_5p_5N(posA, n_1) << N); /* index = quant_5p_5N(posA, n_1) << N; */
- index = vo_L_add(index, quant_1p_N1(posA[5], n_1)); /* index += quant_1p_N1(posA[5], n_1); */
- break;
- default:
- index = 0;
- fprintf(stderr, "Error in function quant_6p_6N_2\n");
- }
- index = vo_L_add(index, ((L_deposit_l(i) & 3L) << (Word16) (6 * N - 4))); /* index += (i & 3) << ((6*N)-4); */
+ switch (i)
+ {
+ case 0:
+ index = (1 << (Word16) (6 * N - 5)); /* index = 1 << ((6*N)-5); */
+ index = vo_L_add(index, (quant_5p_5N(posB, n_1) << N)); /* index += quant_5p_5N(posB, n_1) << N; */
+ index = vo_L_add(index, quant_1p_N1(posB[5], n_1)); /* index += quant_1p_N1(posB[5], n_1); */
+ break;
+ case 1:
+ index = (1L << (Word16) (6 * N - 5)); /* index = 1 << ((6*N)-5); */
+ index = vo_L_add(index, (quant_5p_5N(posB, n_1) << N)); /* index += quant_5p_5N(posB, n_1) << N; */
+ index = vo_L_add(index, quant_1p_N1(posA[0], n_1)); /* index += quant_1p_N1(posA[0], n_1); */
+ break;
+ case 2:
+ index = (1L << (Word16) (6 * N - 5)); /* index = 1 << ((6*N)-5); */
+ /* index += quant_4p_4N(posB, n_1) << ((2*n_1)+1); */
+ index = vo_L_add(index, (quant_4p_4N(posB, n_1) << (Word16) (2 * n_1 + 1)));
+ index = vo_L_add(index, quant_2p_2N1(posA[0], posA[1], n_1)); /* index += quant_2p_2N1(posA[0], posA[1], n_1); */
+ break;
+ case 3:
+ index = (quant_3p_3N1(posA[0], posA[1], posA[2], n_1) << (Word16) (3 * n_1 + 1));
+ /* index = quant_3p_3N1(posA[0], posA[1], posA[2], n_1) << ((3*n_1)+1); */
+ index =vo_L_add(index, quant_3p_3N1(posB[0], posB[1], posB[2], n_1));
+ /* index += quant_3p_3N1(posB[0], posB[1], posB[2], n_1); */
+ break;
+ case 4:
+ i = 2;
+ index = (quant_4p_4N(posA, n_1) << (Word16) (2 * n_1 + 1)); /* index = quant_4p_4N(posA, n_1) << ((2*n_1)+1); */
+ index = vo_L_add(index, quant_2p_2N1(posB[0], posB[1], n_1)); /* index += quant_2p_2N1(posB[0], posB[1], n_1); */
+ break;
+ case 5:
+ i = 1;
+ index = (quant_5p_5N(posA, n_1) << N); /* index = quant_5p_5N(posA, n_1) << N; */
+ index = vo_L_add(index, quant_1p_N1(posB[0], n_1)); /* index += quant_1p_N1(posB[0], n_1); */
+ break;
+ case 6:
+ i = 0;
+ index = (quant_5p_5N(posA, n_1) << N); /* index = quant_5p_5N(posA, n_1) << N; */
+ index = vo_L_add(index, quant_1p_N1(posA[5], n_1)); /* index += quant_1p_N1(posA[5], n_1); */
+ break;
+ default:
+ index = 0;
+ fprintf(stderr, "Error in function quant_6p_6N_2\n");
+ }
+ index = vo_L_add(index, ((L_deposit_l(i) & 3L) << (Word16) (6 * N - 4))); /* index += (i & 3) << ((6*N)-4); */
- return (index);
+ return (index);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/qisf_ns.c b/media/libstagefright/codecs/amrwbenc/src/qisf_ns.c
index fc2f00d..eac98e2 100644
--- a/media/libstagefright/codecs/amrwbenc/src/qisf_ns.c
+++ b/media/libstagefright/codecs/amrwbenc/src/qisf_ns.c
@@ -33,30 +33,30 @@
*------------------------------------------------------------------*/
void Qisf_ns(
- Word16 * isf1, /* input : ISF in the frequency domain (0..0.5) */
- Word16 * isf_q, /* output: quantized ISF */
- Word16 * indice /* output: quantization indices */
- )
+ Word16 * isf1, /* input : ISF in the frequency domain (0..0.5) */
+ Word16 * isf_q, /* output: quantized ISF */
+ Word16 * indice /* output: quantization indices */
+ )
{
- Word16 i;
- Word32 tmp;
+ Word16 i;
+ Word32 tmp;
- for (i = 0; i < ORDER; i++)
- {
- isf_q[i] = sub(isf1[i], mean_isf_noise[i]);
- }
+ for (i = 0; i < ORDER; i++)
+ {
+ isf_q[i] = sub(isf1[i], mean_isf_noise[i]);
+ }
- indice[0] = Sub_VQ(&isf_q[0], dico1_isf_noise, 2, SIZE_BK_NOISE1, &tmp);
- indice[1] = Sub_VQ(&isf_q[2], dico2_isf_noise, 3, SIZE_BK_NOISE2, &tmp);
- indice[2] = Sub_VQ(&isf_q[5], dico3_isf_noise, 3, SIZE_BK_NOISE3, &tmp);
- indice[3] = Sub_VQ(&isf_q[8], dico4_isf_noise, 4, SIZE_BK_NOISE4, &tmp);
- indice[4] = Sub_VQ(&isf_q[12], dico5_isf_noise, 4, SIZE_BK_NOISE5, &tmp);
+ indice[0] = Sub_VQ(&isf_q[0], dico1_isf_noise, 2, SIZE_BK_NOISE1, &tmp);
+ indice[1] = Sub_VQ(&isf_q[2], dico2_isf_noise, 3, SIZE_BK_NOISE2, &tmp);
+ indice[2] = Sub_VQ(&isf_q[5], dico3_isf_noise, 3, SIZE_BK_NOISE3, &tmp);
+ indice[3] = Sub_VQ(&isf_q[8], dico4_isf_noise, 4, SIZE_BK_NOISE4, &tmp);
+ indice[4] = Sub_VQ(&isf_q[12], dico5_isf_noise, 4, SIZE_BK_NOISE5, &tmp);
- /* decoding the ISFs */
+ /* decoding the ISFs */
- Disf_ns(indice, isf_q);
+ Disf_ns(indice, isf_q);
- return;
+ return;
}
/********************************************************************
@@ -70,41 +70,41 @@
*********************************************************************/
void Disf_ns(
- Word16 * indice, /* input: quantization indices */
- Word16 * isf_q /* input : ISF in the frequency domain (0..0.5) */
- )
+ Word16 * indice, /* input: quantization indices */
+ Word16 * isf_q /* input : ISF in the frequency domain (0..0.5) */
+ )
{
- Word16 i;
+ Word16 i;
- for (i = 0; i < 2; i++)
- {
- isf_q[i] = dico1_isf_noise[indice[0] * 2 + i];
- }
- for (i = 0; i < 3; i++)
- {
- isf_q[i + 2] = dico2_isf_noise[indice[1] * 3 + i];
- }
- for (i = 0; i < 3; i++)
- {
- isf_q[i + 5] = dico3_isf_noise[indice[2] * 3 + i];
- }
- for (i = 0; i < 4; i++)
- {
- isf_q[i + 8] = dico4_isf_noise[indice[3] * 4 + i];
- }
- for (i = 0; i < 4; i++)
- {
- isf_q[i + 12] = dico5_isf_noise[indice[4] * 4 + i];
- }
+ for (i = 0; i < 2; i++)
+ {
+ isf_q[i] = dico1_isf_noise[indice[0] * 2 + i];
+ }
+ for (i = 0; i < 3; i++)
+ {
+ isf_q[i + 2] = dico2_isf_noise[indice[1] * 3 + i];
+ }
+ for (i = 0; i < 3; i++)
+ {
+ isf_q[i + 5] = dico3_isf_noise[indice[2] * 3 + i];
+ }
+ for (i = 0; i < 4; i++)
+ {
+ isf_q[i + 8] = dico4_isf_noise[indice[3] * 4 + i];
+ }
+ for (i = 0; i < 4; i++)
+ {
+ isf_q[i + 12] = dico5_isf_noise[indice[4] * 4 + i];
+ }
- for (i = 0; i < ORDER; i++)
- {
- isf_q[i] = add(isf_q[i], mean_isf_noise[i]);
- }
+ for (i = 0; i < ORDER; i++)
+ {
+ isf_q[i] = add(isf_q[i], mean_isf_noise[i]);
+ }
- Reorder_isf(isf_q, ISF_GAP, ORDER);
+ Reorder_isf(isf_q, ISF_GAP, ORDER);
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/qpisf_2s.c b/media/libstagefright/codecs/amrwbenc/src/qpisf_2s.c
index c711cd0..bec334e 100644
--- a/media/libstagefright/codecs/amrwbenc/src/qpisf_2s.c
+++ b/media/libstagefright/codecs/amrwbenc/src/qpisf_2s.c
@@ -36,13 +36,13 @@
/* private functions */
static void VQ_stage1(
- Word16 * x, /* input : ISF residual vector */
- Word16 * dico, /* input : quantization codebook */
- Word16 dim, /* input : dimention of vector */
- Word16 dico_size, /* input : size of quantization codebook */
- Word16 * index, /* output: indices of survivors */
- Word16 surv /* input : number of survivor */
- );
+ Word16 * x, /* input : ISF residual vector */
+ Word16 * dico, /* input : quantization codebook */
+ Word16 dim, /* input : dimention of vector */
+ Word16 dico_size, /* input : size of quantization codebook */
+ Word16 * index, /* output: indices of survivors */
+ Word16 surv /* input : number of survivor */
+ );
/**************************************************************************
* Function: Qpisf_2s_46B() *
@@ -54,84 +54,84 @@
***************************************************************************/
void Qpisf_2s_46b(
- Word16 * isf1, /* (i) Q15 : ISF in the frequency domain (0..0.5) */
- Word16 * isf_q, /* (o) Q15 : quantized ISF (0..0.5) */
- Word16 * past_isfq, /* (io)Q15 : past ISF quantizer */
- Word16 * indice, /* (o) : quantization indices */
- Word16 nb_surv /* (i) : number of survivor (1, 2, 3 or 4) */
- )
+ Word16 * isf1, /* (i) Q15 : ISF in the frequency domain (0..0.5) */
+ Word16 * isf_q, /* (o) Q15 : quantized ISF (0..0.5) */
+ Word16 * past_isfq, /* (io)Q15 : past ISF quantizer */
+ Word16 * indice, /* (o) : quantization indices */
+ Word16 nb_surv /* (i) : number of survivor (1, 2, 3 or 4) */
+ )
{
- Word16 tmp_ind[5];
- Word16 surv1[N_SURV_MAX]; /* indices of survivors from 1st stage */
- Word32 i, k, temp, min_err, distance;
- Word16 isf[ORDER];
- Word16 isf_stage2[ORDER];
+ Word16 tmp_ind[5];
+ Word16 surv1[N_SURV_MAX]; /* indices of survivors from 1st stage */
+ Word32 i, k, temp, min_err, distance;
+ Word16 isf[ORDER];
+ Word16 isf_stage2[ORDER];
- for (i = 0; i < ORDER; i++)
- {
- isf[i] = vo_sub(isf1[i], mean_isf[i]);
- isf[i] = vo_sub(isf[i], vo_mult(MU, past_isfq[i]));
- }
+ for (i = 0; i < ORDER; i++)
+ {
+ isf[i] = vo_sub(isf1[i], mean_isf[i]);
+ isf[i] = vo_sub(isf[i], vo_mult(MU, past_isfq[i]));
+ }
- VQ_stage1(&isf[0], dico1_isf, 9, SIZE_BK1, surv1, nb_surv);
+ VQ_stage1(&isf[0], dico1_isf, 9, SIZE_BK1, surv1, nb_surv);
- distance = MAX_32;
+ distance = MAX_32;
- for (k = 0; k < nb_surv; k++)
- {
- for (i = 0; i < 9; i++)
- {
- isf_stage2[i] = vo_sub(isf[i], dico1_isf[i + surv1[k] * 9]);
- }
- tmp_ind[0] = Sub_VQ(&isf_stage2[0], dico21_isf, 3, SIZE_BK21, &min_err);
- temp = min_err;
- tmp_ind[1] = Sub_VQ(&isf_stage2[3], dico22_isf, 3, SIZE_BK22, &min_err);
- temp = vo_L_add(temp, min_err);
- tmp_ind[2] = Sub_VQ(&isf_stage2[6], dico23_isf, 3, SIZE_BK23, &min_err);
- temp = vo_L_add(temp, min_err);
+ for (k = 0; k < nb_surv; k++)
+ {
+ for (i = 0; i < 9; i++)
+ {
+ isf_stage2[i] = vo_sub(isf[i], dico1_isf[i + surv1[k] * 9]);
+ }
+ tmp_ind[0] = Sub_VQ(&isf_stage2[0], dico21_isf, 3, SIZE_BK21, &min_err);
+ temp = min_err;
+ tmp_ind[1] = Sub_VQ(&isf_stage2[3], dico22_isf, 3, SIZE_BK22, &min_err);
+ temp = vo_L_add(temp, min_err);
+ tmp_ind[2] = Sub_VQ(&isf_stage2[6], dico23_isf, 3, SIZE_BK23, &min_err);
+ temp = vo_L_add(temp, min_err);
- if(temp < distance)
- {
- distance = temp;
- indice[0] = surv1[k];
- for (i = 0; i < 3; i++)
- {
- indice[i + 2] = tmp_ind[i];
- }
- }
- }
+ if(temp < distance)
+ {
+ distance = temp;
+ indice[0] = surv1[k];
+ for (i = 0; i < 3; i++)
+ {
+ indice[i + 2] = tmp_ind[i];
+ }
+ }
+ }
- VQ_stage1(&isf[9], dico2_isf, 7, SIZE_BK2, surv1, nb_surv);
+ VQ_stage1(&isf[9], dico2_isf, 7, SIZE_BK2, surv1, nb_surv);
- distance = MAX_32;
+ distance = MAX_32;
- for (k = 0; k < nb_surv; k++)
- {
- for (i = 0; i < 7; i++)
- {
- isf_stage2[i] = vo_sub(isf[9 + i], dico2_isf[i + surv1[k] * 7]);
- }
+ for (k = 0; k < nb_surv; k++)
+ {
+ for (i = 0; i < 7; i++)
+ {
+ isf_stage2[i] = vo_sub(isf[9 + i], dico2_isf[i + surv1[k] * 7]);
+ }
- tmp_ind[0] = Sub_VQ(&isf_stage2[0], dico24_isf, 3, SIZE_BK24, &min_err);
- temp = min_err;
- tmp_ind[1] = Sub_VQ(&isf_stage2[3], dico25_isf, 4, SIZE_BK25, &min_err);
- temp = vo_L_add(temp, min_err);
+ tmp_ind[0] = Sub_VQ(&isf_stage2[0], dico24_isf, 3, SIZE_BK24, &min_err);
+ temp = min_err;
+ tmp_ind[1] = Sub_VQ(&isf_stage2[3], dico25_isf, 4, SIZE_BK25, &min_err);
+ temp = vo_L_add(temp, min_err);
- if(temp < distance)
- {
- distance = temp;
- indice[1] = surv1[k];
- for (i = 0; i < 2; i++)
- {
- indice[i + 5] = tmp_ind[i];
- }
- }
- }
+ if(temp < distance)
+ {
+ distance = temp;
+ indice[1] = surv1[k];
+ for (i = 0; i < 2; i++)
+ {
+ indice[i + 5] = tmp_ind[i];
+ }
+ }
+ }
- Dpisf_2s_46b(indice, isf_q, past_isfq, isf_q, isf_q, 0, 0);
+ Dpisf_2s_46b(indice, isf_q, past_isfq, isf_q, isf_q, 0, 0);
- return;
+ return;
}
/*****************************************************************************
@@ -144,76 +144,76 @@
******************************************************************************/
void Qpisf_2s_36b(
- Word16 * isf1, /* (i) Q15 : ISF in the frequency domain (0..0.5) */
- Word16 * isf_q, /* (o) Q15 : quantized ISF (0..0.5) */
- Word16 * past_isfq, /* (io)Q15 : past ISF quantizer */
- Word16 * indice, /* (o) : quantization indices */
- Word16 nb_surv /* (i) : number of survivor (1, 2, 3 or 4) */
- )
+ Word16 * isf1, /* (i) Q15 : ISF in the frequency domain (0..0.5) */
+ Word16 * isf_q, /* (o) Q15 : quantized ISF (0..0.5) */
+ Word16 * past_isfq, /* (io)Q15 : past ISF quantizer */
+ Word16 * indice, /* (o) : quantization indices */
+ Word16 nb_surv /* (i) : number of survivor (1, 2, 3 or 4) */
+ )
{
- Word16 i, k, tmp_ind[5];
- Word16 surv1[N_SURV_MAX]; /* indices of survivors from 1st stage */
- Word32 temp, min_err, distance;
- Word16 isf[ORDER];
- Word16 isf_stage2[ORDER];
+ Word16 i, k, tmp_ind[5];
+ Word16 surv1[N_SURV_MAX]; /* indices of survivors from 1st stage */
+ Word32 temp, min_err, distance;
+ Word16 isf[ORDER];
+ Word16 isf_stage2[ORDER];
- for (i = 0; i < ORDER; i++)
- {
- isf[i] = vo_sub(isf1[i], mean_isf[i]);
- isf[i] = vo_sub(isf[i], vo_mult(MU, past_isfq[i]));
- }
+ for (i = 0; i < ORDER; i++)
+ {
+ isf[i] = vo_sub(isf1[i], mean_isf[i]);
+ isf[i] = vo_sub(isf[i], vo_mult(MU, past_isfq[i]));
+ }
- VQ_stage1(&isf[0], dico1_isf, 9, SIZE_BK1, surv1, nb_surv);
+ VQ_stage1(&isf[0], dico1_isf, 9, SIZE_BK1, surv1, nb_surv);
- distance = MAX_32;
+ distance = MAX_32;
- for (k = 0; k < nb_surv; k++)
- {
- for (i = 0; i < 9; i++)
- {
- isf_stage2[i] = vo_sub(isf[i], dico1_isf[i + surv1[k] * 9]);
- }
+ for (k = 0; k < nb_surv; k++)
+ {
+ for (i = 0; i < 9; i++)
+ {
+ isf_stage2[i] = vo_sub(isf[i], dico1_isf[i + surv1[k] * 9]);
+ }
- tmp_ind[0] = Sub_VQ(&isf_stage2[0], dico21_isf_36b, 5, SIZE_BK21_36b, &min_err);
- temp = min_err;
- tmp_ind[1] = Sub_VQ(&isf_stage2[5], dico22_isf_36b, 4, SIZE_BK22_36b, &min_err);
- temp = vo_L_add(temp, min_err);
+ tmp_ind[0] = Sub_VQ(&isf_stage2[0], dico21_isf_36b, 5, SIZE_BK21_36b, &min_err);
+ temp = min_err;
+ tmp_ind[1] = Sub_VQ(&isf_stage2[5], dico22_isf_36b, 4, SIZE_BK22_36b, &min_err);
+ temp = vo_L_add(temp, min_err);
- if(temp < distance)
- {
- distance = temp;
- indice[0] = surv1[k];
- for (i = 0; i < 2; i++)
- {
- indice[i + 2] = tmp_ind[i];
- }
- }
- }
+ if(temp < distance)
+ {
+ distance = temp;
+ indice[0] = surv1[k];
+ for (i = 0; i < 2; i++)
+ {
+ indice[i + 2] = tmp_ind[i];
+ }
+ }
+ }
- VQ_stage1(&isf[9], dico2_isf, 7, SIZE_BK2, surv1, nb_surv);
- distance = MAX_32;
+ VQ_stage1(&isf[9], dico2_isf, 7, SIZE_BK2, surv1, nb_surv);
+ distance = MAX_32;
- for (k = 0; k < nb_surv; k++)
- {
- for (i = 0; i < 7; i++)
- {
- isf_stage2[i] = vo_sub(isf[9 + i], dico2_isf[i + surv1[k] * 7]);
- }
+ for (k = 0; k < nb_surv; k++)
+ {
+ for (i = 0; i < 7; i++)
+ {
+ isf_stage2[i] = vo_sub(isf[9 + i], dico2_isf[i + surv1[k] * 7]);
+ }
- tmp_ind[0] = Sub_VQ(&isf_stage2[0], dico23_isf_36b, 7, SIZE_BK23_36b, &min_err);
- temp = min_err;
+ tmp_ind[0] = Sub_VQ(&isf_stage2[0], dico23_isf_36b, 7, SIZE_BK23_36b, &min_err);
+ temp = min_err;
- if(temp < distance)
- {
- distance = temp;
- indice[1] = surv1[k];
- indice[4] = tmp_ind[0];
- }
- }
+ if(temp < distance)
+ {
+ distance = temp;
+ indice[1] = surv1[k];
+ indice[4] = tmp_ind[0];
+ }
+ }
- Dpisf_2s_36b(indice, isf_q, past_isfq, isf_q, isf_q, 0, 0);
+ Dpisf_2s_36b(indice, isf_q, past_isfq, isf_q, isf_q, 0, 0);
- return;
+ return;
}
/*********************************************************************
@@ -223,90 +223,90 @@
**********************************************************************/
void Dpisf_2s_46b(
- Word16 * indice, /* input: quantization indices */
- Word16 * isf_q, /* output: quantized ISF in frequency domain (0..0.5) */
- Word16 * past_isfq, /* i/0 : past ISF quantizer */
- Word16 * isfold, /* input : past quantized ISF */
- Word16 * isf_buf, /* input : isf buffer */
- Word16 bfi, /* input : Bad frame indicator */
- Word16 enc_dec
- )
+ Word16 * indice, /* input: quantization indices */
+ Word16 * isf_q, /* output: quantized ISF in frequency domain (0..0.5) */
+ Word16 * past_isfq, /* i/0 : past ISF quantizer */
+ Word16 * isfold, /* input : past quantized ISF */
+ Word16 * isf_buf, /* input : isf buffer */
+ Word16 bfi, /* input : Bad frame indicator */
+ Word16 enc_dec
+ )
{
- Word16 ref_isf[M], tmp;
- Word32 i, j, L_tmp;
+ Word16 ref_isf[M], tmp;
+ Word32 i, j, L_tmp;
- if (bfi == 0) /* Good frame */
- {
- for (i = 0; i < 9; i++)
- {
- isf_q[i] = dico1_isf[indice[0] * 9 + i];
- }
- for (i = 0; i < 7; i++)
- {
- isf_q[i + 9] = dico2_isf[indice[1] * 7 + i];
- }
+ if (bfi == 0) /* Good frame */
+ {
+ for (i = 0; i < 9; i++)
+ {
+ isf_q[i] = dico1_isf[indice[0] * 9 + i];
+ }
+ for (i = 0; i < 7; i++)
+ {
+ isf_q[i + 9] = dico2_isf[indice[1] * 7 + i];
+ }
- for (i = 0; i < 3; i++)
- {
- isf_q[i] = add1(isf_q[i], dico21_isf[indice[2] * 3 + i]);
- isf_q[i + 3] = add1(isf_q[i + 3], dico22_isf[indice[3] * 3 + i]);
- isf_q[i + 6] = add1(isf_q[i + 6], dico23_isf[indice[4] * 3 + i]);
- isf_q[i + 9] = add1(isf_q[i + 9], dico24_isf[indice[5] * 3 + i]);
- }
+ for (i = 0; i < 3; i++)
+ {
+ isf_q[i] = add1(isf_q[i], dico21_isf[indice[2] * 3 + i]);
+ isf_q[i + 3] = add1(isf_q[i + 3], dico22_isf[indice[3] * 3 + i]);
+ isf_q[i + 6] = add1(isf_q[i + 6], dico23_isf[indice[4] * 3 + i]);
+ isf_q[i + 9] = add1(isf_q[i + 9], dico24_isf[indice[5] * 3 + i]);
+ }
- for (i = 0; i < 4; i++)
- {
- isf_q[i + 12] = add1(isf_q[i + 12], dico25_isf[indice[6] * 4 + i]);
- }
+ for (i = 0; i < 4; i++)
+ {
+ isf_q[i + 12] = add1(isf_q[i + 12], dico25_isf[indice[6] * 4 + i]);
+ }
- for (i = 0; i < ORDER; i++)
- {
- tmp = isf_q[i];
- isf_q[i] = add1(tmp, mean_isf[i]);
- isf_q[i] = add1(isf_q[i], vo_mult(MU, past_isfq[i]));
- past_isfq[i] = tmp;
- }
+ for (i = 0; i < ORDER; i++)
+ {
+ tmp = isf_q[i];
+ isf_q[i] = add1(tmp, mean_isf[i]);
+ isf_q[i] = add1(isf_q[i], vo_mult(MU, past_isfq[i]));
+ past_isfq[i] = tmp;
+ }
- if (enc_dec)
- {
- for (i = 0; i < M; i++)
- {
- for (j = (L_MEANBUF - 1); j > 0; j--)
- {
- isf_buf[j * M + i] = isf_buf[(j - 1) * M + i];
- }
- isf_buf[i] = isf_q[i];
- }
- }
- } else
- { /* bad frame */
- for (i = 0; i < M; i++)
- {
- L_tmp = mean_isf[i] << 14;
- for (j = 0; j < L_MEANBUF; j++)
- {
- L_tmp += (isf_buf[j * M + i] << 14);
- }
- ref_isf[i] = vo_round(L_tmp);
- }
+ if (enc_dec)
+ {
+ for (i = 0; i < M; i++)
+ {
+ for (j = (L_MEANBUF - 1); j > 0; j--)
+ {
+ isf_buf[j * M + i] = isf_buf[(j - 1) * M + i];
+ }
+ isf_buf[i] = isf_q[i];
+ }
+ }
+ } else
+ { /* bad frame */
+ for (i = 0; i < M; i++)
+ {
+ L_tmp = mean_isf[i] << 14;
+ for (j = 0; j < L_MEANBUF; j++)
+ {
+ L_tmp += (isf_buf[j * M + i] << 14);
+ }
+ ref_isf[i] = vo_round(L_tmp);
+ }
- /* use the past ISFs slightly shifted towards their mean */
- for (i = 0; i < ORDER; i++)
- {
- isf_q[i] = add1(vo_mult(ALPHA, isfold[i]), vo_mult(ONE_ALPHA, ref_isf[i]));
- }
+ /* use the past ISFs slightly shifted towards their mean */
+ for (i = 0; i < ORDER; i++)
+ {
+ isf_q[i] = add1(vo_mult(ALPHA, isfold[i]), vo_mult(ONE_ALPHA, ref_isf[i]));
+ }
- /* estimate past quantized residual to be used in next frame */
- for (i = 0; i < ORDER; i++)
- {
- tmp = add1(ref_isf[i], vo_mult(past_isfq[i], MU)); /* predicted ISF */
- past_isfq[i] = vo_sub(isf_q[i], tmp);
- past_isfq[i] = (past_isfq[i] >> 1); /* past_isfq[i] *= 0.5 */
- }
- }
+ /* estimate past quantized residual to be used in next frame */
+ for (i = 0; i < ORDER; i++)
+ {
+ tmp = add1(ref_isf[i], vo_mult(past_isfq[i], MU)); /* predicted ISF */
+ past_isfq[i] = vo_sub(isf_q[i], tmp);
+ past_isfq[i] = (past_isfq[i] >> 1); /* past_isfq[i] *= 0.5 */
+ }
+ }
- Reorder_isf(isf_q, ISF_GAP, ORDER);
- return;
+ Reorder_isf(isf_q, ISF_GAP, ORDER);
+ return;
}
/*********************************************************************
@@ -316,92 +316,92 @@
*********************************************************************/
void Dpisf_2s_36b(
- Word16 * indice, /* input: quantization indices */
- Word16 * isf_q, /* output: quantized ISF in frequency domain (0..0.5) */
- Word16 * past_isfq, /* i/0 : past ISF quantizer */
- Word16 * isfold, /* input : past quantized ISF */
- Word16 * isf_buf, /* input : isf buffer */
- Word16 bfi, /* input : Bad frame indicator */
- Word16 enc_dec
- )
+ Word16 * indice, /* input: quantization indices */
+ Word16 * isf_q, /* output: quantized ISF in frequency domain (0..0.5) */
+ Word16 * past_isfq, /* i/0 : past ISF quantizer */
+ Word16 * isfold, /* input : past quantized ISF */
+ Word16 * isf_buf, /* input : isf buffer */
+ Word16 bfi, /* input : Bad frame indicator */
+ Word16 enc_dec
+ )
{
- Word16 ref_isf[M], tmp;
- Word32 i, j, L_tmp;
+ Word16 ref_isf[M], tmp;
+ Word32 i, j, L_tmp;
- if (bfi == 0) /* Good frame */
- {
- for (i = 0; i < 9; i++)
- {
- isf_q[i] = dico1_isf[indice[0] * 9 + i];
- }
- for (i = 0; i < 7; i++)
- {
- isf_q[i + 9] = dico2_isf[indice[1] * 7 + i];
- }
+ if (bfi == 0) /* Good frame */
+ {
+ for (i = 0; i < 9; i++)
+ {
+ isf_q[i] = dico1_isf[indice[0] * 9 + i];
+ }
+ for (i = 0; i < 7; i++)
+ {
+ isf_q[i + 9] = dico2_isf[indice[1] * 7 + i];
+ }
- for (i = 0; i < 5; i++)
- {
- isf_q[i] = add1(isf_q[i], dico21_isf_36b[indice[2] * 5 + i]);
- }
- for (i = 0; i < 4; i++)
- {
- isf_q[i + 5] = add1(isf_q[i + 5], dico22_isf_36b[indice[3] * 4 + i]);
- }
- for (i = 0; i < 7; i++)
- {
- isf_q[i + 9] = add1(isf_q[i + 9], dico23_isf_36b[indice[4] * 7 + i]);
- }
+ for (i = 0; i < 5; i++)
+ {
+ isf_q[i] = add1(isf_q[i], dico21_isf_36b[indice[2] * 5 + i]);
+ }
+ for (i = 0; i < 4; i++)
+ {
+ isf_q[i + 5] = add1(isf_q[i + 5], dico22_isf_36b[indice[3] * 4 + i]);
+ }
+ for (i = 0; i < 7; i++)
+ {
+ isf_q[i + 9] = add1(isf_q[i + 9], dico23_isf_36b[indice[4] * 7 + i]);
+ }
- for (i = 0; i < ORDER; i++)
- {
- tmp = isf_q[i];
- isf_q[i] = add1(tmp, mean_isf[i]);
- isf_q[i] = add1(isf_q[i], vo_mult(MU, past_isfq[i]));
- past_isfq[i] = tmp;
- }
+ for (i = 0; i < ORDER; i++)
+ {
+ tmp = isf_q[i];
+ isf_q[i] = add1(tmp, mean_isf[i]);
+ isf_q[i] = add1(isf_q[i], vo_mult(MU, past_isfq[i]));
+ past_isfq[i] = tmp;
+ }
- if (enc_dec)
- {
- for (i = 0; i < M; i++)
- {
- for (j = (L_MEANBUF - 1); j > 0; j--)
- {
- isf_buf[j * M + i] = isf_buf[(j - 1) * M + i];
- }
- isf_buf[i] = isf_q[i];
- }
- }
- } else
- { /* bad frame */
- for (i = 0; i < M; i++)
- {
- L_tmp = (mean_isf[i] << 14);
- for (j = 0; j < L_MEANBUF; j++)
- {
- L_tmp += (isf_buf[j * M + i] << 14);
- }
- ref_isf[i] = vo_round(L_tmp);
- }
+ if (enc_dec)
+ {
+ for (i = 0; i < M; i++)
+ {
+ for (j = (L_MEANBUF - 1); j > 0; j--)
+ {
+ isf_buf[j * M + i] = isf_buf[(j - 1) * M + i];
+ }
+ isf_buf[i] = isf_q[i];
+ }
+ }
+ } else
+ { /* bad frame */
+ for (i = 0; i < M; i++)
+ {
+ L_tmp = (mean_isf[i] << 14);
+ for (j = 0; j < L_MEANBUF; j++)
+ {
+ L_tmp += (isf_buf[j * M + i] << 14);
+ }
+ ref_isf[i] = vo_round(L_tmp);
+ }
- /* use the past ISFs slightly shifted towards their mean */
- for (i = 0; i < ORDER; i++)
- {
- isf_q[i] = add1(vo_mult(ALPHA, isfold[i]), vo_mult(ONE_ALPHA, ref_isf[i]));
- }
+ /* use the past ISFs slightly shifted towards their mean */
+ for (i = 0; i < ORDER; i++)
+ {
+ isf_q[i] = add1(vo_mult(ALPHA, isfold[i]), vo_mult(ONE_ALPHA, ref_isf[i]));
+ }
- /* estimate past quantized residual to be used in next frame */
- for (i = 0; i < ORDER; i++)
- {
- tmp = add1(ref_isf[i], vo_mult(past_isfq[i], MU)); /* predicted ISF */
- past_isfq[i] = vo_sub(isf_q[i], tmp);
- past_isfq[i] = past_isfq[i] >> 1; /* past_isfq[i] *= 0.5 */
- }
- }
+ /* estimate past quantized residual to be used in next frame */
+ for (i = 0; i < ORDER; i++)
+ {
+ tmp = add1(ref_isf[i], vo_mult(past_isfq[i], MU)); /* predicted ISF */
+ past_isfq[i] = vo_sub(isf_q[i], tmp);
+ past_isfq[i] = past_isfq[i] >> 1; /* past_isfq[i] *= 0.5 */
+ }
+ }
- Reorder_isf(isf_q, ISF_GAP, ORDER);
+ Reorder_isf(isf_q, ISF_GAP, ORDER);
- return;
+ return;
}
@@ -419,122 +419,122 @@
****************************************************************************/
void Reorder_isf(
- Word16 * isf, /* (i/o) Q15: ISF in the frequency domain (0..0.5) */
- Word16 min_dist, /* (i) Q15 : minimum distance to keep */
- Word16 n /* (i) : number of ISF */
- )
+ Word16 * isf, /* (i/o) Q15: ISF in the frequency domain (0..0.5) */
+ Word16 min_dist, /* (i) Q15 : minimum distance to keep */
+ Word16 n /* (i) : number of ISF */
+ )
{
- Word32 i;
- Word16 isf_min;
+ Word32 i;
+ Word16 isf_min;
- isf_min = min_dist;
- for (i = 0; i < n - 1; i++)
- {
- if(isf[i] < isf_min)
- {
- isf[i] = isf_min;
- }
- isf_min = (isf[i] + min_dist);
- }
- return;
+ isf_min = min_dist;
+ for (i = 0; i < n - 1; i++)
+ {
+ if(isf[i] < isf_min)
+ {
+ isf[i] = isf_min;
+ }
+ isf_min = (isf[i] + min_dist);
+ }
+ return;
}
Word16 Sub_VQ( /* output: return quantization index */
- Word16 * x, /* input : ISF residual vector */
- Word16 * dico, /* input : quantization codebook */
- Word16 dim, /* input : dimention of vector */
- Word16 dico_size, /* input : size of quantization codebook */
- Word32 * distance /* output: error of quantization */
- )
+ Word16 * x, /* input : ISF residual vector */
+ Word16 * dico, /* input : quantization codebook */
+ Word16 dim, /* input : dimention of vector */
+ Word16 dico_size, /* input : size of quantization codebook */
+ Word32 * distance /* output: error of quantization */
+ )
{
- Word16 temp, *p_dico;
- Word32 i, j, index;
- Word32 dist_min, dist;
+ Word16 temp, *p_dico;
+ Word32 i, j, index;
+ Word32 dist_min, dist;
- dist_min = MAX_32;
- p_dico = dico;
+ dist_min = MAX_32;
+ p_dico = dico;
- index = 0;
- for (i = 0; i < dico_size; i++)
- {
- dist = 0;
+ index = 0;
+ for (i = 0; i < dico_size; i++)
+ {
+ dist = 0;
- for (j = 0; j < dim; j++)
- {
- temp = x[j] - (*p_dico++);
- dist += (temp * temp)<<1;
- }
+ for (j = 0; j < dim; j++)
+ {
+ temp = x[j] - (*p_dico++);
+ dist += (temp * temp)<<1;
+ }
- if(dist < dist_min)
- {
- dist_min = dist;
- index = i;
- }
- }
+ if(dist < dist_min)
+ {
+ dist_min = dist;
+ index = i;
+ }
+ }
- *distance = dist_min;
+ *distance = dist_min;
- /* Reading the selected vector */
- p_dico = &dico[index * dim];
- for (j = 0; j < dim; j++)
- {
- x[j] = *p_dico++;
- }
+ /* Reading the selected vector */
+ p_dico = &dico[index * dim];
+ for (j = 0; j < dim; j++)
+ {
+ x[j] = *p_dico++;
+ }
- return index;
+ return index;
}
static void VQ_stage1(
- Word16 * x, /* input : ISF residual vector */
- Word16 * dico, /* input : quantization codebook */
- Word16 dim, /* input : dimention of vector */
- Word16 dico_size, /* input : size of quantization codebook */
- Word16 * index, /* output: indices of survivors */
- Word16 surv /* input : number of survivor */
- )
+ Word16 * x, /* input : ISF residual vector */
+ Word16 * dico, /* input : quantization codebook */
+ Word16 dim, /* input : dimention of vector */
+ Word16 dico_size, /* input : size of quantization codebook */
+ Word16 * index, /* output: indices of survivors */
+ Word16 surv /* input : number of survivor */
+ )
{
- Word16 temp, *p_dico;
- Word32 i, j, k, l;
- Word32 dist_min[N_SURV_MAX], dist;
+ Word16 temp, *p_dico;
+ Word32 i, j, k, l;
+ Word32 dist_min[N_SURV_MAX], dist;
- dist_min[0] = MAX_32;
- dist_min[1] = MAX_32;
- dist_min[2] = MAX_32;
- dist_min[3] = MAX_32;
- index[0] = 0;
- index[1] = 1;
- index[2] = 2;
- index[3] = 3;
+ dist_min[0] = MAX_32;
+ dist_min[1] = MAX_32;
+ dist_min[2] = MAX_32;
+ dist_min[3] = MAX_32;
+ index[0] = 0;
+ index[1] = 1;
+ index[2] = 2;
+ index[3] = 3;
- p_dico = dico;
+ p_dico = dico;
- for (i = 0; i < dico_size; i++)
- {
- dist = 0;
- for (j = 0; j < dim; j++)
- {
- temp = x[j] - (*p_dico++);
- dist += (temp * temp)<<1;
- }
+ for (i = 0; i < dico_size; i++)
+ {
+ dist = 0;
+ for (j = 0; j < dim; j++)
+ {
+ temp = x[j] - (*p_dico++);
+ dist += (temp * temp)<<1;
+ }
- for (k = 0; k < surv; k++)
- {
- if(dist < dist_min[k])
- {
- for (l = surv - 1; l > k; l--)
- {
- dist_min[l] = dist_min[l - 1];
- index[l] = index[l - 1];
- }
- dist_min[k] = dist;
- index[k] = i;
- break;
- }
- }
- }
- return;
+ for (k = 0; k < surv; k++)
+ {
+ if(dist < dist_min[k])
+ {
+ for (l = surv - 1; l > k; l--)
+ {
+ dist_min[l] = dist_min[l - 1];
+ index[l] = index[l - 1];
+ }
+ dist_min[k] = dist;
+ index[k] = i;
+ break;
+ }
+ }
+ }
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/random.c b/media/libstagefright/codecs/amrwbenc/src/random.c
index b896863..758343c 100644
--- a/media/libstagefright/codecs/amrwbenc/src/random.c
+++ b/media/libstagefright/codecs/amrwbenc/src/random.c
@@ -26,8 +26,8 @@
Word16 Random(Word16 * seed)
{
- /* static Word16 seed = 21845; */
- *seed = (Word16)(L_add((L_mult(*seed, 31821) >> 1), 13849L));
- return (*seed);
+ /* static Word16 seed = 21845; */
+ *seed = (Word16)(L_add((L_mult(*seed, 31821) >> 1), 13849L));
+ return (*seed);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/residu.c b/media/libstagefright/codecs/amrwbenc/src/residu.c
index b0c04b5..76d0e41 100644
--- a/media/libstagefright/codecs/amrwbenc/src/residu.c
+++ b/media/libstagefright/codecs/amrwbenc/src/residu.c
@@ -26,41 +26,41 @@
#include "basic_op.h"
void Residu(
- Word16 a[], /* (i) Q12 : prediction coefficients */
- Word16 x[], /* (i) : speech (values x[-m..-1] are needed */
- Word16 y[], /* (o) x2 : residual signal */
- Word16 lg /* (i) : size of filtering */
- )
+ Word16 a[], /* (i) Q12 : prediction coefficients */
+ Word16 x[], /* (i) : speech (values x[-m..-1] are needed */
+ Word16 y[], /* (o) x2 : residual signal */
+ Word16 lg /* (i) : size of filtering */
+ )
{
- Word16 i,*p1, *p2;
- Word32 s;
- for (i = 0; i < lg; i++)
- {
- p1 = a;
- p2 = &x[i];
- s = vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1++), (*p2--));
- s += vo_mult32((*p1), (*p2));
+ Word16 i,*p1, *p2;
+ Word32 s;
+ for (i = 0; i < lg; i++)
+ {
+ p1 = a;
+ p2 = &x[i];
+ s = vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1++), (*p2--));
+ s += vo_mult32((*p1), (*p2));
- s = L_shl2(s, 5);
- y[i] = extract_h(L_add(s, 0x8000));
- }
+ s = L_shl2(s, 5);
+ y[i] = extract_h(L_add(s, 0x8000));
+ }
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/scale.c b/media/libstagefright/codecs/amrwbenc/src/scale.c
index 418cc06..21458c8 100644
--- a/media/libstagefright/codecs/amrwbenc/src/scale.c
+++ b/media/libstagefright/codecs/amrwbenc/src/scale.c
@@ -25,32 +25,32 @@
#include "basic_op.h"
void Scale_sig(
- Word16 x[], /* (i/o) : signal to scale */
- Word16 lg, /* (i) : size of x[] */
- Word16 exp /* (i) : exponent: x = round(x << exp) */
- )
+ Word16 x[], /* (i/o) : signal to scale */
+ Word16 lg, /* (i) : size of x[] */
+ Word16 exp /* (i) : exponent: x = round(x << exp) */
+ )
{
- Word32 i;
- Word32 L_tmp;
- if(exp > 0)
- {
- for (i = lg - 1 ; i >= 0; i--)
- {
- L_tmp = L_shl2(x[i], 16 + exp);
- x[i] = extract_h(L_add(L_tmp, 0x8000));
- }
- }
- else
- {
- exp = -exp;
- for (i = lg - 1; i >= 0; i--)
- {
- L_tmp = x[i] << 16;
- L_tmp >>= exp;
- x[i] = (L_tmp + 0x8000)>>16;
- }
- }
- return;
+ Word32 i;
+ Word32 L_tmp;
+ if(exp > 0)
+ {
+ for (i = lg - 1 ; i >= 0; i--)
+ {
+ L_tmp = L_shl2(x[i], 16 + exp);
+ x[i] = extract_h(L_add(L_tmp, 0x8000));
+ }
+ }
+ else
+ {
+ exp = -exp;
+ for (i = lg - 1; i >= 0; i--)
+ {
+ L_tmp = x[i] << 16;
+ L_tmp >>= exp;
+ x[i] = (L_tmp + 0x8000)>>16;
+ }
+ }
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/stream.c b/media/libstagefright/codecs/amrwbenc/src/stream.c
index 780f009..a39149e 100644
--- a/media/libstagefright/codecs/amrwbenc/src/stream.c
+++ b/media/libstagefright/codecs/amrwbenc/src/stream.c
@@ -25,34 +25,34 @@
void voAWB_InitFrameBuffer(FrameStream *stream)
{
- stream->set_ptr = NULL;
- stream->frame_ptr_bk = stream->frame_ptr;
- stream->set_len = 0;
- stream->framebuffer_len = 0;
- stream->frame_storelen = 0;
+ stream->set_ptr = NULL;
+ stream->frame_ptr_bk = stream->frame_ptr;
+ stream->set_len = 0;
+ stream->framebuffer_len = 0;
+ stream->frame_storelen = 0;
}
void voAWB_UpdateFrameBuffer(
- FrameStream *stream,
- VO_MEM_OPERATOR *pMemOP
- )
+ FrameStream *stream,
+ VO_MEM_OPERATOR *pMemOP
+ )
{
- int len;
- len = MIN(Frame_Maxsize - stream->frame_storelen, stream->set_len);
- pMemOP->Copy(VO_INDEX_ENC_AMRWB, stream->frame_ptr_bk + stream->frame_storelen , stream->set_ptr, len);
- stream->set_len -= len;
- stream->set_ptr += len;
- stream->framebuffer_len = stream->frame_storelen + len;
- stream->frame_ptr = stream->frame_ptr_bk;
- stream->used_len += len;
+ int len;
+ len = MIN(Frame_Maxsize - stream->frame_storelen, stream->set_len);
+ pMemOP->Copy(VO_INDEX_ENC_AMRWB, stream->frame_ptr_bk + stream->frame_storelen , stream->set_ptr, len);
+ stream->set_len -= len;
+ stream->set_ptr += len;
+ stream->framebuffer_len = stream->frame_storelen + len;
+ stream->frame_ptr = stream->frame_ptr_bk;
+ stream->used_len += len;
}
void voAWB_FlushFrameBuffer(FrameStream *stream)
{
- stream->set_ptr = NULL;
- stream->frame_ptr_bk = stream->frame_ptr;
- stream->set_len = 0;
- stream->framebuffer_len = 0;
- stream->frame_storelen = 0;
+ stream->set_ptr = NULL;
+ stream->frame_ptr_bk = stream->frame_ptr;
+ stream->set_len = 0;
+ stream->framebuffer_len = 0;
+ stream->frame_storelen = 0;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/syn_filt.c b/media/libstagefright/codecs/amrwbenc/src/syn_filt.c
index 961aadc..7eba12f 100644
--- a/media/libstagefright/codecs/amrwbenc/src/syn_filt.c
+++ b/media/libstagefright/codecs/amrwbenc/src/syn_filt.c
@@ -29,134 +29,134 @@
#define UNUSED(x) (void)(x)
void Syn_filt(
- Word16 a[], /* (i) Q12 : a[m+1] prediction coefficients */
- Word16 x[], /* (i) : input signal */
- Word16 y[], /* (o) : output signal */
- Word16 lg, /* (i) : size of filtering */
- Word16 mem[], /* (i/o) : memory associated with this filtering. */
- Word16 update /* (i) : 0=no update, 1=update of memory. */
- )
+ Word16 a[], /* (i) Q12 : a[m+1] prediction coefficients */
+ Word16 x[], /* (i) : input signal */
+ Word16 y[], /* (o) : output signal */
+ Word16 lg, /* (i) : size of filtering */
+ Word16 mem[], /* (i/o) : memory associated with this filtering. */
+ Word16 update /* (i) : 0=no update, 1=update of memory. */
+ )
{
- Word32 i, a0;
- Word16 y_buf[L_SUBFR16k + M16k];
- Word32 L_tmp;
- Word16 *yy, *p1, *p2;
- yy = &y_buf[0];
- /* copy initial filter states into synthesis buffer */
- for (i = 0; i < 16; i++)
- {
- *yy++ = mem[i];
- }
- a0 = (a[0] >> 1); /* input / 2 */
- /* Do the filtering. */
- for (i = 0; i < lg; i++)
- {
- p1 = &a[1];
- p2 = &yy[i-1];
- L_tmp = vo_mult32(a0, x[i]);
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1++), (*p2--));
- L_tmp -= vo_mult32((*p1), (*p2));
+ Word32 i, a0;
+ Word16 y_buf[L_SUBFR16k + M16k];
+ Word32 L_tmp;
+ Word16 *yy, *p1, *p2;
+ yy = &y_buf[0];
+ /* copy initial filter states into synthesis buffer */
+ for (i = 0; i < 16; i++)
+ {
+ *yy++ = mem[i];
+ }
+ a0 = (a[0] >> 1); /* input / 2 */
+ /* Do the filtering. */
+ for (i = 0; i < lg; i++)
+ {
+ p1 = &a[1];
+ p2 = &yy[i-1];
+ L_tmp = vo_mult32(a0, x[i]);
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1++), (*p2--));
+ L_tmp -= vo_mult32((*p1), (*p2));
- L_tmp = L_shl2(L_tmp, 4);
- y[i] = yy[i] = extract_h(L_add(L_tmp, 0x8000));
- }
- /* Update memory if required */
- if (update)
- for (i = 0; i < 16; i++)
- {
- mem[i] = yy[lg - 16 + i];
- }
- return;
+ L_tmp = L_shl2(L_tmp, 4);
+ y[i] = yy[i] = extract_h(L_add(L_tmp, 0x8000));
+ }
+ /* Update memory if required */
+ if (update)
+ for (i = 0; i < 16; i++)
+ {
+ mem[i] = yy[lg - 16 + i];
+ }
+ return;
}
void Syn_filt_32(
- Word16 a[], /* (i) Q12 : a[m+1] prediction coefficients */
- Word16 m, /* (i) : order of LP filter */
- Word16 exc[], /* (i) Qnew: excitation (exc[i] >> Qnew) */
- Word16 Qnew, /* (i) : exc scaling = 0(min) to 8(max) */
- Word16 sig_hi[], /* (o) /16 : synthesis high */
- Word16 sig_lo[], /* (o) /16 : synthesis low */
- Word16 lg /* (i) : size of filtering */
- )
+ Word16 a[], /* (i) Q12 : a[m+1] prediction coefficients */
+ Word16 m, /* (i) : order of LP filter */
+ Word16 exc[], /* (i) Qnew: excitation (exc[i] >> Qnew) */
+ Word16 Qnew, /* (i) : exc scaling = 0(min) to 8(max) */
+ Word16 sig_hi[], /* (o) /16 : synthesis high */
+ Word16 sig_lo[], /* (o) /16 : synthesis low */
+ Word16 lg /* (i) : size of filtering */
+ )
{
- Word32 i,a0;
- Word32 L_tmp, L_tmp1;
- Word16 *p1, *p2, *p3;
+ Word32 i,a0;
+ Word32 L_tmp, L_tmp1;
+ Word16 *p1, *p2, *p3;
UNUSED(m);
- a0 = a[0] >> (4 + Qnew); /* input / 16 and >>Qnew */
- /* Do the filtering. */
- for (i = 0; i < lg; i++)
- {
- L_tmp = 0;
- L_tmp1 = 0;
- p1 = a;
- p2 = &sig_lo[i - 1];
- p3 = &sig_hi[i - 1];
+ a0 = a[0] >> (4 + Qnew); /* input / 16 and >>Qnew */
+ /* Do the filtering. */
+ for (i = 0; i < lg; i++)
+ {
+ L_tmp = 0;
+ L_tmp1 = 0;
+ p1 = a;
+ p2 = &sig_lo[i - 1];
+ p3 = &sig_hi[i - 1];
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ L_tmp -= vo_mult32((*p2--), (*p1));
+ L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp = L_tmp >> 11;
- L_tmp += vo_L_mult(exc[i], a0);
+ L_tmp = L_tmp >> 11;
+ L_tmp += vo_L_mult(exc[i], a0);
- /* sig_hi = bit16 to bit31 of synthesis */
- L_tmp = L_tmp - (L_tmp1<<1);
+ /* sig_hi = bit16 to bit31 of synthesis */
+ L_tmp = L_tmp - (L_tmp1<<1);
- L_tmp = L_tmp >> 3; /* ai in Q12 */
- sig_hi[i] = extract_h(L_tmp);
+ L_tmp = L_tmp >> 3; /* ai in Q12 */
+ sig_hi[i] = extract_h(L_tmp);
- /* sig_lo = bit4 to bit15 of synthesis */
- L_tmp >>= 4; /* 4 : sig_lo[i] >> 4 */
- sig_lo[i] = (Word16)((L_tmp - (sig_hi[i] << 13)));
- }
+ /* sig_lo = bit4 to bit15 of synthesis */
+ L_tmp >>= 4; /* 4 : sig_lo[i] >> 4 */
+ sig_lo[i] = (Word16)((L_tmp - (sig_hi[i] << 13)));
+ }
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/updt_tar.c b/media/libstagefright/codecs/amrwbenc/src/updt_tar.c
index 96779fd..ba7c2ff 100644
--- a/media/libstagefright/codecs/amrwbenc/src/updt_tar.c
+++ b/media/libstagefright/codecs/amrwbenc/src/updt_tar.c
@@ -25,24 +25,25 @@
#include "basic_op.h"
void Updt_tar(
- Word16 * x, /* (i) Q0 : old target (for pitch search) */
- Word16 * x2, /* (o) Q0 : new target (for codebook search) */
- Word16 * y, /* (i) Q0 : filtered adaptive codebook vector */
- Word16 gain, /* (i) Q14 : adaptive codebook gain */
- Word16 L /* (i) : subframe size */
- )
+ Word16 * x, /* (i) Q0 : old target (for pitch search) */
+ Word16 * x2, /* (o) Q0 : new target (for codebook search) */
+ Word16 * y, /* (i) Q0 : filtered adaptive codebook vector */
+ Word16 gain, /* (i) Q14 : adaptive codebook gain */
+ Word16 L /* (i) : subframe size */
+ )
{
- Word32 i;
- Word32 L_tmp;
+ Word32 i;
+ Word32 L_tmp, L_tmp2;
- for (i = 0; i < L; i++)
- {
- L_tmp = x[i] << 15;
- L_tmp -= (y[i] * gain)<<1;
- x2[i] = extract_h(L_shl2(L_tmp, 1));
- }
+ for (i = 0; i < L; i++)
+ {
+ L_tmp = x[i] << 15;
+ L_tmp2 = L_mult(y[i], gain);
+ L_tmp = L_sub(L_tmp, L_tmp2);
+ x2[i] = extract_h(L_shl2(L_tmp, 1));
+ }
- return;
+ return;
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/util.c b/media/libstagefright/codecs/amrwbenc/src/util.c
index 333140d..374245f 100644
--- a/media/libstagefright/codecs/amrwbenc/src/util.c
+++ b/media/libstagefright/codecs/amrwbenc/src/util.c
@@ -30,15 +30,15 @@
************************************************************************/
void Set_zero(
- Word16 x[], /* (o) : vector to clear */
- Word16 L /* (i) : length of vector */
- )
+ Word16 x[], /* (o) : vector to clear */
+ Word16 L /* (i) : length of vector */
+ )
{
- Word32 num = (Word32)L;
- while (num > 0) {
- *x++ = 0;
+ Word32 num = (Word32)L;
+ while (num > 0) {
+ *x++ = 0;
--num;
- }
+ }
}
@@ -49,28 +49,28 @@
*********************************************************************/
void Copy(
- Word16 x[], /* (i) : input vector */
- Word16 y[], /* (o) : output vector */
- Word16 L /* (i) : vector length */
- )
+ Word16 x[], /* (i) : input vector */
+ Word16 y[], /* (o) : output vector */
+ Word16 L /* (i) : vector length */
+ )
{
- Word32 temp1,temp2,num;
+ Word32 temp1,temp2,num;
if (L <= 0) {
return;
}
- if(L&1)
- {
- temp1 = *x++;
- *y++ = temp1;
- }
- num = (Word32)(L>>1);
- while (num > 0) {
- temp1 = *x++;
- temp2 = *x++;
- *y++ = temp1;
- *y++ = temp2;
+ if(L&1)
+ {
+ temp1 = *x++;
+ *y++ = temp1;
+ }
+ num = (Word32)(L>>1);
+ while (num > 0) {
+ temp1 = *x++;
+ temp2 = *x++;
+ *y++ = temp1;
+ *y++ = temp2;
--num;
- }
+ }
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c b/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c
index df7b9b3..4cafb01 100644
--- a/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c
+++ b/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c
@@ -19,8 +19,8 @@
* *
* Description: Performs the main encoder routine *
* Fixed-point C simulation of AMR WB ACELP coding *
-* algorithm with 20 msspeech frames for *
-* wideband speech signals. *
+* algorithm with 20 msspeech frames for *
+* wideband speech signals. *
* *
************************************************************************/
@@ -51,95 +51,95 @@
/* isp tables for initialization */
static Word16 isp_init[M] =
{
- 32138, 30274, 27246, 23170, 18205, 12540, 6393, 0,
- -6393, -12540, -18205, -23170, -27246, -30274, -32138, 1475
+ 32138, 30274, 27246, 23170, 18205, 12540, 6393, 0,
+ -6393, -12540, -18205, -23170, -27246, -30274, -32138, 1475
};
static Word16 isf_init[M] =
{
- 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192,
- 9216, 10240, 11264, 12288, 13312, 14336, 15360, 3840
+ 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192,
+ 9216, 10240, 11264, 12288, 13312, 14336, 15360, 3840
};
/* High Band encoding */
static const Word16 HP_gain[16] =
{
- 3624, 4673, 5597, 6479, 7425, 8378, 9324, 10264,
- 11210, 12206, 13391, 14844, 16770, 19655, 24289, 32728
+ 3624, 4673, 5597, 6479, 7425, 8378, 9324, 10264,
+ 11210, 12206, 13391, 14844, 16770, 19655, 24289, 32728
};
/* Private function declaration */
static Word16 synthesis(
- Word16 Aq[], /* A(z) : quantized Az */
- Word16 exc[], /* (i) : excitation at 12kHz */
- Word16 Q_new, /* (i) : scaling performed on exc */
- Word16 synth16k[], /* (o) : 16kHz synthesis signal */
- Coder_State * st /* (i/o) : State structure */
- );
+ Word16 Aq[], /* A(z) : quantized Az */
+ Word16 exc[], /* (i) : excitation at 12kHz */
+ Word16 Q_new, /* (i) : scaling performed on exc */
+ Word16 synth16k[], /* (o) : 16kHz synthesis signal */
+ Coder_State * st /* (i/o) : State structure */
+ );
/* Codec some parameters initialization */
void Reset_encoder(void *st, Word16 reset_all)
{
- Word16 i;
- Coder_State *cod_state;
- cod_state = (Coder_State *) st;
- Set_zero(cod_state->old_exc, PIT_MAX + L_INTERPOL);
- Set_zero(cod_state->mem_syn, M);
- Set_zero(cod_state->past_isfq, M);
- cod_state->mem_w0 = 0;
- cod_state->tilt_code = 0;
- cod_state->first_frame = 1;
- Init_gp_clip(cod_state->gp_clip);
- cod_state->L_gc_thres = 0;
- if (reset_all != 0)
- {
- /* Static vectors to zero */
- Set_zero(cod_state->old_speech, L_TOTAL - L_FRAME);
- Set_zero(cod_state->old_wsp, (PIT_MAX / OPL_DECIM));
- Set_zero(cod_state->mem_decim2, 3);
- /* routines initialization */
- Init_Decim_12k8(cod_state->mem_decim);
- Init_HP50_12k8(cod_state->mem_sig_in);
- Init_Levinson(cod_state->mem_levinson);
- Init_Q_gain2(cod_state->qua_gain);
- Init_Hp_wsp(cod_state->hp_wsp_mem);
- /* isp initialization */
- Copy(isp_init, cod_state->ispold, M);
- Copy(isp_init, cod_state->ispold_q, M);
- /* variable initialization */
- cod_state->mem_preemph = 0;
- cod_state->mem_wsp = 0;
- cod_state->Q_old = 15;
- cod_state->Q_max[0] = 15;
- cod_state->Q_max[1] = 15;
- cod_state->old_wsp_max = 0;
- cod_state->old_wsp_shift = 0;
- /* pitch ol initialization */
- cod_state->old_T0_med = 40;
- cod_state->ol_gain = 0;
- cod_state->ada_w = 0;
- cod_state->ol_wght_flg = 0;
- for (i = 0; i < 5; i++)
- {
- cod_state->old_ol_lag[i] = 40;
- }
- Set_zero(cod_state->old_hp_wsp, (L_FRAME / 2) / OPL_DECIM + (PIT_MAX / OPL_DECIM));
- Set_zero(cod_state->mem_syn_hf, M);
- Set_zero(cod_state->mem_syn_hi, M);
- Set_zero(cod_state->mem_syn_lo, M);
- Init_HP50_12k8(cod_state->mem_sig_out);
- Init_Filt_6k_7k(cod_state->mem_hf);
- Init_HP400_12k8(cod_state->mem_hp400);
- Copy(isf_init, cod_state->isfold, M);
- cod_state->mem_deemph = 0;
- cod_state->seed2 = 21845;
- Init_Filt_6k_7k(cod_state->mem_hf2);
- cod_state->gain_alpha = 32767;
- cod_state->vad_hist = 0;
- wb_vad_reset(cod_state->vadSt);
- dtx_enc_reset(cod_state->dtx_encSt, isf_init);
- }
- return;
+ Word16 i;
+ Coder_State *cod_state;
+ cod_state = (Coder_State *) st;
+ Set_zero(cod_state->old_exc, PIT_MAX + L_INTERPOL);
+ Set_zero(cod_state->mem_syn, M);
+ Set_zero(cod_state->past_isfq, M);
+ cod_state->mem_w0 = 0;
+ cod_state->tilt_code = 0;
+ cod_state->first_frame = 1;
+ Init_gp_clip(cod_state->gp_clip);
+ cod_state->L_gc_thres = 0;
+ if (reset_all != 0)
+ {
+ /* Static vectors to zero */
+ Set_zero(cod_state->old_speech, L_TOTAL - L_FRAME);
+ Set_zero(cod_state->old_wsp, (PIT_MAX / OPL_DECIM));
+ Set_zero(cod_state->mem_decim2, 3);
+ /* routines initialization */
+ Init_Decim_12k8(cod_state->mem_decim);
+ Init_HP50_12k8(cod_state->mem_sig_in);
+ Init_Levinson(cod_state->mem_levinson);
+ Init_Q_gain2(cod_state->qua_gain);
+ Init_Hp_wsp(cod_state->hp_wsp_mem);
+ /* isp initialization */
+ Copy(isp_init, cod_state->ispold, M);
+ Copy(isp_init, cod_state->ispold_q, M);
+ /* variable initialization */
+ cod_state->mem_preemph = 0;
+ cod_state->mem_wsp = 0;
+ cod_state->Q_old = 15;
+ cod_state->Q_max[0] = 15;
+ cod_state->Q_max[1] = 15;
+ cod_state->old_wsp_max = 0;
+ cod_state->old_wsp_shift = 0;
+ /* pitch ol initialization */
+ cod_state->old_T0_med = 40;
+ cod_state->ol_gain = 0;
+ cod_state->ada_w = 0;
+ cod_state->ol_wght_flg = 0;
+ for (i = 0; i < 5; i++)
+ {
+ cod_state->old_ol_lag[i] = 40;
+ }
+ Set_zero(cod_state->old_hp_wsp, (L_FRAME / 2) / OPL_DECIM + (PIT_MAX / OPL_DECIM));
+ Set_zero(cod_state->mem_syn_hf, M);
+ Set_zero(cod_state->mem_syn_hi, M);
+ Set_zero(cod_state->mem_syn_lo, M);
+ Init_HP50_12k8(cod_state->mem_sig_out);
+ Init_Filt_6k_7k(cod_state->mem_hf);
+ Init_HP400_12k8(cod_state->mem_hp400);
+ Copy(isf_init, cod_state->isfold, M);
+ cod_state->mem_deemph = 0;
+ cod_state->seed2 = 21845;
+ Init_Filt_6k_7k(cod_state->mem_hf2);
+ cod_state->gain_alpha = 32767;
+ cod_state->vad_hist = 0;
+ wb_vad_reset(cod_state->vadSt);
+ dtx_enc_reset(cod_state->dtx_encSt, isf_init);
+ }
+ return;
}
/*-----------------------------------------------------------------*
@@ -149,1176 +149,1180 @@
* *
*-----------------------------------------------------------------*/
void coder(
- Word16 * mode, /* input : used mode */
- Word16 speech16k[], /* input : 320 new speech samples (at 16 kHz) */
- Word16 prms[], /* output: output parameters */
- Word16 * ser_size, /* output: bit rate of the used mode */
- void *spe_state, /* i/o : State structure */
- Word16 allow_dtx /* input : DTX ON/OFF */
- )
+ Word16 * mode, /* input : used mode */
+ Word16 speech16k[], /* input : 320 new speech samples (at 16 kHz) */
+ Word16 prms[], /* output: output parameters */
+ Word16 * ser_size, /* output: bit rate of the used mode */
+ void *spe_state, /* i/o : State structure */
+ Word16 allow_dtx /* input : DTX ON/OFF */
+ )
{
- /* Coder states */
- Coder_State *st;
- /* Speech vector */
- Word16 old_speech[L_TOTAL];
- Word16 *new_speech, *speech, *p_window;
+ /* Coder states */
+ Coder_State *st;
+ /* Speech vector */
+ Word16 old_speech[L_TOTAL];
+ Word16 *new_speech, *speech, *p_window;
- /* Weighted speech vector */
- Word16 old_wsp[L_FRAME + (PIT_MAX / OPL_DECIM)];
- Word16 *wsp;
+ /* Weighted speech vector */
+ Word16 old_wsp[L_FRAME + (PIT_MAX / OPL_DECIM)];
+ Word16 *wsp;
- /* Excitation vector */
- Word16 old_exc[(L_FRAME + 1) + PIT_MAX + L_INTERPOL];
- Word16 *exc;
+ /* Excitation vector */
+ Word16 old_exc[(L_FRAME + 1) + PIT_MAX + L_INTERPOL];
+ Word16 *exc;
- /* LPC coefficients */
- Word16 r_h[M + 1], r_l[M + 1]; /* Autocorrelations of windowed speech */
- Word16 rc[M]; /* Reflection coefficients. */
- Word16 Ap[M + 1]; /* A(z) with spectral expansion */
- Word16 ispnew[M]; /* immittance spectral pairs at 4nd sfr */
- Word16 ispnew_q[M]; /* quantized ISPs at 4nd subframe */
- Word16 isf[M]; /* ISF (frequency domain) at 4nd sfr */
- Word16 *p_A, *p_Aq; /* ptr to A(z) for the 4 subframes */
- Word16 A[NB_SUBFR * (M + 1)]; /* A(z) unquantized for the 4 subframes */
- Word16 Aq[NB_SUBFR * (M + 1)]; /* A(z) quantized for the 4 subframes */
+ /* LPC coefficients */
+ Word16 r_h[M + 1], r_l[M + 1]; /* Autocorrelations of windowed speech */
+ Word16 rc[M]; /* Reflection coefficients. */
+ Word16 Ap[M + 1]; /* A(z) with spectral expansion */
+ Word16 ispnew[M]; /* immittance spectral pairs at 4nd sfr */
+ Word16 ispnew_q[M]; /* quantized ISPs at 4nd subframe */
+ Word16 isf[M]; /* ISF (frequency domain) at 4nd sfr */
+ Word16 *p_A, *p_Aq; /* ptr to A(z) for the 4 subframes */
+ Word16 A[NB_SUBFR * (M + 1)]; /* A(z) unquantized for the 4 subframes */
+ Word16 Aq[NB_SUBFR * (M + 1)]; /* A(z) quantized for the 4 subframes */
- /* Other vectors */
- Word16 xn[L_SUBFR]; /* Target vector for pitch search */
- Word16 xn2[L_SUBFR]; /* Target vector for codebook search */
- Word16 dn[L_SUBFR]; /* Correlation between xn2 and h1 */
- Word16 cn[L_SUBFR]; /* Target vector in residual domain */
- Word16 h1[L_SUBFR]; /* Impulse response vector */
- Word16 h2[L_SUBFR]; /* Impulse response vector */
- Word16 code[L_SUBFR]; /* Fixed codebook excitation */
- Word16 y1[L_SUBFR]; /* Filtered adaptive excitation */
- Word16 y2[L_SUBFR]; /* Filtered adaptive excitation */
- Word16 error[M + L_SUBFR]; /* error of quantization */
- Word16 synth[L_SUBFR]; /* 12.8kHz synthesis vector */
- Word16 exc2[L_FRAME]; /* excitation vector */
- Word16 buf[L_FRAME]; /* VAD buffer */
+ /* Other vectors */
+ Word16 xn[L_SUBFR]; /* Target vector for pitch search */
+ Word16 xn2[L_SUBFR]; /* Target vector for codebook search */
+ Word16 dn[L_SUBFR]; /* Correlation between xn2 and h1 */
+ Word16 cn[L_SUBFR]; /* Target vector in residual domain */
+ Word16 h1[L_SUBFR]; /* Impulse response vector */
+ Word16 h2[L_SUBFR]; /* Impulse response vector */
+ Word16 code[L_SUBFR]; /* Fixed codebook excitation */
+ Word16 y1[L_SUBFR]; /* Filtered adaptive excitation */
+ Word16 y2[L_SUBFR]; /* Filtered adaptive excitation */
+ Word16 error[M + L_SUBFR]; /* error of quantization */
+ Word16 synth[L_SUBFR]; /* 12.8kHz synthesis vector */
+ Word16 exc2[L_FRAME]; /* excitation vector */
+ Word16 buf[L_FRAME]; /* VAD buffer */
- /* Scalars */
- Word32 i, j, i_subfr, select, pit_flag, clip_gain, vad_flag;
- Word16 codec_mode;
- Word16 T_op, T_op2, T0, T0_min, T0_max, T0_frac, index;
- Word16 gain_pit, gain_code, g_coeff[4], g_coeff2[4];
- Word16 tmp, gain1, gain2, exp, Q_new, mu, shift, max;
- Word16 voice_fac;
- Word16 indice[8];
- Word32 L_tmp, L_gain_code, L_max, L_tmp1;
- Word16 code2[L_SUBFR]; /* Fixed codebook excitation */
- Word16 stab_fac, fac, gain_code_lo;
+ /* Scalars */
+ Word32 i, j, i_subfr, select, pit_flag, clip_gain, vad_flag;
+ Word16 codec_mode;
+ Word16 T_op, T_op2, T0, T0_min, T0_max, T0_frac, index;
+ Word16 gain_pit, gain_code, g_coeff[4], g_coeff2[4];
+ Word16 tmp, gain1, gain2, exp, Q_new, mu, shift, max;
+ Word16 voice_fac;
+ Word16 indice[8];
+ Word32 L_tmp, L_gain_code, L_max, L_tmp1;
+ Word16 code2[L_SUBFR]; /* Fixed codebook excitation */
+ Word16 stab_fac, fac, gain_code_lo;
- Word16 corr_gain;
- Word16 *vo_p0, *vo_p1, *vo_p2, *vo_p3;
+ Word16 corr_gain;
+ Word16 *vo_p0, *vo_p1, *vo_p2, *vo_p3;
- st = (Coder_State *) spe_state;
+ st = (Coder_State *) spe_state;
- *ser_size = nb_of_bits[*mode];
- codec_mode = *mode;
+ *ser_size = nb_of_bits[*mode];
+ codec_mode = *mode;
- /*--------------------------------------------------------------------------*
- * Initialize pointers to speech vector. *
- * *
- * *
- * |-------|-------|-------|-------|-------|-------| *
- * past sp sf1 sf2 sf3 sf4 L_NEXT *
- * <------- Total speech buffer (L_TOTAL) ------> *
- * old_speech *
- * <------- LPC analysis window (L_WINDOW) ------> *
- * | <-- present frame (L_FRAME) ----> *
- * p_window | <----- new speech (L_FRAME) ----> *
- * | | *
- * speech | *
- * new_speech *
- *--------------------------------------------------------------------------*/
+ /*--------------------------------------------------------------------------*
+ * Initialize pointers to speech vector. *
+ * *
+ * *
+ * |-------|-------|-------|-------|-------|-------| *
+ * past sp sf1 sf2 sf3 sf4 L_NEXT *
+ * <------- Total speech buffer (L_TOTAL) ------> *
+ * old_speech *
+ * <------- LPC analysis window (L_WINDOW) ------> *
+ * | <-- present frame (L_FRAME) ----> *
+ * p_window | <----- new speech (L_FRAME) ----> *
+ * | | *
+ * speech | *
+ * new_speech *
+ *--------------------------------------------------------------------------*/
- new_speech = old_speech + L_TOTAL - L_FRAME - L_FILT; /* New speech */
- speech = old_speech + L_TOTAL - L_FRAME - L_NEXT; /* Present frame */
- p_window = old_speech + L_TOTAL - L_WINDOW;
+ new_speech = old_speech + L_TOTAL - L_FRAME - L_FILT; /* New speech */
+ speech = old_speech + L_TOTAL - L_FRAME - L_NEXT; /* Present frame */
+ p_window = old_speech + L_TOTAL - L_WINDOW;
- exc = old_exc + PIT_MAX + L_INTERPOL;
- wsp = old_wsp + (PIT_MAX / OPL_DECIM);
+ exc = old_exc + PIT_MAX + L_INTERPOL;
+ wsp = old_wsp + (PIT_MAX / OPL_DECIM);
- /* copy coder memory state into working space */
- Copy(st->old_speech, old_speech, L_TOTAL - L_FRAME);
- Copy(st->old_wsp, old_wsp, PIT_MAX / OPL_DECIM);
- Copy(st->old_exc, old_exc, PIT_MAX + L_INTERPOL);
+ /* copy coder memory state into working space */
+ Copy(st->old_speech, old_speech, L_TOTAL - L_FRAME);
+ Copy(st->old_wsp, old_wsp, PIT_MAX / OPL_DECIM);
+ Copy(st->old_exc, old_exc, PIT_MAX + L_INTERPOL);
- /*---------------------------------------------------------------*
- * Down sampling signal from 16kHz to 12.8kHz *
- * -> The signal is extended by L_FILT samples (padded to zero) *
- * to avoid additional delay (L_FILT samples) in the coder. *
- * The last L_FILT samples are approximated after decimation and *
- * are used (and windowed) only in autocorrelations. *
- *---------------------------------------------------------------*/
+ /*---------------------------------------------------------------*
+ * Down sampling signal from 16kHz to 12.8kHz *
+ * -> The signal is extended by L_FILT samples (padded to zero) *
+ * to avoid additional delay (L_FILT samples) in the coder. *
+ * The last L_FILT samples are approximated after decimation and *
+ * are used (and windowed) only in autocorrelations. *
+ *---------------------------------------------------------------*/
- Decim_12k8(speech16k, L_FRAME16k, new_speech, st->mem_decim);
+ Decim_12k8(speech16k, L_FRAME16k, new_speech, st->mem_decim);
- /* last L_FILT samples for autocorrelation window */
- Copy(st->mem_decim, code, 2 * L_FILT16k);
- Set_zero(error, L_FILT16k); /* set next sample to zero */
- Decim_12k8(error, L_FILT16k, new_speech + L_FRAME, code);
+ /* last L_FILT samples for autocorrelation window */
+ Copy(st->mem_decim, code, 2 * L_FILT16k);
+ Set_zero(error, L_FILT16k); /* set next sample to zero */
+ Decim_12k8(error, L_FILT16k, new_speech + L_FRAME, code);
- /*---------------------------------------------------------------*
- * Perform 50Hz HP filtering of input signal. *
- *---------------------------------------------------------------*/
+ /*---------------------------------------------------------------*
+ * Perform 50Hz HP filtering of input signal. *
+ *---------------------------------------------------------------*/
- HP50_12k8(new_speech, L_FRAME, st->mem_sig_in);
+ HP50_12k8(new_speech, L_FRAME, st->mem_sig_in);
- /* last L_FILT samples for autocorrelation window */
- Copy(st->mem_sig_in, code, 6);
- HP50_12k8(new_speech + L_FRAME, L_FILT, code);
+ /* last L_FILT samples for autocorrelation window */
+ Copy(st->mem_sig_in, code, 6);
+ HP50_12k8(new_speech + L_FRAME, L_FILT, code);
- /*---------------------------------------------------------------*
- * Perform fixed preemphasis through 1 - g z^-1 *
- * Scale signal to get maximum of precision in filtering *
- *---------------------------------------------------------------*/
+ /*---------------------------------------------------------------*
+ * Perform fixed preemphasis through 1 - g z^-1 *
+ * Scale signal to get maximum of precision in filtering *
+ *---------------------------------------------------------------*/
- mu = PREEMPH_FAC >> 1; /* Q15 --> Q14 */
+ mu = PREEMPH_FAC >> 1; /* Q15 --> Q14 */
- /* get max of new preemphased samples (L_FRAME+L_FILT) */
- L_tmp = new_speech[0] << 15;
- L_tmp -= (st->mem_preemph * mu)<<1;
- L_max = L_abs(L_tmp);
+ /* get max of new preemphased samples (L_FRAME+L_FILT) */
+ L_tmp = new_speech[0] << 15;
+ L_tmp -= (st->mem_preemph * mu)<<1;
+ L_max = L_abs(L_tmp);
- for (i = 1; i < L_FRAME + L_FILT; i++)
- {
- L_tmp = new_speech[i] << 15;
- L_tmp -= (new_speech[i - 1] * mu)<<1;
- L_tmp = L_abs(L_tmp);
- if(L_tmp > L_max)
- {
- L_max = L_tmp;
- }
- }
+ for (i = 1; i < L_FRAME + L_FILT; i++)
+ {
+ L_tmp = new_speech[i] << 15;
+ L_tmp -= (new_speech[i - 1] * mu)<<1;
+ L_tmp = L_abs(L_tmp);
+ if(L_tmp > L_max)
+ {
+ L_max = L_tmp;
+ }
+ }
- /* get scaling factor for new and previous samples */
- /* limit scaling to Q_MAX to keep dynamic for ringing in low signal */
- /* limit scaling to Q_MAX also to avoid a[0]<1 in syn_filt_32 */
- tmp = extract_h(L_max);
- if (tmp == 0)
- {
- shift = Q_MAX;
- } else
- {
- shift = norm_s(tmp) - 1;
- if (shift < 0)
- {
- shift = 0;
- }
- if (shift > Q_MAX)
- {
- shift = Q_MAX;
- }
- }
- Q_new = shift;
- if (Q_new > st->Q_max[0])
- {
- Q_new = st->Q_max[0];
- }
- if (Q_new > st->Q_max[1])
- {
- Q_new = st->Q_max[1];
- }
- exp = (Q_new - st->Q_old);
- st->Q_old = Q_new;
- st->Q_max[1] = st->Q_max[0];
- st->Q_max[0] = shift;
+ /* get scaling factor for new and previous samples */
+ /* limit scaling to Q_MAX to keep dynamic for ringing in low signal */
+ /* limit scaling to Q_MAX also to avoid a[0]<1 in syn_filt_32 */
+ tmp = extract_h(L_max);
+ if (tmp == 0)
+ {
+ shift = Q_MAX;
+ } else
+ {
+ shift = norm_s(tmp) - 1;
+ if (shift < 0)
+ {
+ shift = 0;
+ }
+ if (shift > Q_MAX)
+ {
+ shift = Q_MAX;
+ }
+ }
+ Q_new = shift;
+ if (Q_new > st->Q_max[0])
+ {
+ Q_new = st->Q_max[0];
+ }
+ if (Q_new > st->Q_max[1])
+ {
+ Q_new = st->Q_max[1];
+ }
+ exp = (Q_new - st->Q_old);
+ st->Q_old = Q_new;
+ st->Q_max[1] = st->Q_max[0];
+ st->Q_max[0] = shift;
- /* preemphasis with scaling (L_FRAME+L_FILT) */
- tmp = new_speech[L_FRAME - 1];
+ /* preemphasis with scaling (L_FRAME+L_FILT) */
+ tmp = new_speech[L_FRAME - 1];
- for (i = L_FRAME + L_FILT - 1; i > 0; i--)
- {
- L_tmp = new_speech[i] << 15;
- L_tmp -= (new_speech[i - 1] * mu)<<1;
- L_tmp = (L_tmp << Q_new);
- new_speech[i] = vo_round(L_tmp);
- }
+ for (i = L_FRAME + L_FILT - 1; i > 0; i--)
+ {
+ L_tmp = new_speech[i] << 15;
+ L_tmp -= (new_speech[i - 1] * mu)<<1;
+ L_tmp = (L_tmp << Q_new);
+ new_speech[i] = vo_round(L_tmp);
+ }
- L_tmp = new_speech[0] << 15;
- L_tmp -= (st->mem_preemph * mu)<<1;
- L_tmp = (L_tmp << Q_new);
- new_speech[0] = vo_round(L_tmp);
+ L_tmp = new_speech[0] << 15;
+ L_tmp -= (st->mem_preemph * mu)<<1;
+ L_tmp = (L_tmp << Q_new);
+ new_speech[0] = vo_round(L_tmp);
- st->mem_preemph = tmp;
+ st->mem_preemph = tmp;
- /* scale previous samples and memory */
+ /* scale previous samples and memory */
- Scale_sig(old_speech, L_TOTAL - L_FRAME - L_FILT, exp);
- Scale_sig(old_exc, PIT_MAX + L_INTERPOL, exp);
- Scale_sig(st->mem_syn, M, exp);
- Scale_sig(st->mem_decim2, 3, exp);
- Scale_sig(&(st->mem_wsp), 1, exp);
- Scale_sig(&(st->mem_w0), 1, exp);
+ Scale_sig(old_speech, L_TOTAL - L_FRAME - L_FILT, exp);
+ Scale_sig(old_exc, PIT_MAX + L_INTERPOL, exp);
+ Scale_sig(st->mem_syn, M, exp);
+ Scale_sig(st->mem_decim2, 3, exp);
+ Scale_sig(&(st->mem_wsp), 1, exp);
+ Scale_sig(&(st->mem_w0), 1, exp);
- /*------------------------------------------------------------------------*
- * Call VAD *
- * Preemphesis scale down signal in low frequency and keep dynamic in HF.*
- * Vad work slightly in futur (new_speech = speech + L_NEXT - L_FILT). *
- *------------------------------------------------------------------------*/
- Copy(new_speech, buf, L_FRAME);
+ /*------------------------------------------------------------------------*
+ * Call VAD *
+ * Preemphesis scale down signal in low frequency and keep dynamic in HF.*
+ * Vad work slightly in futur (new_speech = speech + L_NEXT - L_FILT). *
+ *------------------------------------------------------------------------*/
+ Copy(new_speech, buf, L_FRAME);
#ifdef ASM_OPT /* asm optimization branch */
- Scale_sig_opt(buf, L_FRAME, 1 - Q_new);
+ Scale_sig_opt(buf, L_FRAME, 1 - Q_new);
#else
- Scale_sig(buf, L_FRAME, 1 - Q_new);
+ Scale_sig(buf, L_FRAME, 1 - Q_new);
#endif
- vad_flag = wb_vad(st->vadSt, buf); /* Voice Activity Detection */
- if (vad_flag == 0)
- {
- st->vad_hist = (st->vad_hist + 1);
- } else
- {
- st->vad_hist = 0;
- }
+ vad_flag = wb_vad(st->vadSt, buf); /* Voice Activity Detection */
+ if (vad_flag == 0)
+ {
+ st->vad_hist = (st->vad_hist + 1);
+ } else
+ {
+ st->vad_hist = 0;
+ }
- /* DTX processing */
- if (allow_dtx != 0)
- {
- /* Note that mode may change here */
- tx_dtx_handler(st->dtx_encSt, vad_flag, mode);
- *ser_size = nb_of_bits[*mode];
- }
+ /* DTX processing */
+ if (allow_dtx != 0)
+ {
+ /* Note that mode may change here */
+ tx_dtx_handler(st->dtx_encSt, vad_flag, mode);
+ *ser_size = nb_of_bits[*mode];
+ }
- if(*mode != MRDTX)
- {
- Parm_serial(vad_flag, 1, &prms);
- }
- /*------------------------------------------------------------------------*
- * Perform LPC analysis *
- * ~~~~~~~~~~~~~~~~~~~~ *
- * - autocorrelation + lag windowing *
- * - Levinson-durbin algorithm to find a[] *
- * - convert a[] to isp[] *
- * - convert isp[] to isf[] for quantization *
- * - quantize and code the isf[] *
- * - convert isf[] to isp[] for interpolation *
- * - find the interpolated ISPs and convert to a[] for the 4 subframes *
- *------------------------------------------------------------------------*/
+ if(*mode != MRDTX)
+ {
+ Parm_serial(vad_flag, 1, &prms);
+ }
+ /*------------------------------------------------------------------------*
+ * Perform LPC analysis *
+ * ~~~~~~~~~~~~~~~~~~~~ *
+ * - autocorrelation + lag windowing *
+ * - Levinson-durbin algorithm to find a[] *
+ * - convert a[] to isp[] *
+ * - convert isp[] to isf[] for quantization *
+ * - quantize and code the isf[] *
+ * - convert isf[] to isp[] for interpolation *
+ * - find the interpolated ISPs and convert to a[] for the 4 subframes *
+ *------------------------------------------------------------------------*/
- /* LP analysis centered at 4nd subframe */
- Autocorr(p_window, M, r_h, r_l); /* Autocorrelations */
- Lag_window(r_h, r_l); /* Lag windowing */
- Levinson(r_h, r_l, A, rc, st->mem_levinson); /* Levinson Durbin */
- Az_isp(A, ispnew, st->ispold); /* From A(z) to ISP */
+ /* LP analysis centered at 4nd subframe */
+ Autocorr(p_window, M, r_h, r_l); /* Autocorrelations */
+ Lag_window(r_h, r_l); /* Lag windowing */
+ Levinson(r_h, r_l, A, rc, st->mem_levinson); /* Levinson Durbin */
+ Az_isp(A, ispnew, st->ispold); /* From A(z) to ISP */
- /* Find the interpolated ISPs and convert to a[] for all subframes */
- Int_isp(st->ispold, ispnew, interpol_frac, A);
+ /* Find the interpolated ISPs and convert to a[] for all subframes */
+ Int_isp(st->ispold, ispnew, interpol_frac, A);
- /* update ispold[] for the next frame */
- Copy(ispnew, st->ispold, M);
+ /* update ispold[] for the next frame */
+ Copy(ispnew, st->ispold, M);
- /* Convert ISPs to frequency domain 0..6400 */
- Isp_isf(ispnew, isf, M);
+ /* Convert ISPs to frequency domain 0..6400 */
+ Isp_isf(ispnew, isf, M);
- /* check resonance for pitch clipping algorithm */
- Gp_clip_test_isf(isf, st->gp_clip);
+ /* check resonance for pitch clipping algorithm */
+ Gp_clip_test_isf(isf, st->gp_clip);
- /*----------------------------------------------------------------------*
- * Perform PITCH_OL analysis *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~ *
- * - Find the residual res[] for the whole speech frame *
- * - Find the weighted input speech wsp[] for the whole speech frame *
- * - scale wsp[] to avoid overflow in pitch estimation *
- * - Find open loop pitch lag for whole speech frame *
- *----------------------------------------------------------------------*/
- p_A = A;
- for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR)
- {
- /* Weighting of LPC coefficients */
- Weight_a(p_A, Ap, GAMMA1, M);
+ /*----------------------------------------------------------------------*
+ * Perform PITCH_OL analysis *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~ *
+ * - Find the residual res[] for the whole speech frame *
+ * - Find the weighted input speech wsp[] for the whole speech frame *
+ * - scale wsp[] to avoid overflow in pitch estimation *
+ * - Find open loop pitch lag for whole speech frame *
+ *----------------------------------------------------------------------*/
+ p_A = A;
+ for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR)
+ {
+ /* Weighting of LPC coefficients */
+ Weight_a(p_A, Ap, GAMMA1, M);
#ifdef ASM_OPT /* asm optimization branch */
- Residu_opt(Ap, &speech[i_subfr], &wsp[i_subfr], L_SUBFR);
+ Residu_opt(Ap, &speech[i_subfr], &wsp[i_subfr], L_SUBFR);
#else
- Residu(Ap, &speech[i_subfr], &wsp[i_subfr], L_SUBFR);
+ Residu(Ap, &speech[i_subfr], &wsp[i_subfr], L_SUBFR);
#endif
- p_A += (M + 1);
- }
+ p_A += (M + 1);
+ }
- Deemph2(wsp, TILT_FAC, L_FRAME, &(st->mem_wsp));
+ Deemph2(wsp, TILT_FAC, L_FRAME, &(st->mem_wsp));
- /* find maximum value on wsp[] for 12 bits scaling */
- max = 0;
- for (i = 0; i < L_FRAME; i++)
- {
- tmp = abs_s(wsp[i]);
- if(tmp > max)
- {
- max = tmp;
- }
- }
- tmp = st->old_wsp_max;
- if(max > tmp)
- {
- tmp = max; /* tmp = max(wsp_max, old_wsp_max) */
- }
- st->old_wsp_max = max;
+ /* find maximum value on wsp[] for 12 bits scaling */
+ max = 0;
+ for (i = 0; i < L_FRAME; i++)
+ {
+ tmp = abs_s(wsp[i]);
+ if(tmp > max)
+ {
+ max = tmp;
+ }
+ }
+ tmp = st->old_wsp_max;
+ if(max > tmp)
+ {
+ tmp = max; /* tmp = max(wsp_max, old_wsp_max) */
+ }
+ st->old_wsp_max = max;
- shift = norm_s(tmp) - 3;
- if (shift > 0)
- {
- shift = 0; /* shift = 0..-3 */
- }
- /* decimation of wsp[] to search pitch in LF and to reduce complexity */
- LP_Decim2(wsp, L_FRAME, st->mem_decim2);
+ shift = norm_s(tmp) - 3;
+ if (shift > 0)
+ {
+ shift = 0; /* shift = 0..-3 */
+ }
+ /* decimation of wsp[] to search pitch in LF and to reduce complexity */
+ LP_Decim2(wsp, L_FRAME, st->mem_decim2);
- /* scale wsp[] in 12 bits to avoid overflow */
+ /* scale wsp[] in 12 bits to avoid overflow */
#ifdef ASM_OPT /* asm optimization branch */
- Scale_sig_opt(wsp, L_FRAME / OPL_DECIM, shift);
+ Scale_sig_opt(wsp, L_FRAME / OPL_DECIM, shift);
#else
- Scale_sig(wsp, L_FRAME / OPL_DECIM, shift);
+ Scale_sig(wsp, L_FRAME / OPL_DECIM, shift);
#endif
- /* scale old_wsp (warning: exp must be Q_new-Q_old) */
- exp = exp + (shift - st->old_wsp_shift);
- st->old_wsp_shift = shift;
+ /* scale old_wsp (warning: exp must be Q_new-Q_old) */
+ exp = exp + (shift - st->old_wsp_shift);
+ st->old_wsp_shift = shift;
- Scale_sig(old_wsp, PIT_MAX / OPL_DECIM, exp);
- Scale_sig(st->old_hp_wsp, PIT_MAX / OPL_DECIM, exp);
+ Scale_sig(old_wsp, PIT_MAX / OPL_DECIM, exp);
+ Scale_sig(st->old_hp_wsp, PIT_MAX / OPL_DECIM, exp);
- scale_mem_Hp_wsp(st->hp_wsp_mem, exp);
+ scale_mem_Hp_wsp(st->hp_wsp_mem, exp);
- /* Find open loop pitch lag for whole speech frame */
+ /* Find open loop pitch lag for whole speech frame */
- if(*ser_size == NBBITS_7k)
- {
- /* Find open loop pitch lag for whole speech frame */
- T_op = Pitch_med_ol(wsp, st, L_FRAME / OPL_DECIM);
- } else
- {
- /* Find open loop pitch lag for first 1/2 frame */
- T_op = Pitch_med_ol(wsp, st, (L_FRAME/2) / OPL_DECIM);
- }
+ if(*ser_size == NBBITS_7k)
+ {
+ /* Find open loop pitch lag for whole speech frame */
+ T_op = Pitch_med_ol(wsp, st, L_FRAME / OPL_DECIM);
+ } else
+ {
+ /* Find open loop pitch lag for first 1/2 frame */
+ T_op = Pitch_med_ol(wsp, st, (L_FRAME/2) / OPL_DECIM);
+ }
- if(st->ol_gain > 19661) /* 0.6 in Q15 */
- {
- st->old_T0_med = Med_olag(T_op, st->old_ol_lag);
- st->ada_w = 32767;
- } else
- {
- st->ada_w = vo_mult(st->ada_w, 29491);
- }
+ if(st->ol_gain > 19661) /* 0.6 in Q15 */
+ {
+ st->old_T0_med = Med_olag(T_op, st->old_ol_lag);
+ st->ada_w = 32767;
+ } else
+ {
+ st->ada_w = vo_mult(st->ada_w, 29491);
+ }
- if(st->ada_w < 26214)
- st->ol_wght_flg = 0;
- else
- st->ol_wght_flg = 1;
+ if(st->ada_w < 26214)
+ st->ol_wght_flg = 0;
+ else
+ st->ol_wght_flg = 1;
- wb_vad_tone_detection(st->vadSt, st->ol_gain);
- T_op *= OPL_DECIM;
+ wb_vad_tone_detection(st->vadSt, st->ol_gain);
+ T_op *= OPL_DECIM;
- if(*ser_size != NBBITS_7k)
- {
- /* Find open loop pitch lag for second 1/2 frame */
- T_op2 = Pitch_med_ol(wsp + ((L_FRAME / 2) / OPL_DECIM), st, (L_FRAME/2) / OPL_DECIM);
+ if(*ser_size != NBBITS_7k)
+ {
+ /* Find open loop pitch lag for second 1/2 frame */
+ T_op2 = Pitch_med_ol(wsp + ((L_FRAME / 2) / OPL_DECIM), st, (L_FRAME/2) / OPL_DECIM);
- if(st->ol_gain > 19661) /* 0.6 in Q15 */
- {
- st->old_T0_med = Med_olag(T_op2, st->old_ol_lag);
- st->ada_w = 32767;
- } else
- {
- st->ada_w = mult(st->ada_w, 29491);
- }
+ if(st->ol_gain > 19661) /* 0.6 in Q15 */
+ {
+ st->old_T0_med = Med_olag(T_op2, st->old_ol_lag);
+ st->ada_w = 32767;
+ } else
+ {
+ st->ada_w = mult(st->ada_w, 29491);
+ }
- if(st->ada_w < 26214)
- st->ol_wght_flg = 0;
- else
- st->ol_wght_flg = 1;
+ if(st->ada_w < 26214)
+ st->ol_wght_flg = 0;
+ else
+ st->ol_wght_flg = 1;
- wb_vad_tone_detection(st->vadSt, st->ol_gain);
+ wb_vad_tone_detection(st->vadSt, st->ol_gain);
- T_op2 *= OPL_DECIM;
+ T_op2 *= OPL_DECIM;
- } else
- {
- T_op2 = T_op;
- }
- /*----------------------------------------------------------------------*
- * DTX-CNG *
- *----------------------------------------------------------------------*/
- if(*mode == MRDTX) /* CNG mode */
- {
- /* Buffer isf's and energy */
+ } else
+ {
+ T_op2 = T_op;
+ }
+ /*----------------------------------------------------------------------*
+ * DTX-CNG *
+ *----------------------------------------------------------------------*/
+ if(*mode == MRDTX) /* CNG mode */
+ {
+ /* Buffer isf's and energy */
#ifdef ASM_OPT /* asm optimization branch */
- Residu_opt(&A[3 * (M + 1)], speech, exc, L_FRAME);
+ Residu_opt(&A[3 * (M + 1)], speech, exc, L_FRAME);
#else
- Residu(&A[3 * (M + 1)], speech, exc, L_FRAME);
+ Residu(&A[3 * (M + 1)], speech, exc, L_FRAME);
#endif
- for (i = 0; i < L_FRAME; i++)
- {
- exc2[i] = shr(exc[i], Q_new);
- }
+ for (i = 0; i < L_FRAME; i++)
+ {
+ exc2[i] = shr(exc[i], Q_new);
+ }
- L_tmp = 0;
- for (i = 0; i < L_FRAME; i++)
- L_tmp += (exc2[i] * exc2[i])<<1;
+ L_tmp = 0;
+ for (i = 0; i < L_FRAME; i++)
+ L_tmp += (exc2[i] * exc2[i])<<1;
- L_tmp >>= 1;
+ L_tmp >>= 1;
- dtx_buffer(st->dtx_encSt, isf, L_tmp, codec_mode);
+ dtx_buffer(st->dtx_encSt, isf, L_tmp, codec_mode);
- /* Quantize and code the ISFs */
- dtx_enc(st->dtx_encSt, isf, exc2, &prms);
+ /* Quantize and code the ISFs */
+ dtx_enc(st->dtx_encSt, isf, exc2, &prms);
- /* Convert ISFs to the cosine domain */
- Isf_isp(isf, ispnew_q, M);
- Isp_Az(ispnew_q, Aq, M, 0);
+ /* Convert ISFs to the cosine domain */
+ Isf_isp(isf, ispnew_q, M);
+ Isp_Az(ispnew_q, Aq, M, 0);
- for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR)
- {
- corr_gain = synthesis(Aq, &exc2[i_subfr], 0, &speech16k[i_subfr * 5 / 4], st);
- }
- Copy(isf, st->isfold, M);
+ for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR)
+ {
+ corr_gain = synthesis(Aq, &exc2[i_subfr], 0, &speech16k[i_subfr * 5 / 4], st);
+ }
+ Copy(isf, st->isfold, M);
- /* reset speech coder memories */
- Reset_encoder(st, 0);
+ /* reset speech coder memories */
+ Reset_encoder(st, 0);
- /*--------------------------------------------------*
- * Update signal for next frame. *
- * -> save past of speech[] and wsp[]. *
- *--------------------------------------------------*/
+ /*--------------------------------------------------*
+ * Update signal for next frame. *
+ * -> save past of speech[] and wsp[]. *
+ *--------------------------------------------------*/
- Copy(&old_speech[L_FRAME], st->old_speech, L_TOTAL - L_FRAME);
- Copy(&old_wsp[L_FRAME / OPL_DECIM], st->old_wsp, PIT_MAX / OPL_DECIM);
+ Copy(&old_speech[L_FRAME], st->old_speech, L_TOTAL - L_FRAME);
+ Copy(&old_wsp[L_FRAME / OPL_DECIM], st->old_wsp, PIT_MAX / OPL_DECIM);
- return;
- }
- /*----------------------------------------------------------------------*
- * ACELP *
- *----------------------------------------------------------------------*/
+ return;
+ }
+ /*----------------------------------------------------------------------*
+ * ACELP *
+ *----------------------------------------------------------------------*/
- /* Quantize and code the ISFs */
+ /* Quantize and code the ISFs */
- if (*ser_size <= NBBITS_7k)
- {
- Qpisf_2s_36b(isf, isf, st->past_isfq, indice, 4);
+ if (*ser_size <= NBBITS_7k)
+ {
+ Qpisf_2s_36b(isf, isf, st->past_isfq, indice, 4);
- Parm_serial(indice[0], 8, &prms);
- Parm_serial(indice[1], 8, &prms);
- Parm_serial(indice[2], 7, &prms);
- Parm_serial(indice[3], 7, &prms);
- Parm_serial(indice[4], 6, &prms);
- } else
- {
- Qpisf_2s_46b(isf, isf, st->past_isfq, indice, 4);
+ Parm_serial(indice[0], 8, &prms);
+ Parm_serial(indice[1], 8, &prms);
+ Parm_serial(indice[2], 7, &prms);
+ Parm_serial(indice[3], 7, &prms);
+ Parm_serial(indice[4], 6, &prms);
+ } else
+ {
+ Qpisf_2s_46b(isf, isf, st->past_isfq, indice, 4);
- Parm_serial(indice[0], 8, &prms);
- Parm_serial(indice[1], 8, &prms);
- Parm_serial(indice[2], 6, &prms);
- Parm_serial(indice[3], 7, &prms);
- Parm_serial(indice[4], 7, &prms);
- Parm_serial(indice[5], 5, &prms);
- Parm_serial(indice[6], 5, &prms);
- }
+ Parm_serial(indice[0], 8, &prms);
+ Parm_serial(indice[1], 8, &prms);
+ Parm_serial(indice[2], 6, &prms);
+ Parm_serial(indice[3], 7, &prms);
+ Parm_serial(indice[4], 7, &prms);
+ Parm_serial(indice[5], 5, &prms);
+ Parm_serial(indice[6], 5, &prms);
+ }
- /* Check stability on isf : distance between old isf and current isf */
+ /* Check stability on isf : distance between old isf and current isf */
- L_tmp = 0;
- for (i = 0; i < M - 1; i++)
- {
- tmp = vo_sub(isf[i], st->isfold[i]);
- L_tmp += (tmp * tmp)<<1;
- }
+ L_tmp = 0;
+ for (i = 0; i < M - 1; i++)
+ {
+ tmp = vo_sub(isf[i], st->isfold[i]);
+ L_tmp += (tmp * tmp)<<1;
+ }
- tmp = extract_h(L_shl2(L_tmp, 8));
+ tmp = extract_h(L_shl2(L_tmp, 8));
- tmp = vo_mult(tmp, 26214); /* tmp = L_tmp*0.8/256 */
- tmp = vo_sub(20480, tmp); /* 1.25 - tmp (in Q14) */
+ tmp = vo_mult(tmp, 26214); /* tmp = L_tmp*0.8/256 */
+ tmp = vo_sub(20480, tmp); /* 1.25 - tmp (in Q14) */
- stab_fac = shl(tmp, 1);
+ stab_fac = shl(tmp, 1);
- if (stab_fac < 0)
- {
- stab_fac = 0;
- }
- Copy(isf, st->isfold, M);
+ if (stab_fac < 0)
+ {
+ stab_fac = 0;
+ }
+ Copy(isf, st->isfold, M);
- /* Convert ISFs to the cosine domain */
- Isf_isp(isf, ispnew_q, M);
+ /* Convert ISFs to the cosine domain */
+ Isf_isp(isf, ispnew_q, M);
- if (st->first_frame != 0)
- {
- st->first_frame = 0;
- Copy(ispnew_q, st->ispold_q, M);
- }
- /* Find the interpolated ISPs and convert to a[] for all subframes */
+ if (st->first_frame != 0)
+ {
+ st->first_frame = 0;
+ Copy(ispnew_q, st->ispold_q, M);
+ }
+ /* Find the interpolated ISPs and convert to a[] for all subframes */
- Int_isp(st->ispold_q, ispnew_q, interpol_frac, Aq);
+ Int_isp(st->ispold_q, ispnew_q, interpol_frac, Aq);
- /* update ispold[] for the next frame */
- Copy(ispnew_q, st->ispold_q, M);
+ /* update ispold[] for the next frame */
+ Copy(ispnew_q, st->ispold_q, M);
- p_Aq = Aq;
- for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR)
- {
+ p_Aq = Aq;
+ for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR)
+ {
#ifdef ASM_OPT /* asm optimization branch */
- Residu_opt(p_Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR);
+ Residu_opt(p_Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR);
#else
- Residu(p_Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR);
+ Residu(p_Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR);
#endif
- p_Aq += (M + 1);
- }
+ p_Aq += (M + 1);
+ }
- /* Buffer isf's and energy for dtx on non-speech frame */
- if (vad_flag == 0)
- {
- for (i = 0; i < L_FRAME; i++)
- {
- exc2[i] = exc[i] >> Q_new;
- }
- L_tmp = 0;
- for (i = 0; i < L_FRAME; i++)
- L_tmp += (exc2[i] * exc2[i])<<1;
- L_tmp >>= 1;
+ /* Buffer isf's and energy for dtx on non-speech frame */
+ if (vad_flag == 0)
+ {
+ for (i = 0; i < L_FRAME; i++)
+ {
+ exc2[i] = exc[i] >> Q_new;
+ }
+ L_tmp = 0;
+ for (i = 0; i < L_FRAME; i++) {
+ Word32 tmp = L_mult(exc2[i], exc2[i]); // (exc2[i] * exc2[i])<<1;
+ L_tmp = L_add(L_tmp, tmp);
+ }
+ L_tmp >>= 1;
- dtx_buffer(st->dtx_encSt, isf, L_tmp, codec_mode);
- }
- /* range for closed loop pitch search in 1st subframe */
+ dtx_buffer(st->dtx_encSt, isf, L_tmp, codec_mode);
+ }
+ /* range for closed loop pitch search in 1st subframe */
- T0_min = T_op - 8;
- if (T0_min < PIT_MIN)
- {
- T0_min = PIT_MIN;
- }
- T0_max = (T0_min + 15);
+ T0_min = T_op - 8;
+ if (T0_min < PIT_MIN)
+ {
+ T0_min = PIT_MIN;
+ }
+ T0_max = (T0_min + 15);
- if(T0_max > PIT_MAX)
- {
- T0_max = PIT_MAX;
- T0_min = T0_max - 15;
- }
- /*------------------------------------------------------------------------*
- * Loop for every subframe in the analysis frame *
- *------------------------------------------------------------------------*
- * To find the pitch and innovation parameters. The subframe size is *
- * L_SUBFR and the loop is repeated L_FRAME/L_SUBFR times. *
- * - compute the target signal for pitch search *
- * - compute impulse response of weighted synthesis filter (h1[]) *
- * - find the closed-loop pitch parameters *
- * - encode the pitch dealy *
- * - find 2 lt prediction (with / without LP filter for lt pred) *
- * - find 2 pitch gains and choose the best lt prediction. *
- * - find target vector for codebook search *
- * - update the impulse response h1[] for codebook search *
- * - correlation between target vector and impulse response *
- * - codebook search and encoding *
- * - VQ of pitch and codebook gains *
- * - find voicing factor and tilt of code for next subframe. *
- * - update states of weighting filter *
- * - find excitation and synthesis speech *
- *------------------------------------------------------------------------*/
- p_A = A;
- p_Aq = Aq;
- for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR)
- {
- pit_flag = i_subfr;
- if ((i_subfr == 2 * L_SUBFR) && (*ser_size > NBBITS_7k))
- {
- pit_flag = 0;
- /* range for closed loop pitch search in 3rd subframe */
- T0_min = (T_op2 - 8);
+ if(T0_max > PIT_MAX)
+ {
+ T0_max = PIT_MAX;
+ T0_min = T0_max - 15;
+ }
+ /*------------------------------------------------------------------------*
+ * Loop for every subframe in the analysis frame *
+ *------------------------------------------------------------------------*
+ * To find the pitch and innovation parameters. The subframe size is *
+ * L_SUBFR and the loop is repeated L_FRAME/L_SUBFR times. *
+ * - compute the target signal for pitch search *
+ * - compute impulse response of weighted synthesis filter (h1[]) *
+ * - find the closed-loop pitch parameters *
+ * - encode the pitch dealy *
+ * - find 2 lt prediction (with / without LP filter for lt pred) *
+ * - find 2 pitch gains and choose the best lt prediction. *
+ * - find target vector for codebook search *
+ * - update the impulse response h1[] for codebook search *
+ * - correlation between target vector and impulse response *
+ * - codebook search and encoding *
+ * - VQ of pitch and codebook gains *
+ * - find voicing factor and tilt of code for next subframe. *
+ * - update states of weighting filter *
+ * - find excitation and synthesis speech *
+ *------------------------------------------------------------------------*/
+ p_A = A;
+ p_Aq = Aq;
+ for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR)
+ {
+ pit_flag = i_subfr;
+ if ((i_subfr == 2 * L_SUBFR) && (*ser_size > NBBITS_7k))
+ {
+ pit_flag = 0;
+ /* range for closed loop pitch search in 3rd subframe */
+ T0_min = (T_op2 - 8);
- if (T0_min < PIT_MIN)
- {
- T0_min = PIT_MIN;
- }
- T0_max = (T0_min + 15);
- if (T0_max > PIT_MAX)
- {
- T0_max = PIT_MAX;
- T0_min = (T0_max - 15);
- }
- }
- /*-----------------------------------------------------------------------*
- * *
- * Find the target vector for pitch search: *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *
- * *
- * |------| res[n] *
- * speech[n]---| A(z) |-------- *
- * |------| | |--------| error[n] |------| *
- * zero -- (-)--| 1/A(z) |-----------| W(z) |-- target *
- * exc |--------| |------| *
- * *
- * Instead of subtracting the zero-input response of filters from *
- * the weighted input speech, the above configuration is used to *
- * compute the target vector. *
- * *
- *-----------------------------------------------------------------------*/
+ if (T0_min < PIT_MIN)
+ {
+ T0_min = PIT_MIN;
+ }
+ T0_max = (T0_min + 15);
+ if (T0_max > PIT_MAX)
+ {
+ T0_max = PIT_MAX;
+ T0_min = (T0_max - 15);
+ }
+ }
+ /*-----------------------------------------------------------------------*
+ * *
+ * Find the target vector for pitch search: *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *
+ * *
+ * |------| res[n] *
+ * speech[n]---| A(z) |-------- *
+ * |------| | |--------| error[n] |------| *
+ * zero -- (-)--| 1/A(z) |-----------| W(z) |-- target *
+ * exc |--------| |------| *
+ * *
+ * Instead of subtracting the zero-input response of filters from *
+ * the weighted input speech, the above configuration is used to *
+ * compute the target vector. *
+ * *
+ *-----------------------------------------------------------------------*/
- for (i = 0; i < M; i++)
- {
- error[i] = vo_sub(speech[i + i_subfr - M], st->mem_syn[i]);
- }
+ for (i = 0; i < M; i++)
+ {
+ error[i] = vo_sub(speech[i + i_subfr - M], st->mem_syn[i]);
+ }
#ifdef ASM_OPT /* asm optimization branch */
- Residu_opt(p_Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR);
+ Residu_opt(p_Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR);
#else
- Residu(p_Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR);
+ Residu(p_Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR);
#endif
- Syn_filt(p_Aq, &exc[i_subfr], error + M, L_SUBFR, error, 0);
- Weight_a(p_A, Ap, GAMMA1, M);
+ Syn_filt(p_Aq, &exc[i_subfr], error + M, L_SUBFR, error, 0);
+ Weight_a(p_A, Ap, GAMMA1, M);
#ifdef ASM_OPT /* asm optimization branch */
- Residu_opt(Ap, error + M, xn, L_SUBFR);
+ Residu_opt(Ap, error + M, xn, L_SUBFR);
#else
- Residu(Ap, error + M, xn, L_SUBFR);
+ Residu(Ap, error + M, xn, L_SUBFR);
#endif
- Deemph2(xn, TILT_FAC, L_SUBFR, &(st->mem_w0));
+ Deemph2(xn, TILT_FAC, L_SUBFR, &(st->mem_w0));
- /*----------------------------------------------------------------------*
- * Find approx. target in residual domain "cn[]" for inovation search. *
- *----------------------------------------------------------------------*/
- /* first half: xn[] --> cn[] */
- Set_zero(code, M);
- Copy(xn, code + M, L_SUBFR / 2);
- tmp = 0;
- Preemph2(code + M, TILT_FAC, L_SUBFR / 2, &tmp);
- Weight_a(p_A, Ap, GAMMA1, M);
- Syn_filt(Ap,code + M, code + M, L_SUBFR / 2, code, 0);
+ /*----------------------------------------------------------------------*
+ * Find approx. target in residual domain "cn[]" for inovation search. *
+ *----------------------------------------------------------------------*/
+ /* first half: xn[] --> cn[] */
+ Set_zero(code, M);
+ Copy(xn, code + M, L_SUBFR / 2);
+ tmp = 0;
+ Preemph2(code + M, TILT_FAC, L_SUBFR / 2, &tmp);
+ Weight_a(p_A, Ap, GAMMA1, M);
+ Syn_filt(Ap,code + M, code + M, L_SUBFR / 2, code, 0);
#ifdef ASM_OPT /* asm optimization branch */
- Residu_opt(p_Aq,code + M, cn, L_SUBFR / 2);
+ Residu_opt(p_Aq,code + M, cn, L_SUBFR / 2);
#else
- Residu(p_Aq,code + M, cn, L_SUBFR / 2);
+ Residu(p_Aq,code + M, cn, L_SUBFR / 2);
#endif
- /* second half: res[] --> cn[] (approximated and faster) */
- Copy(&exc[i_subfr + (L_SUBFR / 2)], cn + (L_SUBFR / 2), L_SUBFR / 2);
+ /* second half: res[] --> cn[] (approximated and faster) */
+ Copy(&exc[i_subfr + (L_SUBFR / 2)], cn + (L_SUBFR / 2), L_SUBFR / 2);
- /*---------------------------------------------------------------*
- * Compute impulse response, h1[], of weighted synthesis filter *
- *---------------------------------------------------------------*/
+ /*---------------------------------------------------------------*
+ * Compute impulse response, h1[], of weighted synthesis filter *
+ *---------------------------------------------------------------*/
- Set_zero(error, M + L_SUBFR);
- Weight_a(p_A, error + M, GAMMA1, M);
+ Set_zero(error, M + L_SUBFR);
+ Weight_a(p_A, error + M, GAMMA1, M);
- vo_p0 = error+M;
- vo_p3 = h1;
- for (i = 0; i < L_SUBFR; i++)
- {
- L_tmp = *vo_p0 << 14; /* x4 (Q12 to Q14) */
- vo_p1 = p_Aq + 1;
- vo_p2 = vo_p0-1;
- for (j = 1; j <= M/4; j++)
- {
- L_tmp -= *vo_p1++ * *vo_p2--;
- L_tmp -= *vo_p1++ * *vo_p2--;
- L_tmp -= *vo_p1++ * *vo_p2--;
- L_tmp -= *vo_p1++ * *vo_p2--;
- }
- *vo_p3++ = *vo_p0++ = vo_round((L_tmp <<4));
- }
- /* deemph without division by 2 -> Q14 to Q15 */
- tmp = 0;
- Deemph2(h1, TILT_FAC, L_SUBFR, &tmp); /* h1 in Q14 */
+ vo_p0 = error+M;
+ vo_p3 = h1;
+ for (i = 0; i < L_SUBFR; i++)
+ {
+ L_tmp = *vo_p0 << 14; /* x4 (Q12 to Q14) */
+ vo_p1 = p_Aq + 1;
+ vo_p2 = vo_p0-1;
+ for (j = 1; j <= M/4; j++)
+ {
+ L_tmp -= *vo_p1++ * *vo_p2--;
+ L_tmp -= *vo_p1++ * *vo_p2--;
+ L_tmp -= *vo_p1++ * *vo_p2--;
+ L_tmp -= *vo_p1++ * *vo_p2--;
+ }
+ *vo_p3++ = *vo_p0++ = vo_round((L_tmp <<4));
+ }
+ /* deemph without division by 2 -> Q14 to Q15 */
+ tmp = 0;
+ Deemph2(h1, TILT_FAC, L_SUBFR, &tmp); /* h1 in Q14 */
- /* h2 in Q12 for codebook search */
- Copy(h1, h2, L_SUBFR);
+ /* h2 in Q12 for codebook search */
+ Copy(h1, h2, L_SUBFR);
- /*---------------------------------------------------------------*
- * scale xn[] and h1[] to avoid overflow in dot_product12() *
- *---------------------------------------------------------------*/
+ /*---------------------------------------------------------------*
+ * scale xn[] and h1[] to avoid overflow in dot_product12() *
+ *---------------------------------------------------------------*/
#ifdef ASM_OPT /* asm optimization branch */
- Scale_sig_opt(h2, L_SUBFR, -2);
- Scale_sig_opt(xn, L_SUBFR, shift); /* scaling of xn[] to limit dynamic at 12 bits */
- Scale_sig_opt(h1, L_SUBFR, 1 + shift); /* set h1[] in Q15 with scaling for convolution */
+ Scale_sig_opt(h2, L_SUBFR, -2);
+ Scale_sig_opt(xn, L_SUBFR, shift); /* scaling of xn[] to limit dynamic at 12 bits */
+ Scale_sig_opt(h1, L_SUBFR, 1 + shift); /* set h1[] in Q15 with scaling for convolution */
#else
- Scale_sig(h2, L_SUBFR, -2);
- Scale_sig(xn, L_SUBFR, shift); /* scaling of xn[] to limit dynamic at 12 bits */
- Scale_sig(h1, L_SUBFR, 1 + shift); /* set h1[] in Q15 with scaling for convolution */
+ Scale_sig(h2, L_SUBFR, -2);
+ Scale_sig(xn, L_SUBFR, shift); /* scaling of xn[] to limit dynamic at 12 bits */
+ Scale_sig(h1, L_SUBFR, 1 + shift); /* set h1[] in Q15 with scaling for convolution */
#endif
- /*----------------------------------------------------------------------*
- * Closed-loop fractional pitch search *
- *----------------------------------------------------------------------*/
- /* find closed loop fractional pitch lag */
- if(*ser_size <= NBBITS_9k)
- {
- T0 = Pitch_fr4(&exc[i_subfr], xn, h1, T0_min, T0_max, &T0_frac,
- pit_flag, PIT_MIN, PIT_FR1_8b, L_SUBFR);
+ /*----------------------------------------------------------------------*
+ * Closed-loop fractional pitch search *
+ *----------------------------------------------------------------------*/
+ /* find closed loop fractional pitch lag */
+ if(*ser_size <= NBBITS_9k)
+ {
+ T0 = Pitch_fr4(&exc[i_subfr], xn, h1, T0_min, T0_max, &T0_frac,
+ pit_flag, PIT_MIN, PIT_FR1_8b, L_SUBFR);
- /* encode pitch lag */
- if (pit_flag == 0) /* if 1st/3rd subframe */
- {
- /*--------------------------------------------------------------*
- * The pitch range for the 1st/3rd subframe is encoded with *
- * 8 bits and is divided as follows: *
- * PIT_MIN to PIT_FR1-1 resolution 1/2 (frac = 0 or 2) *
- * PIT_FR1 to PIT_MAX resolution 1 (frac = 0) *
- *--------------------------------------------------------------*/
- if (T0 < PIT_FR1_8b)
- {
- index = ((T0 << 1) + (T0_frac >> 1) - (PIT_MIN<<1));
- } else
- {
- index = ((T0 - PIT_FR1_8b) + ((PIT_FR1_8b - PIT_MIN)*2));
- }
+ /* encode pitch lag */
+ if (pit_flag == 0) /* if 1st/3rd subframe */
+ {
+ /*--------------------------------------------------------------*
+ * The pitch range for the 1st/3rd subframe is encoded with *
+ * 8 bits and is divided as follows: *
+ * PIT_MIN to PIT_FR1-1 resolution 1/2 (frac = 0 or 2) *
+ * PIT_FR1 to PIT_MAX resolution 1 (frac = 0) *
+ *--------------------------------------------------------------*/
+ if (T0 < PIT_FR1_8b)
+ {
+ index = ((T0 << 1) + (T0_frac >> 1) - (PIT_MIN<<1));
+ } else
+ {
+ index = ((T0 - PIT_FR1_8b) + ((PIT_FR1_8b - PIT_MIN)*2));
+ }
- Parm_serial(index, 8, &prms);
+ Parm_serial(index, 8, &prms);
- /* find T0_min and T0_max for subframe 2 and 4 */
- T0_min = (T0 - 8);
- if (T0_min < PIT_MIN)
- {
- T0_min = PIT_MIN;
- }
- T0_max = T0_min + 15;
- if (T0_max > PIT_MAX)
- {
- T0_max = PIT_MAX;
- T0_min = (T0_max - 15);
- }
- } else
- { /* if subframe 2 or 4 */
- /*--------------------------------------------------------------*
- * The pitch range for subframe 2 or 4 is encoded with 5 bits: *
- * T0_min to T0_max resolution 1/2 (frac = 0 or 2) *
- *--------------------------------------------------------------*/
- i = (T0 - T0_min);
- index = (i << 1) + (T0_frac >> 1);
+ /* find T0_min and T0_max for subframe 2 and 4 */
+ T0_min = (T0 - 8);
+ if (T0_min < PIT_MIN)
+ {
+ T0_min = PIT_MIN;
+ }
+ T0_max = T0_min + 15;
+ if (T0_max > PIT_MAX)
+ {
+ T0_max = PIT_MAX;
+ T0_min = (T0_max - 15);
+ }
+ } else
+ { /* if subframe 2 or 4 */
+ /*--------------------------------------------------------------*
+ * The pitch range for subframe 2 or 4 is encoded with 5 bits: *
+ * T0_min to T0_max resolution 1/2 (frac = 0 or 2) *
+ *--------------------------------------------------------------*/
+ i = (T0 - T0_min);
+ index = (i << 1) + (T0_frac >> 1);
- Parm_serial(index, 5, &prms);
- }
- } else
- {
- T0 = Pitch_fr4(&exc[i_subfr], xn, h1, T0_min, T0_max, &T0_frac,
- pit_flag, PIT_FR2, PIT_FR1_9b, L_SUBFR);
+ Parm_serial(index, 5, &prms);
+ }
+ } else
+ {
+ T0 = Pitch_fr4(&exc[i_subfr], xn, h1, T0_min, T0_max, &T0_frac,
+ pit_flag, PIT_FR2, PIT_FR1_9b, L_SUBFR);
- /* encode pitch lag */
- if (pit_flag == 0) /* if 1st/3rd subframe */
- {
- /*--------------------------------------------------------------*
- * The pitch range for the 1st/3rd subframe is encoded with *
- * 9 bits and is divided as follows: *
- * PIT_MIN to PIT_FR2-1 resolution 1/4 (frac = 0,1,2 or 3) *
- * PIT_FR2 to PIT_FR1-1 resolution 1/2 (frac = 0 or 1) *
- * PIT_FR1 to PIT_MAX resolution 1 (frac = 0) *
- *--------------------------------------------------------------*/
+ /* encode pitch lag */
+ if (pit_flag == 0) /* if 1st/3rd subframe */
+ {
+ /*--------------------------------------------------------------*
+ * The pitch range for the 1st/3rd subframe is encoded with *
+ * 9 bits and is divided as follows: *
+ * PIT_MIN to PIT_FR2-1 resolution 1/4 (frac = 0,1,2 or 3) *
+ * PIT_FR2 to PIT_FR1-1 resolution 1/2 (frac = 0 or 1) *
+ * PIT_FR1 to PIT_MAX resolution 1 (frac = 0) *
+ *--------------------------------------------------------------*/
- if (T0 < PIT_FR2)
- {
- index = ((T0 << 2) + T0_frac) - (PIT_MIN << 2);
- } else if(T0 < PIT_FR1_9b)
- {
- index = ((((T0 << 1) + (T0_frac >> 1)) - (PIT_FR2<<1)) + ((PIT_FR2 - PIT_MIN)<<2));
- } else
- {
- index = (((T0 - PIT_FR1_9b) + ((PIT_FR2 - PIT_MIN)<<2)) + ((PIT_FR1_9b - PIT_FR2)<<1));
- }
+ if (T0 < PIT_FR2)
+ {
+ index = ((T0 << 2) + T0_frac) - (PIT_MIN << 2);
+ } else if(T0 < PIT_FR1_9b)
+ {
+ index = ((((T0 << 1) + (T0_frac >> 1)) - (PIT_FR2<<1)) + ((PIT_FR2 - PIT_MIN)<<2));
+ } else
+ {
+ index = (((T0 - PIT_FR1_9b) + ((PIT_FR2 - PIT_MIN)<<2)) + ((PIT_FR1_9b - PIT_FR2)<<1));
+ }
- Parm_serial(index, 9, &prms);
+ Parm_serial(index, 9, &prms);
- /* find T0_min and T0_max for subframe 2 and 4 */
+ /* find T0_min and T0_max for subframe 2 and 4 */
- T0_min = (T0 - 8);
- if (T0_min < PIT_MIN)
- {
- T0_min = PIT_MIN;
- }
- T0_max = T0_min + 15;
+ T0_min = (T0 - 8);
+ if (T0_min < PIT_MIN)
+ {
+ T0_min = PIT_MIN;
+ }
+ T0_max = T0_min + 15;
- if (T0_max > PIT_MAX)
- {
- T0_max = PIT_MAX;
- T0_min = (T0_max - 15);
- }
- } else
- { /* if subframe 2 or 4 */
- /*--------------------------------------------------------------*
- * The pitch range for subframe 2 or 4 is encoded with 6 bits: *
- * T0_min to T0_max resolution 1/4 (frac = 0,1,2 or 3) *
- *--------------------------------------------------------------*/
- i = (T0 - T0_min);
- index = (i << 2) + T0_frac;
- Parm_serial(index, 6, &prms);
- }
- }
+ if (T0_max > PIT_MAX)
+ {
+ T0_max = PIT_MAX;
+ T0_min = (T0_max - 15);
+ }
+ } else
+ { /* if subframe 2 or 4 */
+ /*--------------------------------------------------------------*
+ * The pitch range for subframe 2 or 4 is encoded with 6 bits: *
+ * T0_min to T0_max resolution 1/4 (frac = 0,1,2 or 3) *
+ *--------------------------------------------------------------*/
+ i = (T0 - T0_min);
+ index = (i << 2) + T0_frac;
+ Parm_serial(index, 6, &prms);
+ }
+ }
- /*-----------------------------------------------------------------*
- * Gain clipping test to avoid unstable synthesis on frame erasure *
- *-----------------------------------------------------------------*/
+ /*-----------------------------------------------------------------*
+ * Gain clipping test to avoid unstable synthesis on frame erasure *
+ *-----------------------------------------------------------------*/
- clip_gain = 0;
- if((st->gp_clip[0] < 154) && (st->gp_clip[1] > 14746))
- clip_gain = 1;
+ clip_gain = 0;
+ if((st->gp_clip[0] < 154) && (st->gp_clip[1] > 14746))
+ clip_gain = 1;
- /*-----------------------------------------------------------------*
- * - find unity gain pitch excitation (adaptive codebook entry) *
- * with fractional interpolation. *
- * - find filtered pitch exc. y1[]=exc[] convolved with h1[]) *
- * - compute pitch gain1 *
- *-----------------------------------------------------------------*/
- /* find pitch exitation */
+ /*-----------------------------------------------------------------*
+ * - find unity gain pitch excitation (adaptive codebook entry) *
+ * with fractional interpolation. *
+ * - find filtered pitch exc. y1[]=exc[] convolved with h1[]) *
+ * - compute pitch gain1 *
+ *-----------------------------------------------------------------*/
+ /* find pitch exitation */
#ifdef ASM_OPT /* asm optimization branch */
- pred_lt4_asm(&exc[i_subfr], T0, T0_frac, L_SUBFR + 1);
+ pred_lt4_asm(&exc[i_subfr], T0, T0_frac, L_SUBFR + 1);
#else
- Pred_lt4(&exc[i_subfr], T0, T0_frac, L_SUBFR + 1);
+ Pred_lt4(&exc[i_subfr], T0, T0_frac, L_SUBFR + 1);
#endif
- if (*ser_size > NBBITS_9k)
- {
+ if (*ser_size > NBBITS_9k)
+ {
#ifdef ASM_OPT /* asm optimization branch */
- Convolve_asm(&exc[i_subfr], h1, y1, L_SUBFR);
+ Convolve_asm(&exc[i_subfr], h1, y1, L_SUBFR);
#else
- Convolve(&exc[i_subfr], h1, y1, L_SUBFR);
+ Convolve(&exc[i_subfr], h1, y1, L_SUBFR);
#endif
- gain1 = G_pitch(xn, y1, g_coeff, L_SUBFR);
- /* clip gain if necessary to avoid problem at decoder */
- if ((clip_gain != 0) && (gain1 > GP_CLIP))
- {
- gain1 = GP_CLIP;
- }
- /* find energy of new target xn2[] */
- Updt_tar(xn, dn, y1, gain1, L_SUBFR); /* dn used temporary */
- } else
- {
- gain1 = 0;
- }
- /*-----------------------------------------------------------------*
- * - find pitch excitation filtered by 1st order LP filter. *
- * - find filtered pitch exc. y2[]=exc[] convolved with h1[]) *
- * - compute pitch gain2 *
- *-----------------------------------------------------------------*/
- /* find pitch excitation with lp filter */
- vo_p0 = exc + i_subfr-1;
- vo_p1 = code;
- /* find pitch excitation with lp filter */
- for (i = 0; i < L_SUBFR/2; i++)
- {
- L_tmp = 5898 * *vo_p0++;
- L_tmp1 = 5898 * *vo_p0;
- L_tmp += 20972 * *vo_p0++;
- L_tmp1 += 20972 * *vo_p0++;
- L_tmp1 += 5898 * *vo_p0--;
- L_tmp += 5898 * *vo_p0;
- *vo_p1++ = (L_tmp + 0x4000)>>15;
- *vo_p1++ = (L_tmp1 + 0x4000)>>15;
- }
+ gain1 = G_pitch(xn, y1, g_coeff, L_SUBFR);
+ /* clip gain if necessary to avoid problem at decoder */
+ if ((clip_gain != 0) && (gain1 > GP_CLIP))
+ {
+ gain1 = GP_CLIP;
+ }
+ /* find energy of new target xn2[] */
+ Updt_tar(xn, dn, y1, gain1, L_SUBFR); /* dn used temporary */
+ } else
+ {
+ gain1 = 0;
+ }
+ /*-----------------------------------------------------------------*
+ * - find pitch excitation filtered by 1st order LP filter. *
+ * - find filtered pitch exc. y2[]=exc[] convolved with h1[]) *
+ * - compute pitch gain2 *
+ *-----------------------------------------------------------------*/
+ /* find pitch excitation with lp filter */
+ vo_p0 = exc + i_subfr-1;
+ vo_p1 = code;
+ /* find pitch excitation with lp filter */
+ for (i = 0; i < L_SUBFR/2; i++)
+ {
+ L_tmp = 5898 * *vo_p0++;
+ L_tmp1 = 5898 * *vo_p0;
+ L_tmp += 20972 * *vo_p0++;
+ L_tmp1 += 20972 * *vo_p0++;
+ L_tmp1 += 5898 * *vo_p0--;
+ L_tmp += 5898 * *vo_p0;
+ *vo_p1++ = (L_tmp + 0x4000)>>15;
+ *vo_p1++ = (L_tmp1 + 0x4000)>>15;
+ }
#ifdef ASM_OPT /* asm optimization branch */
- Convolve_asm(code, h1, y2, L_SUBFR);
+ Convolve_asm(code, h1, y2, L_SUBFR);
#else
- Convolve(code, h1, y2, L_SUBFR);
+ Convolve(code, h1, y2, L_SUBFR);
#endif
- gain2 = G_pitch(xn, y2, g_coeff2, L_SUBFR);
+ gain2 = G_pitch(xn, y2, g_coeff2, L_SUBFR);
- /* clip gain if necessary to avoid problem at decoder */
- if ((clip_gain != 0) && (gain2 > GP_CLIP))
- {
- gain2 = GP_CLIP;
- }
- /* find energy of new target xn2[] */
- Updt_tar(xn, xn2, y2, gain2, L_SUBFR);
- /*-----------------------------------------------------------------*
- * use the best prediction (minimise quadratic error). *
- *-----------------------------------------------------------------*/
- select = 0;
- if(*ser_size > NBBITS_9k)
- {
- L_tmp = 0L;
- vo_p0 = dn;
- vo_p1 = xn2;
- for (i = 0; i < L_SUBFR/2; i++)
- {
- L_tmp += *vo_p0 * *vo_p0;
- vo_p0++;
- L_tmp -= *vo_p1 * *vo_p1;
- vo_p1++;
- L_tmp += *vo_p0 * *vo_p0;
- vo_p0++;
- L_tmp -= *vo_p1 * *vo_p1;
- vo_p1++;
- }
+ /* clip gain if necessary to avoid problem at decoder */
+ if ((clip_gain != 0) && (gain2 > GP_CLIP))
+ {
+ gain2 = GP_CLIP;
+ }
+ /* find energy of new target xn2[] */
+ Updt_tar(xn, xn2, y2, gain2, L_SUBFR);
+ /*-----------------------------------------------------------------*
+ * use the best prediction (minimise quadratic error). *
+ *-----------------------------------------------------------------*/
+ select = 0;
+ if(*ser_size > NBBITS_9k)
+ {
+ L_tmp = 0L;
+ vo_p0 = dn;
+ vo_p1 = xn2;
+ for (i = 0; i < L_SUBFR/2; i++)
+ {
+ L_tmp += *vo_p0 * *vo_p0;
+ vo_p0++;
+ L_tmp -= *vo_p1 * *vo_p1;
+ vo_p1++;
+ L_tmp += *vo_p0 * *vo_p0;
+ vo_p0++;
+ L_tmp -= *vo_p1 * *vo_p1;
+ vo_p1++;
+ }
- if (L_tmp <= 0)
- {
- select = 1;
- }
- Parm_serial(select, 1, &prms);
- }
- if (select == 0)
- {
- /* use the lp filter for pitch excitation prediction */
- gain_pit = gain2;
- Copy(code, &exc[i_subfr], L_SUBFR);
- Copy(y2, y1, L_SUBFR);
- Copy(g_coeff2, g_coeff, 4);
- } else
- {
- /* no filter used for pitch excitation prediction */
- gain_pit = gain1;
- Copy(dn, xn2, L_SUBFR); /* target vector for codebook search */
- }
- /*-----------------------------------------------------------------*
- * - update cn[] for codebook search *
- *-----------------------------------------------------------------*/
- Updt_tar(cn, cn, &exc[i_subfr], gain_pit, L_SUBFR);
+ if (L_tmp <= 0)
+ {
+ select = 1;
+ }
+ Parm_serial(select, 1, &prms);
+ }
+ if (select == 0)
+ {
+ /* use the lp filter for pitch excitation prediction */
+ gain_pit = gain2;
+ Copy(code, &exc[i_subfr], L_SUBFR);
+ Copy(y2, y1, L_SUBFR);
+ Copy(g_coeff2, g_coeff, 4);
+ } else
+ {
+ /* no filter used for pitch excitation prediction */
+ gain_pit = gain1;
+ Copy(dn, xn2, L_SUBFR); /* target vector for codebook search */
+ }
+ /*-----------------------------------------------------------------*
+ * - update cn[] for codebook search *
+ *-----------------------------------------------------------------*/
+ Updt_tar(cn, cn, &exc[i_subfr], gain_pit, L_SUBFR);
#ifdef ASM_OPT /* asm optimization branch */
- Scale_sig_opt(cn, L_SUBFR, shift); /* scaling of cn[] to limit dynamic at 12 bits */
+ Scale_sig_opt(cn, L_SUBFR, shift); /* scaling of cn[] to limit dynamic at 12 bits */
#else
- Scale_sig(cn, L_SUBFR, shift); /* scaling of cn[] to limit dynamic at 12 bits */
+ Scale_sig(cn, L_SUBFR, shift); /* scaling of cn[] to limit dynamic at 12 bits */
#endif
- /*-----------------------------------------------------------------*
- * - include fixed-gain pitch contribution into impulse resp. h1[] *
- *-----------------------------------------------------------------*/
- tmp = 0;
- Preemph(h2, st->tilt_code, L_SUBFR, &tmp);
+ /*-----------------------------------------------------------------*
+ * - include fixed-gain pitch contribution into impulse resp. h1[] *
+ *-----------------------------------------------------------------*/
+ tmp = 0;
+ Preemph(h2, st->tilt_code, L_SUBFR, &tmp);
- if (T0_frac > 2)
- T0 = (T0 + 1);
- Pit_shrp(h2, T0, PIT_SHARP, L_SUBFR);
- /*-----------------------------------------------------------------*
- * - Correlation between target xn2[] and impulse response h1[] *
- * - Innovative codebook search *
- *-----------------------------------------------------------------*/
- cor_h_x(h2, xn2, dn);
- if (*ser_size <= NBBITS_7k)
- {
- ACELP_2t64_fx(dn, cn, h2, code, y2, indice);
+ if (T0_frac > 2)
+ T0 = (T0 + 1);
+ Pit_shrp(h2, T0, PIT_SHARP, L_SUBFR);
+ /*-----------------------------------------------------------------*
+ * - Correlation between target xn2[] and impulse response h1[] *
+ * - Innovative codebook search *
+ *-----------------------------------------------------------------*/
+ cor_h_x(h2, xn2, dn);
+ if (*ser_size <= NBBITS_7k)
+ {
+ ACELP_2t64_fx(dn, cn, h2, code, y2, indice);
- Parm_serial(indice[0], 12, &prms);
- } else if(*ser_size <= NBBITS_9k)
- {
- ACELP_4t64_fx(dn, cn, h2, code, y2, 20, *ser_size, indice);
+ Parm_serial(indice[0], 12, &prms);
+ } else if(*ser_size <= NBBITS_9k)
+ {
+ ACELP_4t64_fx(dn, cn, h2, code, y2, 20, *ser_size, indice);
- Parm_serial(indice[0], 5, &prms);
- Parm_serial(indice[1], 5, &prms);
- Parm_serial(indice[2], 5, &prms);
- Parm_serial(indice[3], 5, &prms);
- } else if(*ser_size <= NBBITS_12k)
- {
- ACELP_4t64_fx(dn, cn, h2, code, y2, 36, *ser_size, indice);
+ Parm_serial(indice[0], 5, &prms);
+ Parm_serial(indice[1], 5, &prms);
+ Parm_serial(indice[2], 5, &prms);
+ Parm_serial(indice[3], 5, &prms);
+ } else if(*ser_size <= NBBITS_12k)
+ {
+ ACELP_4t64_fx(dn, cn, h2, code, y2, 36, *ser_size, indice);
- Parm_serial(indice[0], 9, &prms);
- Parm_serial(indice[1], 9, &prms);
- Parm_serial(indice[2], 9, &prms);
- Parm_serial(indice[3], 9, &prms);
- } else if(*ser_size <= NBBITS_14k)
- {
- ACELP_4t64_fx(dn, cn, h2, code, y2, 44, *ser_size, indice);
+ Parm_serial(indice[0], 9, &prms);
+ Parm_serial(indice[1], 9, &prms);
+ Parm_serial(indice[2], 9, &prms);
+ Parm_serial(indice[3], 9, &prms);
+ } else if(*ser_size <= NBBITS_14k)
+ {
+ ACELP_4t64_fx(dn, cn, h2, code, y2, 44, *ser_size, indice);
- Parm_serial(indice[0], 13, &prms);
- Parm_serial(indice[1], 13, &prms);
- Parm_serial(indice[2], 9, &prms);
- Parm_serial(indice[3], 9, &prms);
- } else if(*ser_size <= NBBITS_16k)
- {
- ACELP_4t64_fx(dn, cn, h2, code, y2, 52, *ser_size, indice);
+ Parm_serial(indice[0], 13, &prms);
+ Parm_serial(indice[1], 13, &prms);
+ Parm_serial(indice[2], 9, &prms);
+ Parm_serial(indice[3], 9, &prms);
+ } else if(*ser_size <= NBBITS_16k)
+ {
+ ACELP_4t64_fx(dn, cn, h2, code, y2, 52, *ser_size, indice);
- Parm_serial(indice[0], 13, &prms);
- Parm_serial(indice[1], 13, &prms);
- Parm_serial(indice[2], 13, &prms);
- Parm_serial(indice[3], 13, &prms);
- } else if(*ser_size <= NBBITS_18k)
- {
- ACELP_4t64_fx(dn, cn, h2, code, y2, 64, *ser_size, indice);
+ Parm_serial(indice[0], 13, &prms);
+ Parm_serial(indice[1], 13, &prms);
+ Parm_serial(indice[2], 13, &prms);
+ Parm_serial(indice[3], 13, &prms);
+ } else if(*ser_size <= NBBITS_18k)
+ {
+ ACELP_4t64_fx(dn, cn, h2, code, y2, 64, *ser_size, indice);
- Parm_serial(indice[0], 2, &prms);
- Parm_serial(indice[1], 2, &prms);
- Parm_serial(indice[2], 2, &prms);
- Parm_serial(indice[3], 2, &prms);
- Parm_serial(indice[4], 14, &prms);
- Parm_serial(indice[5], 14, &prms);
- Parm_serial(indice[6], 14, &prms);
- Parm_serial(indice[7], 14, &prms);
- } else if(*ser_size <= NBBITS_20k)
- {
- ACELP_4t64_fx(dn, cn, h2, code, y2, 72, *ser_size, indice);
+ Parm_serial(indice[0], 2, &prms);
+ Parm_serial(indice[1], 2, &prms);
+ Parm_serial(indice[2], 2, &prms);
+ Parm_serial(indice[3], 2, &prms);
+ Parm_serial(indice[4], 14, &prms);
+ Parm_serial(indice[5], 14, &prms);
+ Parm_serial(indice[6], 14, &prms);
+ Parm_serial(indice[7], 14, &prms);
+ } else if(*ser_size <= NBBITS_20k)
+ {
+ ACELP_4t64_fx(dn, cn, h2, code, y2, 72, *ser_size, indice);
- Parm_serial(indice[0], 10, &prms);
- Parm_serial(indice[1], 10, &prms);
- Parm_serial(indice[2], 2, &prms);
- Parm_serial(indice[3], 2, &prms);
- Parm_serial(indice[4], 10, &prms);
- Parm_serial(indice[5], 10, &prms);
- Parm_serial(indice[6], 14, &prms);
- Parm_serial(indice[7], 14, &prms);
- } else
- {
- ACELP_4t64_fx(dn, cn, h2, code, y2, 88, *ser_size, indice);
+ Parm_serial(indice[0], 10, &prms);
+ Parm_serial(indice[1], 10, &prms);
+ Parm_serial(indice[2], 2, &prms);
+ Parm_serial(indice[3], 2, &prms);
+ Parm_serial(indice[4], 10, &prms);
+ Parm_serial(indice[5], 10, &prms);
+ Parm_serial(indice[6], 14, &prms);
+ Parm_serial(indice[7], 14, &prms);
+ } else
+ {
+ ACELP_4t64_fx(dn, cn, h2, code, y2, 88, *ser_size, indice);
- Parm_serial(indice[0], 11, &prms);
- Parm_serial(indice[1], 11, &prms);
- Parm_serial(indice[2], 11, &prms);
- Parm_serial(indice[3], 11, &prms);
- Parm_serial(indice[4], 11, &prms);
- Parm_serial(indice[5], 11, &prms);
- Parm_serial(indice[6], 11, &prms);
- Parm_serial(indice[7], 11, &prms);
- }
- /*-------------------------------------------------------*
- * - Add the fixed-gain pitch contribution to code[]. *
- *-------------------------------------------------------*/
- tmp = 0;
- Preemph(code, st->tilt_code, L_SUBFR, &tmp);
- Pit_shrp(code, T0, PIT_SHARP, L_SUBFR);
- /*----------------------------------------------------------*
- * - Compute the fixed codebook gain *
- * - quantize fixed codebook gain *
- *----------------------------------------------------------*/
- if(*ser_size <= NBBITS_9k)
- {
- index = Q_gain2(xn, y1, Q_new + shift, y2, code, g_coeff, L_SUBFR, 6,
- &gain_pit, &L_gain_code, clip_gain, st->qua_gain);
- Parm_serial(index, 6, &prms);
- } else
- {
- index = Q_gain2(xn, y1, Q_new + shift, y2, code, g_coeff, L_SUBFR, 7,
- &gain_pit, &L_gain_code, clip_gain, st->qua_gain);
- Parm_serial(index, 7, &prms);
- }
- /* test quantized gain of pitch for pitch clipping algorithm */
- Gp_clip_test_gain_pit(gain_pit, st->gp_clip);
+ Parm_serial(indice[0], 11, &prms);
+ Parm_serial(indice[1], 11, &prms);
+ Parm_serial(indice[2], 11, &prms);
+ Parm_serial(indice[3], 11, &prms);
+ Parm_serial(indice[4], 11, &prms);
+ Parm_serial(indice[5], 11, &prms);
+ Parm_serial(indice[6], 11, &prms);
+ Parm_serial(indice[7], 11, &prms);
+ }
+ /*-------------------------------------------------------*
+ * - Add the fixed-gain pitch contribution to code[]. *
+ *-------------------------------------------------------*/
+ tmp = 0;
+ Preemph(code, st->tilt_code, L_SUBFR, &tmp);
+ Pit_shrp(code, T0, PIT_SHARP, L_SUBFR);
+ /*----------------------------------------------------------*
+ * - Compute the fixed codebook gain *
+ * - quantize fixed codebook gain *
+ *----------------------------------------------------------*/
+ if(*ser_size <= NBBITS_9k)
+ {
+ index = Q_gain2(xn, y1, Q_new + shift, y2, code, g_coeff, L_SUBFR, 6,
+ &gain_pit, &L_gain_code, clip_gain, st->qua_gain);
+ Parm_serial(index, 6, &prms);
+ } else
+ {
+ index = Q_gain2(xn, y1, Q_new + shift, y2, code, g_coeff, L_SUBFR, 7,
+ &gain_pit, &L_gain_code, clip_gain, st->qua_gain);
+ Parm_serial(index, 7, &prms);
+ }
+ /* test quantized gain of pitch for pitch clipping algorithm */
+ Gp_clip_test_gain_pit(gain_pit, st->gp_clip);
- L_tmp = L_shl(L_gain_code, Q_new);
- gain_code = extract_h(L_add(L_tmp, 0x8000));
+ L_tmp = L_shl(L_gain_code, Q_new);
+ gain_code = extract_h(L_add(L_tmp, 0x8000));
- /*----------------------------------------------------------*
- * Update parameters for the next subframe. *
- * - tilt of code: 0.0 (unvoiced) to 0.5 (voiced) *
- *----------------------------------------------------------*/
- /* find voice factor in Q15 (1=voiced, -1=unvoiced) */
- Copy(&exc[i_subfr], exc2, L_SUBFR);
+ /*----------------------------------------------------------*
+ * Update parameters for the next subframe. *
+ * - tilt of code: 0.0 (unvoiced) to 0.5 (voiced) *
+ *----------------------------------------------------------*/
+ /* find voice factor in Q15 (1=voiced, -1=unvoiced) */
+ Copy(&exc[i_subfr], exc2, L_SUBFR);
#ifdef ASM_OPT /* asm optimization branch */
- Scale_sig_opt(exc2, L_SUBFR, shift);
+ Scale_sig_opt(exc2, L_SUBFR, shift);
#else
- Scale_sig(exc2, L_SUBFR, shift);
+ Scale_sig(exc2, L_SUBFR, shift);
#endif
- voice_fac = voice_factor(exc2, shift, gain_pit, code, gain_code, L_SUBFR);
- /* tilt of code for next subframe: 0.5=voiced, 0=unvoiced */
- st->tilt_code = ((voice_fac >> 2) + 8192);
- /*------------------------------------------------------*
- * - Update filter's memory "mem_w0" for finding the *
- * target vector in the next subframe. *
- * - Find the total excitation *
- * - Find synthesis speech to update mem_syn[]. *
- *------------------------------------------------------*/
+ voice_fac = voice_factor(exc2, shift, gain_pit, code, gain_code, L_SUBFR);
+ /* tilt of code for next subframe: 0.5=voiced, 0=unvoiced */
+ st->tilt_code = ((voice_fac >> 2) + 8192);
+ /*------------------------------------------------------*
+ * - Update filter's memory "mem_w0" for finding the *
+ * target vector in the next subframe. *
+ * - Find the total excitation *
+ * - Find synthesis speech to update mem_syn[]. *
+ *------------------------------------------------------*/
- /* y2 in Q9, gain_pit in Q14 */
- L_tmp = (gain_code * y2[L_SUBFR - 1])<<1;
- L_tmp = L_shl(L_tmp, (5 + shift));
- L_tmp = L_negate(L_tmp);
- L_tmp += (xn[L_SUBFR - 1] * 16384)<<1;
- L_tmp -= (y1[L_SUBFR - 1] * gain_pit)<<1;
- L_tmp = L_shl(L_tmp, (1 - shift));
- st->mem_w0 = extract_h(L_add(L_tmp, 0x8000));
+ /* y2 in Q9, gain_pit in Q14 */
+ L_tmp = (gain_code * y2[L_SUBFR - 1])<<1;
+ L_tmp = L_shl(L_tmp, (5 + shift));
+ L_tmp = L_negate(L_tmp);
+ L_tmp += (xn[L_SUBFR - 1] * 16384)<<1;
+ L_tmp -= (y1[L_SUBFR - 1] * gain_pit)<<1;
+ L_tmp = L_shl(L_tmp, (1 - shift));
+ st->mem_w0 = extract_h(L_add(L_tmp, 0x8000));
- if (*ser_size >= NBBITS_24k)
- Copy(&exc[i_subfr], exc2, L_SUBFR);
+ if (*ser_size >= NBBITS_24k)
+ Copy(&exc[i_subfr], exc2, L_SUBFR);
- for (i = 0; i < L_SUBFR; i++)
- {
- /* code in Q9, gain_pit in Q14 */
- L_tmp = (gain_code * code[i])<<1;
- L_tmp = (L_tmp << 5);
- L_tmp += (exc[i + i_subfr] * gain_pit)<<1;
- L_tmp = L_shl2(L_tmp, 1);
- exc[i + i_subfr] = extract_h(L_add(L_tmp, 0x8000));
- }
+ for (i = 0; i < L_SUBFR; i++)
+ {
+ Word32 tmp;
+ /* code in Q9, gain_pit in Q14 */
+ L_tmp = (gain_code * code[i])<<1;
+ L_tmp = (L_tmp << 5);
+ tmp = L_mult(exc[i + i_subfr], gain_pit); // (exc[i + i_subfr] * gain_pit)<<1
+ L_tmp = L_add(L_tmp, tmp);
+ L_tmp = L_shl2(L_tmp, 1);
+ exc[i + i_subfr] = extract_h(L_add(L_tmp, 0x8000));
+ }
- Syn_filt(p_Aq,&exc[i_subfr], synth, L_SUBFR, st->mem_syn, 1);
+ Syn_filt(p_Aq,&exc[i_subfr], synth, L_SUBFR, st->mem_syn, 1);
- if(*ser_size >= NBBITS_24k)
- {
- /*------------------------------------------------------------*
- * phase dispersion to enhance noise in low bit rate *
- *------------------------------------------------------------*/
- /* L_gain_code in Q16 */
- VO_L_Extract(L_gain_code, &gain_code, &gain_code_lo);
+ if(*ser_size >= NBBITS_24k)
+ {
+ /*------------------------------------------------------------*
+ * phase dispersion to enhance noise in low bit rate *
+ *------------------------------------------------------------*/
+ /* L_gain_code in Q16 */
+ VO_L_Extract(L_gain_code, &gain_code, &gain_code_lo);
- /*------------------------------------------------------------*
- * noise enhancer *
- * ~~~~~~~~~~~~~~ *
- * - Enhance excitation on noise. (modify gain of code) *
- * If signal is noisy and LPC filter is stable, move gain *
- * of code 1.5 dB toward gain of code threshold. *
- * This decrease by 3 dB noise energy variation. *
- *------------------------------------------------------------*/
- tmp = (16384 - (voice_fac >> 1)); /* 1=unvoiced, 0=voiced */
- fac = vo_mult(stab_fac, tmp);
- L_tmp = L_gain_code;
- if(L_tmp < st->L_gc_thres)
- {
- L_tmp = vo_L_add(L_tmp, Mpy_32_16(gain_code, gain_code_lo, 6226));
- if(L_tmp > st->L_gc_thres)
- {
- L_tmp = st->L_gc_thres;
- }
- } else
- {
- L_tmp = Mpy_32_16(gain_code, gain_code_lo, 27536);
- if(L_tmp < st->L_gc_thres)
- {
- L_tmp = st->L_gc_thres;
- }
- }
- st->L_gc_thres = L_tmp;
+ /*------------------------------------------------------------*
+ * noise enhancer *
+ * ~~~~~~~~~~~~~~ *
+ * - Enhance excitation on noise. (modify gain of code) *
+ * If signal is noisy and LPC filter is stable, move gain *
+ * of code 1.5 dB toward gain of code threshold. *
+ * This decrease by 3 dB noise energy variation. *
+ *------------------------------------------------------------*/
+ tmp = (16384 - (voice_fac >> 1)); /* 1=unvoiced, 0=voiced */
+ fac = vo_mult(stab_fac, tmp);
+ L_tmp = L_gain_code;
+ if(L_tmp < st->L_gc_thres)
+ {
+ L_tmp = vo_L_add(L_tmp, Mpy_32_16(gain_code, gain_code_lo, 6226));
+ if(L_tmp > st->L_gc_thres)
+ {
+ L_tmp = st->L_gc_thres;
+ }
+ } else
+ {
+ L_tmp = Mpy_32_16(gain_code, gain_code_lo, 27536);
+ if(L_tmp < st->L_gc_thres)
+ {
+ L_tmp = st->L_gc_thres;
+ }
+ }
+ st->L_gc_thres = L_tmp;
- L_gain_code = Mpy_32_16(gain_code, gain_code_lo, (32767 - fac));
- VO_L_Extract(L_tmp, &gain_code, &gain_code_lo);
- L_gain_code = vo_L_add(L_gain_code, Mpy_32_16(gain_code, gain_code_lo, fac));
+ L_gain_code = Mpy_32_16(gain_code, gain_code_lo, (32767 - fac));
+ VO_L_Extract(L_tmp, &gain_code, &gain_code_lo);
+ L_gain_code = vo_L_add(L_gain_code, Mpy_32_16(gain_code, gain_code_lo, fac));
- /*------------------------------------------------------------*
- * pitch enhancer *
- * ~~~~~~~~~~~~~~ *
- * - Enhance excitation on voice. (HP filtering of code) *
- * On voiced signal, filtering of code by a smooth fir HP *
- * filter to decrease energy of code in low frequency. *
- *------------------------------------------------------------*/
+ /*------------------------------------------------------------*
+ * pitch enhancer *
+ * ~~~~~~~~~~~~~~ *
+ * - Enhance excitation on voice. (HP filtering of code) *
+ * On voiced signal, filtering of code by a smooth fir HP *
+ * filter to decrease energy of code in low frequency. *
+ *------------------------------------------------------------*/
- tmp = ((voice_fac >> 3) + 4096); /* 0.25=voiced, 0=unvoiced */
+ tmp = ((voice_fac >> 3) + 4096); /* 0.25=voiced, 0=unvoiced */
- L_tmp = L_deposit_h(code[0]);
- L_tmp -= (code[1] * tmp)<<1;
- code2[0] = vo_round(L_tmp);
+ L_tmp = L_deposit_h(code[0]);
+ L_tmp -= (code[1] * tmp)<<1;
+ code2[0] = vo_round(L_tmp);
- for (i = 1; i < L_SUBFR - 1; i++)
- {
- L_tmp = L_deposit_h(code[i]);
- L_tmp -= (code[i + 1] * tmp)<<1;
- L_tmp -= (code[i - 1] * tmp)<<1;
- code2[i] = vo_round(L_tmp);
- }
+ for (i = 1; i < L_SUBFR - 1; i++)
+ {
+ L_tmp = L_deposit_h(code[i]);
+ L_tmp -= (code[i + 1] * tmp)<<1;
+ L_tmp -= (code[i - 1] * tmp)<<1;
+ code2[i] = vo_round(L_tmp);
+ }
- L_tmp = L_deposit_h(code[L_SUBFR - 1]);
- L_tmp -= (code[L_SUBFR - 2] * tmp)<<1;
- code2[L_SUBFR - 1] = vo_round(L_tmp);
+ L_tmp = L_deposit_h(code[L_SUBFR - 1]);
+ L_tmp -= (code[L_SUBFR - 2] * tmp)<<1;
+ code2[L_SUBFR - 1] = vo_round(L_tmp);
- /* build excitation */
- gain_code = vo_round(L_shl(L_gain_code, Q_new));
+ /* build excitation */
+ gain_code = vo_round(L_shl(L_gain_code, Q_new));
- for (i = 0; i < L_SUBFR; i++)
- {
- L_tmp = (code2[i] * gain_code)<<1;
- L_tmp = (L_tmp << 5);
- L_tmp += (exc2[i] * gain_pit)<<1;
- L_tmp = (L_tmp << 1);
- exc2[i] = vo_round(L_tmp);
- }
+ for (i = 0; i < L_SUBFR; i++)
+ {
+ L_tmp = (code2[i] * gain_code)<<1;
+ L_tmp = (L_tmp << 5);
+ L_tmp += (exc2[i] * gain_pit)<<1;
+ L_tmp = (L_tmp << 1);
+ exc2[i] = voround(L_tmp);
+ }
- corr_gain = synthesis(p_Aq, exc2, Q_new, &speech16k[i_subfr * 5 / 4], st);
- Parm_serial(corr_gain, 4, &prms);
- }
- p_A += (M + 1);
- p_Aq += (M + 1);
- } /* end of subframe loop */
+ corr_gain = synthesis(p_Aq, exc2, Q_new, &speech16k[i_subfr * 5 / 4], st);
+ Parm_serial(corr_gain, 4, &prms);
+ }
+ p_A += (M + 1);
+ p_Aq += (M + 1);
+ } /* end of subframe loop */
- /*--------------------------------------------------*
- * Update signal for next frame. *
- * -> save past of speech[], wsp[] and exc[]. *
- *--------------------------------------------------*/
- Copy(&old_speech[L_FRAME], st->old_speech, L_TOTAL - L_FRAME);
- Copy(&old_wsp[L_FRAME / OPL_DECIM], st->old_wsp, PIT_MAX / OPL_DECIM);
- Copy(&old_exc[L_FRAME], st->old_exc, PIT_MAX + L_INTERPOL);
- return;
+ /*--------------------------------------------------*
+ * Update signal for next frame. *
+ * -> save past of speech[], wsp[] and exc[]. *
+ *--------------------------------------------------*/
+ Copy(&old_speech[L_FRAME], st->old_speech, L_TOTAL - L_FRAME);
+ Copy(&old_wsp[L_FRAME / OPL_DECIM], st->old_wsp, PIT_MAX / OPL_DECIM);
+ Copy(&old_exc[L_FRAME], st->old_exc, PIT_MAX + L_INTERPOL);
+ return;
}
/*-----------------------------------------------------*
@@ -1329,225 +1333,225 @@
*-----------------------------------------------------*/
static Word16 synthesis(
- Word16 Aq[], /* A(z) : quantized Az */
- Word16 exc[], /* (i) : excitation at 12kHz */
- Word16 Q_new, /* (i) : scaling performed on exc */
- Word16 synth16k[], /* (o) : 16kHz synthesis signal */
- Coder_State * st /* (i/o) : State structure */
- )
+ Word16 Aq[], /* A(z) : quantized Az */
+ Word16 exc[], /* (i) : excitation at 12kHz */
+ Word16 Q_new, /* (i) : scaling performed on exc */
+ Word16 synth16k[], /* (o) : 16kHz synthesis signal */
+ Coder_State * st /* (i/o) : State structure */
+ )
{
- Word16 fac, tmp, exp;
- Word16 ener, exp_ener;
- Word32 L_tmp, i;
+ Word16 fac, tmp, exp;
+ Word16 ener, exp_ener;
+ Word32 L_tmp, i;
- Word16 synth_hi[M + L_SUBFR], synth_lo[M + L_SUBFR];
- Word16 synth[L_SUBFR];
- Word16 HF[L_SUBFR16k]; /* High Frequency vector */
- Word16 Ap[M + 1];
+ Word16 synth_hi[M + L_SUBFR], synth_lo[M + L_SUBFR];
+ Word16 synth[L_SUBFR];
+ Word16 HF[L_SUBFR16k]; /* High Frequency vector */
+ Word16 Ap[M + 1];
- Word16 HF_SP[L_SUBFR16k]; /* High Frequency vector (from original signal) */
+ Word16 HF_SP[L_SUBFR16k]; /* High Frequency vector (from original signal) */
- Word16 HP_est_gain, HP_calc_gain, HP_corr_gain;
- Word16 dist_min, dist;
- Word16 HP_gain_ind = 0;
- Word16 gain1, gain2;
- Word16 weight1, weight2;
+ Word16 HP_est_gain, HP_calc_gain, HP_corr_gain;
+ Word16 dist_min, dist;
+ Word16 HP_gain_ind = 0;
+ Word16 gain1, gain2;
+ Word16 weight1, weight2;
- /*------------------------------------------------------------*
- * speech synthesis *
- * ~~~~~~~~~~~~~~~~ *
- * - Find synthesis speech corresponding to exc2[]. *
- * - Perform fixed deemphasis and hp 50hz filtering. *
- * - Oversampling from 12.8kHz to 16kHz. *
- *------------------------------------------------------------*/
- Copy(st->mem_syn_hi, synth_hi, M);
- Copy(st->mem_syn_lo, synth_lo, M);
+ /*------------------------------------------------------------*
+ * speech synthesis *
+ * ~~~~~~~~~~~~~~~~ *
+ * - Find synthesis speech corresponding to exc2[]. *
+ * - Perform fixed deemphasis and hp 50hz filtering. *
+ * - Oversampling from 12.8kHz to 16kHz. *
+ *------------------------------------------------------------*/
+ Copy(st->mem_syn_hi, synth_hi, M);
+ Copy(st->mem_syn_lo, synth_lo, M);
#ifdef ASM_OPT /* asm optimization branch */
- Syn_filt_32_asm(Aq, M, exc, Q_new, synth_hi + M, synth_lo + M, L_SUBFR);
+ Syn_filt_32_asm(Aq, M, exc, Q_new, synth_hi + M, synth_lo + M, L_SUBFR);
#else
- Syn_filt_32(Aq, M, exc, Q_new, synth_hi + M, synth_lo + M, L_SUBFR);
+ Syn_filt_32(Aq, M, exc, Q_new, synth_hi + M, synth_lo + M, L_SUBFR);
#endif
- Copy(synth_hi + L_SUBFR, st->mem_syn_hi, M);
- Copy(synth_lo + L_SUBFR, st->mem_syn_lo, M);
+ Copy(synth_hi + L_SUBFR, st->mem_syn_hi, M);
+ Copy(synth_lo + L_SUBFR, st->mem_syn_lo, M);
#ifdef ASM_OPT /* asm optimization branch */
- Deemph_32_asm(synth_hi + M, synth_lo + M, synth, &(st->mem_deemph));
+ Deemph_32_asm(synth_hi + M, synth_lo + M, synth, &(st->mem_deemph));
#else
- Deemph_32(synth_hi + M, synth_lo + M, synth, PREEMPH_FAC, L_SUBFR, &(st->mem_deemph));
+ Deemph_32(synth_hi + M, synth_lo + M, synth, PREEMPH_FAC, L_SUBFR, &(st->mem_deemph));
#endif
- HP50_12k8(synth, L_SUBFR, st->mem_sig_out);
+ HP50_12k8(synth, L_SUBFR, st->mem_sig_out);
- /* Original speech signal as reference for high band gain quantisation */
- for (i = 0; i < L_SUBFR16k; i++)
- {
- HF_SP[i] = synth16k[i];
- }
+ /* Original speech signal as reference for high band gain quantisation */
+ for (i = 0; i < L_SUBFR16k; i++)
+ {
+ HF_SP[i] = synth16k[i];
+ }
- /*------------------------------------------------------*
- * HF noise synthesis *
- * ~~~~~~~~~~~~~~~~~~ *
- * - Generate HF noise between 5.5 and 7.5 kHz. *
- * - Set energy of noise according to synthesis tilt. *
- * tilt > 0.8 ==> - 14 dB (voiced) *
- * tilt 0.5 ==> - 6 dB (voiced or noise) *
- * tilt < 0.0 ==> 0 dB (noise) *
- *------------------------------------------------------*/
- /* generate white noise vector */
- for (i = 0; i < L_SUBFR16k; i++)
- {
- HF[i] = Random(&(st->seed2))>>3;
- }
- /* energy of excitation */
+ /*------------------------------------------------------*
+ * HF noise synthesis *
+ * ~~~~~~~~~~~~~~~~~~ *
+ * - Generate HF noise between 5.5 and 7.5 kHz. *
+ * - Set energy of noise according to synthesis tilt. *
+ * tilt > 0.8 ==> - 14 dB (voiced) *
+ * tilt 0.5 ==> - 6 dB (voiced or noise) *
+ * tilt < 0.0 ==> 0 dB (noise) *
+ *------------------------------------------------------*/
+ /* generate white noise vector */
+ for (i = 0; i < L_SUBFR16k; i++)
+ {
+ HF[i] = Random(&(st->seed2))>>3;
+ }
+ /* energy of excitation */
#ifdef ASM_OPT /* asm optimization branch */
- Scale_sig_opt(exc, L_SUBFR, -3);
- Q_new = Q_new - 3;
- ener = extract_h(Dot_product12_asm(exc, exc, L_SUBFR, &exp_ener));
+ Scale_sig_opt(exc, L_SUBFR, -3);
+ Q_new = Q_new - 3;
+ ener = extract_h(Dot_product12_asm(exc, exc, L_SUBFR, &exp_ener));
#else
- Scale_sig(exc, L_SUBFR, -3);
- Q_new = Q_new - 3;
- ener = extract_h(Dot_product12(exc, exc, L_SUBFR, &exp_ener));
+ Scale_sig(exc, L_SUBFR, -3);
+ Q_new = Q_new - 3;
+ ener = extract_h(Dot_product12(exc, exc, L_SUBFR, &exp_ener));
#endif
- exp_ener = exp_ener - (Q_new + Q_new);
- /* set energy of white noise to energy of excitation */
+ exp_ener = exp_ener - (Q_new + Q_new);
+ /* set energy of white noise to energy of excitation */
#ifdef ASM_OPT /* asm optimization branch */
- tmp = extract_h(Dot_product12_asm(HF, HF, L_SUBFR16k, &exp));
+ tmp = extract_h(Dot_product12_asm(HF, HF, L_SUBFR16k, &exp));
#else
- tmp = extract_h(Dot_product12(HF, HF, L_SUBFR16k, &exp));
+ tmp = extract_h(Dot_product12(HF, HF, L_SUBFR16k, &exp));
#endif
- if(tmp > ener)
- {
- tmp = (tmp >> 1); /* Be sure tmp < ener */
- exp = (exp + 1);
- }
- L_tmp = L_deposit_h(div_s(tmp, ener)); /* result is normalized */
- exp = (exp - exp_ener);
- Isqrt_n(&L_tmp, &exp);
- L_tmp = L_shl(L_tmp, (exp + 1)); /* L_tmp x 2, L_tmp in Q31 */
- tmp = extract_h(L_tmp); /* tmp = 2 x sqrt(ener_exc/ener_hf) */
+ if(tmp > ener)
+ {
+ tmp = (tmp >> 1); /* Be sure tmp < ener */
+ exp = (exp + 1);
+ }
+ L_tmp = L_deposit_h(div_s(tmp, ener)); /* result is normalized */
+ exp = (exp - exp_ener);
+ Isqrt_n(&L_tmp, &exp);
+ L_tmp = L_shl(L_tmp, (exp + 1)); /* L_tmp x 2, L_tmp in Q31 */
+ tmp = extract_h(L_tmp); /* tmp = 2 x sqrt(ener_exc/ener_hf) */
- for (i = 0; i < L_SUBFR16k; i++)
- {
- HF[i] = vo_mult(HF[i], tmp);
- }
+ for (i = 0; i < L_SUBFR16k; i++)
+ {
+ HF[i] = vo_mult(HF[i], tmp);
+ }
- /* find tilt of synthesis speech (tilt: 1=voiced, -1=unvoiced) */
- HP400_12k8(synth, L_SUBFR, st->mem_hp400);
+ /* find tilt of synthesis speech (tilt: 1=voiced, -1=unvoiced) */
+ HP400_12k8(synth, L_SUBFR, st->mem_hp400);
- L_tmp = 1L;
- for (i = 0; i < L_SUBFR; i++)
- L_tmp += (synth[i] * synth[i])<<1;
+ L_tmp = 1L;
+ for (i = 0; i < L_SUBFR; i++)
+ L_tmp += (synth[i] * synth[i])<<1;
- exp = norm_l(L_tmp);
- ener = extract_h(L_tmp << exp); /* ener = r[0] */
+ exp = norm_l(L_tmp);
+ ener = extract_h(L_tmp << exp); /* ener = r[0] */
- L_tmp = 1L;
- for (i = 1; i < L_SUBFR; i++)
- L_tmp +=(synth[i] * synth[i - 1])<<1;
+ L_tmp = 1L;
+ for (i = 1; i < L_SUBFR; i++)
+ L_tmp +=(synth[i] * synth[i - 1])<<1;
- tmp = extract_h(L_tmp << exp); /* tmp = r[1] */
+ tmp = extract_h(L_tmp << exp); /* tmp = r[1] */
- if (tmp > 0)
- {
- fac = div_s(tmp, ener);
- } else
- {
- fac = 0;
- }
+ if (tmp > 0)
+ {
+ fac = div_s(tmp, ener);
+ } else
+ {
+ fac = 0;
+ }
- /* modify energy of white noise according to synthesis tilt */
- gain1 = 32767 - fac;
- gain2 = vo_mult(gain1, 20480);
- gain2 = shl(gain2, 1);
+ /* modify energy of white noise according to synthesis tilt */
+ gain1 = 32767 - fac;
+ gain2 = vo_mult(gain1, 20480);
+ gain2 = shl(gain2, 1);
- if (st->vad_hist > 0)
- {
- weight1 = 0;
- weight2 = 32767;
- } else
- {
- weight1 = 32767;
- weight2 = 0;
- }
- tmp = vo_mult(weight1, gain1);
- tmp = add1(tmp, vo_mult(weight2, gain2));
+ if (st->vad_hist > 0)
+ {
+ weight1 = 0;
+ weight2 = 32767;
+ } else
+ {
+ weight1 = 32767;
+ weight2 = 0;
+ }
+ tmp = vo_mult(weight1, gain1);
+ tmp = add1(tmp, vo_mult(weight2, gain2));
- if (tmp != 0)
- {
- tmp = (tmp + 1);
- }
- HP_est_gain = tmp;
+ if (tmp != 0)
+ {
+ tmp = (tmp + 1);
+ }
+ HP_est_gain = tmp;
- if(HP_est_gain < 3277)
- {
- HP_est_gain = 3277; /* 0.1 in Q15 */
- }
- /* synthesis of noise: 4.8kHz..5.6kHz --> 6kHz..7kHz */
- Weight_a(Aq, Ap, 19661, M); /* fac=0.6 */
+ if(HP_est_gain < 3277)
+ {
+ HP_est_gain = 3277; /* 0.1 in Q15 */
+ }
+ /* synthesis of noise: 4.8kHz..5.6kHz --> 6kHz..7kHz */
+ Weight_a(Aq, Ap, 19661, M); /* fac=0.6 */
#ifdef ASM_OPT /* asm optimization branch */
- Syn_filt_asm(Ap, HF, HF, st->mem_syn_hf);
- /* noise High Pass filtering (1ms of delay) */
- Filt_6k_7k_asm(HF, L_SUBFR16k, st->mem_hf);
- /* filtering of the original signal */
- Filt_6k_7k_asm(HF_SP, L_SUBFR16k, st->mem_hf2);
+ Syn_filt_asm(Ap, HF, HF, st->mem_syn_hf);
+ /* noise High Pass filtering (1ms of delay) */
+ Filt_6k_7k_asm(HF, L_SUBFR16k, st->mem_hf);
+ /* filtering of the original signal */
+ Filt_6k_7k_asm(HF_SP, L_SUBFR16k, st->mem_hf2);
- /* check the gain difference */
- Scale_sig_opt(HF_SP, L_SUBFR16k, -1);
- ener = extract_h(Dot_product12_asm(HF_SP, HF_SP, L_SUBFR16k, &exp_ener));
- /* set energy of white noise to energy of excitation */
- tmp = extract_h(Dot_product12_asm(HF, HF, L_SUBFR16k, &exp));
+ /* check the gain difference */
+ Scale_sig_opt(HF_SP, L_SUBFR16k, -1);
+ ener = extract_h(Dot_product12_asm(HF_SP, HF_SP, L_SUBFR16k, &exp_ener));
+ /* set energy of white noise to energy of excitation */
+ tmp = extract_h(Dot_product12_asm(HF, HF, L_SUBFR16k, &exp));
#else
- Syn_filt(Ap, HF, HF, L_SUBFR16k, st->mem_syn_hf, 1);
- /* noise High Pass filtering (1ms of delay) */
- Filt_6k_7k(HF, L_SUBFR16k, st->mem_hf);
- /* filtering of the original signal */
- Filt_6k_7k(HF_SP, L_SUBFR16k, st->mem_hf2);
- /* check the gain difference */
- Scale_sig(HF_SP, L_SUBFR16k, -1);
- ener = extract_h(Dot_product12(HF_SP, HF_SP, L_SUBFR16k, &exp_ener));
- /* set energy of white noise to energy of excitation */
- tmp = extract_h(Dot_product12(HF, HF, L_SUBFR16k, &exp));
+ Syn_filt(Ap, HF, HF, L_SUBFR16k, st->mem_syn_hf, 1);
+ /* noise High Pass filtering (1ms of delay) */
+ Filt_6k_7k(HF, L_SUBFR16k, st->mem_hf);
+ /* filtering of the original signal */
+ Filt_6k_7k(HF_SP, L_SUBFR16k, st->mem_hf2);
+ /* check the gain difference */
+ Scale_sig(HF_SP, L_SUBFR16k, -1);
+ ener = extract_h(Dot_product12(HF_SP, HF_SP, L_SUBFR16k, &exp_ener));
+ /* set energy of white noise to energy of excitation */
+ tmp = extract_h(Dot_product12(HF, HF, L_SUBFR16k, &exp));
#endif
- if (tmp > ener)
- {
- tmp = (tmp >> 1); /* Be sure tmp < ener */
- exp = (exp + 1);
- }
- L_tmp = L_deposit_h(div_s(tmp, ener)); /* result is normalized */
- exp = vo_sub(exp, exp_ener);
- Isqrt_n(&L_tmp, &exp);
- L_tmp = L_shl(L_tmp, exp); /* L_tmp, L_tmp in Q31 */
- HP_calc_gain = extract_h(L_tmp); /* tmp = sqrt(ener_input/ener_hf) */
+ if (tmp > ener)
+ {
+ tmp = (tmp >> 1); /* Be sure tmp < ener */
+ exp = (exp + 1);
+ }
+ L_tmp = L_deposit_h(div_s(tmp, ener)); /* result is normalized */
+ exp = vo_sub(exp, exp_ener);
+ Isqrt_n(&L_tmp, &exp);
+ L_tmp = L_shl(L_tmp, exp); /* L_tmp, L_tmp in Q31 */
+ HP_calc_gain = extract_h(L_tmp); /* tmp = sqrt(ener_input/ener_hf) */
- /* st->gain_alpha *= st->dtx_encSt->dtxHangoverCount/7 */
- L_tmp = (vo_L_mult(st->dtx_encSt->dtxHangoverCount, 4681) << 15);
- st->gain_alpha = vo_mult(st->gain_alpha, extract_h(L_tmp));
+ /* st->gain_alpha *= st->dtx_encSt->dtxHangoverCount/7 */
+ L_tmp = (vo_L_mult(st->dtx_encSt->dtxHangoverCount, 4681) << 15);
+ st->gain_alpha = vo_mult(st->gain_alpha, extract_h(L_tmp));
- if(st->dtx_encSt->dtxHangoverCount > 6)
- st->gain_alpha = 32767;
- HP_est_gain = HP_est_gain >> 1; /* From Q15 to Q14 */
- HP_corr_gain = add1(vo_mult(HP_calc_gain, st->gain_alpha), vo_mult((32767 - st->gain_alpha), HP_est_gain));
+ if(st->dtx_encSt->dtxHangoverCount > 6)
+ st->gain_alpha = 32767;
+ HP_est_gain = HP_est_gain >> 1; /* From Q15 to Q14 */
+ HP_corr_gain = add1(vo_mult(HP_calc_gain, st->gain_alpha), vo_mult((32767 - st->gain_alpha), HP_est_gain));
- /* Quantise the correction gain */
- dist_min = 32767;
- for (i = 0; i < 16; i++)
- {
- dist = vo_mult((HP_corr_gain - HP_gain[i]), (HP_corr_gain - HP_gain[i]));
- if (dist_min > dist)
- {
- dist_min = dist;
- HP_gain_ind = i;
- }
- }
- HP_corr_gain = HP_gain[HP_gain_ind];
- /* return the quantised gain index when using the highest mode, otherwise zero */
- return (HP_gain_ind);
+ /* Quantise the correction gain */
+ dist_min = 32767;
+ for (i = 0; i < 16; i++)
+ {
+ dist = vo_mult((HP_corr_gain - HP_gain[i]), (HP_corr_gain - HP_gain[i]));
+ if (dist_min > dist)
+ {
+ dist_min = dist;
+ HP_gain_ind = i;
+ }
+ }
+ HP_corr_gain = HP_gain[HP_gain_ind];
+ /* return the quantised gain index when using the highest mode, otherwise zero */
+ return (HP_gain_ind);
}
/*************************************************
@@ -1558,33 +1562,33 @@
int AMR_Enc_Encode(HAMRENC hCodec)
{
- Word32 i;
- Coder_State *gData = (Coder_State*)hCodec;
- Word16 *signal;
- Word16 packed_size = 0;
- Word16 prms[NB_BITS_MAX];
- Word16 coding_mode = 0, nb_bits, allow_dtx, mode, reset_flag;
- mode = gData->mode;
- coding_mode = gData->mode;
- nb_bits = nb_of_bits[mode];
- signal = (Word16 *)gData->inputStream;
- allow_dtx = gData->allow_dtx;
+ Word32 i;
+ Coder_State *gData = (Coder_State*)hCodec;
+ Word16 *signal;
+ Word16 packed_size = 0;
+ Word16 prms[NB_BITS_MAX];
+ Word16 coding_mode = 0, nb_bits, allow_dtx, mode, reset_flag;
+ mode = gData->mode;
+ coding_mode = gData->mode;
+ nb_bits = nb_of_bits[mode];
+ signal = (Word16 *)gData->inputStream;
+ allow_dtx = gData->allow_dtx;
- /* check for homing frame */
- reset_flag = encoder_homing_frame_test(signal);
+ /* check for homing frame */
+ reset_flag = encoder_homing_frame_test(signal);
- for (i = 0; i < L_FRAME16k; i++) /* Delete the 2 LSBs (14-bit input) */
- {
- *(signal + i) = (Word16) (*(signal + i) & 0xfffC);
- }
+ for (i = 0; i < L_FRAME16k; i++) /* Delete the 2 LSBs (14-bit input) */
+ {
+ *(signal + i) = (Word16) (*(signal + i) & 0xfffC);
+ }
- coder(&coding_mode, signal, prms, &nb_bits, gData, allow_dtx);
- packed_size = PackBits(prms, coding_mode, mode, gData);
- if (reset_flag != 0)
- {
- Reset_encoder(gData, 1);
- }
- return packed_size;
+ coder(&coding_mode, signal, prms, &nb_bits, gData, allow_dtx);
+ packed_size = PackBits(prms, coding_mode, mode, gData);
+ if (reset_flag != 0)
+ {
+ Reset_encoder(gData, 1);
+ }
+ return packed_size;
}
/***************************************************************************
@@ -1594,94 +1598,94 @@
***************************************************************************/
VO_U32 VO_API voAMRWB_Init(VO_HANDLE * phCodec, /* o: the audio codec handle */
- VO_AUDIO_CODINGTYPE vType, /* i: Codec Type ID */
- VO_CODEC_INIT_USERDATA * pUserData /* i: init Parameters */
- )
+ VO_AUDIO_CODINGTYPE vType, /* i: Codec Type ID */
+ VO_CODEC_INIT_USERDATA * pUserData /* i: init Parameters */
+ )
{
- Coder_State *st;
- FrameStream *stream;
+ Coder_State *st;
+ FrameStream *stream;
#ifdef USE_DEAULT_MEM
- VO_MEM_OPERATOR voMemoprator;
+ VO_MEM_OPERATOR voMemoprator;
#endif
- VO_MEM_OPERATOR *pMemOP;
+ VO_MEM_OPERATOR *pMemOP;
UNUSED(vType);
- int interMem = 0;
+ int interMem = 0;
- if(pUserData == NULL || pUserData->memflag != VO_IMF_USERMEMOPERATOR || pUserData->memData == NULL )
- {
+ if(pUserData == NULL || pUserData->memflag != VO_IMF_USERMEMOPERATOR || pUserData->memData == NULL )
+ {
#ifdef USE_DEAULT_MEM
- voMemoprator.Alloc = cmnMemAlloc;
- voMemoprator.Copy = cmnMemCopy;
- voMemoprator.Free = cmnMemFree;
- voMemoprator.Set = cmnMemSet;
- voMemoprator.Check = cmnMemCheck;
- interMem = 1;
- pMemOP = &voMemoprator;
+ voMemoprator.Alloc = cmnMemAlloc;
+ voMemoprator.Copy = cmnMemCopy;
+ voMemoprator.Free = cmnMemFree;
+ voMemoprator.Set = cmnMemSet;
+ voMemoprator.Check = cmnMemCheck;
+ interMem = 1;
+ pMemOP = &voMemoprator;
#else
- *phCodec = NULL;
- return VO_ERR_INVALID_ARG;
+ *phCodec = NULL;
+ return VO_ERR_INVALID_ARG;
#endif
- }
- else
- {
- pMemOP = (VO_MEM_OPERATOR *)pUserData->memData;
- }
- /*-------------------------------------------------------------------------*
- * Memory allocation for coder state. *
- *-------------------------------------------------------------------------*/
- if ((st = (Coder_State *)mem_malloc(pMemOP, sizeof(Coder_State), 32, VO_INDEX_ENC_AMRWB)) == NULL)
- {
- return VO_ERR_OUTOF_MEMORY;
- }
+ }
+ else
+ {
+ pMemOP = (VO_MEM_OPERATOR *)pUserData->memData;
+ }
+ /*-------------------------------------------------------------------------*
+ * Memory allocation for coder state. *
+ *-------------------------------------------------------------------------*/
+ if ((st = (Coder_State *)mem_malloc(pMemOP, sizeof(Coder_State), 32, VO_INDEX_ENC_AMRWB)) == NULL)
+ {
+ return VO_ERR_OUTOF_MEMORY;
+ }
- st->vadSt = NULL;
- st->dtx_encSt = NULL;
- st->sid_update_counter = 3;
- st->sid_handover_debt = 0;
- st->prev_ft = TX_SPEECH;
- st->inputStream = NULL;
- st->inputSize = 0;
+ st->vadSt = NULL;
+ st->dtx_encSt = NULL;
+ st->sid_update_counter = 3;
+ st->sid_handover_debt = 0;
+ st->prev_ft = TX_SPEECH;
+ st->inputStream = NULL;
+ st->inputSize = 0;
- /* Default setting */
- st->mode = VOAMRWB_MD2385; /* bit rate 23.85kbps */
- st->frameType = VOAMRWB_RFC3267; /* frame type: RFC3267 */
- st->allow_dtx = 0; /* disable DTX mode */
+ /* Default setting */
+ st->mode = VOAMRWB_MD2385; /* bit rate 23.85kbps */
+ st->frameType = VOAMRWB_RFC3267; /* frame type: RFC3267 */
+ st->allow_dtx = 0; /* disable DTX mode */
- st->outputStream = NULL;
- st->outputSize = 0;
+ st->outputStream = NULL;
+ st->outputSize = 0;
- st->stream = (FrameStream *)mem_malloc(pMemOP, sizeof(FrameStream), 32, VO_INDEX_ENC_AMRWB);
- if(st->stream == NULL)
- return VO_ERR_OUTOF_MEMORY;
+ st->stream = (FrameStream *)mem_malloc(pMemOP, sizeof(FrameStream), 32, VO_INDEX_ENC_AMRWB);
+ if(st->stream == NULL)
+ return VO_ERR_OUTOF_MEMORY;
- st->stream->frame_ptr = (unsigned char *)mem_malloc(pMemOP, Frame_Maxsize, 32, VO_INDEX_ENC_AMRWB);
- if(st->stream->frame_ptr == NULL)
- return VO_ERR_OUTOF_MEMORY;
+ st->stream->frame_ptr = (unsigned char *)mem_malloc(pMemOP, Frame_Maxsize, 32, VO_INDEX_ENC_AMRWB);
+ if(st->stream->frame_ptr == NULL)
+ return VO_ERR_OUTOF_MEMORY;
- stream = st->stream;
- voAWB_InitFrameBuffer(stream);
+ stream = st->stream;
+ voAWB_InitFrameBuffer(stream);
- wb_vad_init(&(st->vadSt), pMemOP);
- dtx_enc_init(&(st->dtx_encSt), isf_init, pMemOP);
+ wb_vad_init(&(st->vadSt), pMemOP);
+ dtx_enc_init(&(st->dtx_encSt), isf_init, pMemOP);
- Reset_encoder((void *) st, 1);
+ Reset_encoder((void *) st, 1);
- if(interMem)
- {
- st->voMemoprator.Alloc = cmnMemAlloc;
- st->voMemoprator.Copy = cmnMemCopy;
- st->voMemoprator.Free = cmnMemFree;
- st->voMemoprator.Set = cmnMemSet;
- st->voMemoprator.Check = cmnMemCheck;
- pMemOP = &st->voMemoprator;
- }
+ if(interMem)
+ {
+ st->voMemoprator.Alloc = cmnMemAlloc;
+ st->voMemoprator.Copy = cmnMemCopy;
+ st->voMemoprator.Free = cmnMemFree;
+ st->voMemoprator.Set = cmnMemSet;
+ st->voMemoprator.Check = cmnMemCheck;
+ pMemOP = &st->voMemoprator;
+ }
- st->pvoMemop = pMemOP;
+ st->pvoMemop = pMemOP;
- *phCodec = (void *) st;
+ *phCodec = (void *) st;
- return VO_ERR_NONE;
+ return VO_ERR_NONE;
}
/**********************************************************************************
@@ -1691,32 +1695,32 @@
***********************************************************************************/
VO_U32 VO_API voAMRWB_SetInputData(
- VO_HANDLE hCodec, /* i/o: The codec handle which was created by Init function */
- VO_CODECBUFFER * pInput /* i: The input buffer parameter */
- )
+ VO_HANDLE hCodec, /* i/o: The codec handle which was created by Init function */
+ VO_CODECBUFFER * pInput /* i: The input buffer parameter */
+ )
{
- Coder_State *gData;
- FrameStream *stream;
+ Coder_State *gData;
+ FrameStream *stream;
- if(NULL == hCodec)
- {
- return VO_ERR_INVALID_ARG;
- }
+ if(NULL == hCodec)
+ {
+ return VO_ERR_INVALID_ARG;
+ }
- gData = (Coder_State *)hCodec;
- stream = gData->stream;
+ gData = (Coder_State *)hCodec;
+ stream = gData->stream;
- if(NULL == pInput || NULL == pInput->Buffer)
- {
- return VO_ERR_INVALID_ARG;
- }
+ if(NULL == pInput || NULL == pInput->Buffer)
+ {
+ return VO_ERR_INVALID_ARG;
+ }
- stream->set_ptr = pInput->Buffer;
- stream->set_len = pInput->Length;
- stream->frame_ptr = stream->frame_ptr_bk;
- stream->used_len = 0;
+ stream->set_ptr = pInput->Buffer;
+ stream->set_len = pInput->Length;
+ stream->frame_ptr = stream->frame_ptr_bk;
+ stream->used_len = 0;
- return VO_ERR_NONE;
+ return VO_ERR_NONE;
}
/**************************************************************************************
@@ -1726,52 +1730,52 @@
***************************************************************************************/
VO_U32 VO_API voAMRWB_GetOutputData(
- VO_HANDLE hCodec, /* i: The Codec Handle which was created by Init function*/
- VO_CODECBUFFER * pOutput, /* o: The output audio data */
- VO_AUDIO_OUTPUTINFO * pAudioFormat /* o: The encoder module filled audio format and used the input size*/
- )
+ VO_HANDLE hCodec, /* i: The Codec Handle which was created by Init function*/
+ VO_CODECBUFFER * pOutput, /* o: The output audio data */
+ VO_AUDIO_OUTPUTINFO * pAudioFormat /* o: The encoder module filled audio format and used the input size*/
+ )
{
- Coder_State* gData = (Coder_State*)hCodec;
- VO_MEM_OPERATOR *pMemOP;
- FrameStream *stream = (FrameStream *)gData->stream;
- pMemOP = (VO_MEM_OPERATOR *)gData->pvoMemop;
+ Coder_State* gData = (Coder_State*)hCodec;
+ VO_MEM_OPERATOR *pMemOP;
+ FrameStream *stream = (FrameStream *)gData->stream;
+ pMemOP = (VO_MEM_OPERATOR *)gData->pvoMemop;
- if(stream->framebuffer_len < Frame_MaxByte) /* check the work buffer len */
- {
- stream->frame_storelen = stream->framebuffer_len;
- if(stream->frame_storelen)
- {
- pMemOP->Copy(VO_INDEX_ENC_AMRWB, stream->frame_ptr_bk , stream->frame_ptr , stream->frame_storelen);
- }
- if(stream->set_len > 0)
- {
- voAWB_UpdateFrameBuffer(stream, pMemOP);
- }
- if(stream->framebuffer_len < Frame_MaxByte)
- {
- if(pAudioFormat)
- pAudioFormat->InputUsed = stream->used_len;
- return VO_ERR_INPUT_BUFFER_SMALL;
- }
- }
+ if(stream->framebuffer_len < Frame_MaxByte) /* check the work buffer len */
+ {
+ stream->frame_storelen = stream->framebuffer_len;
+ if(stream->frame_storelen)
+ {
+ pMemOP->Copy(VO_INDEX_ENC_AMRWB, stream->frame_ptr_bk , stream->frame_ptr , stream->frame_storelen);
+ }
+ if(stream->set_len > 0)
+ {
+ voAWB_UpdateFrameBuffer(stream, pMemOP);
+ }
+ if(stream->framebuffer_len < Frame_MaxByte)
+ {
+ if(pAudioFormat)
+ pAudioFormat->InputUsed = stream->used_len;
+ return VO_ERR_INPUT_BUFFER_SMALL;
+ }
+ }
- gData->inputStream = stream->frame_ptr;
- gData->outputStream = (unsigned short*)pOutput->Buffer;
+ gData->inputStream = stream->frame_ptr;
+ gData->outputStream = (unsigned short*)pOutput->Buffer;
- gData->outputSize = AMR_Enc_Encode(gData); /* encoder main function */
+ gData->outputSize = AMR_Enc_Encode(gData); /* encoder main function */
- pOutput->Length = gData->outputSize; /* get the output buffer length */
- stream->frame_ptr += 640; /* update the work buffer ptr */
- stream->framebuffer_len -= 640;
+ pOutput->Length = gData->outputSize; /* get the output buffer length */
+ stream->frame_ptr += 640; /* update the work buffer ptr */
+ stream->framebuffer_len -= 640;
- if(pAudioFormat) /* return output audio information */
- {
- pAudioFormat->Format.Channels = 1;
- pAudioFormat->Format.SampleRate = 8000;
- pAudioFormat->Format.SampleBits = 16;
- pAudioFormat->InputUsed = stream->used_len;
- }
- return VO_ERR_NONE;
+ if(pAudioFormat) /* return output audio information */
+ {
+ pAudioFormat->Format.Channels = 1;
+ pAudioFormat->Format.SampleRate = 8000;
+ pAudioFormat->Format.SampleBits = 16;
+ pAudioFormat->InputUsed = stream->used_len;
+ }
+ return VO_ERR_NONE;
}
/*************************************************************************
@@ -1782,50 +1786,50 @@
VO_U32 VO_API voAMRWB_SetParam(
- VO_HANDLE hCodec, /* i/o: The Codec Handle which was created by Init function */
- VO_S32 uParamID, /* i: The param ID */
- VO_PTR pData /* i: The param value depend on the ID */
- )
+ VO_HANDLE hCodec, /* i/o: The Codec Handle which was created by Init function */
+ VO_S32 uParamID, /* i: The param ID */
+ VO_PTR pData /* i: The param value depend on the ID */
+ )
{
- Coder_State* gData = (Coder_State*)hCodec;
- FrameStream *stream = (FrameStream *)(gData->stream);
- int *lValue = (int*)pData;
+ Coder_State* gData = (Coder_State*)hCodec;
+ FrameStream *stream = (FrameStream *)(gData->stream);
+ int *lValue = (int*)pData;
- switch(uParamID)
- {
- /* setting AMR-WB frame type*/
- case VO_PID_AMRWB_FRAMETYPE:
- if(*lValue < VOAMRWB_DEFAULT || *lValue > VOAMRWB_RFC3267)
- return VO_ERR_WRONG_PARAM_ID;
- gData->frameType = *lValue;
- break;
- /* setting AMR-WB bit rate */
- case VO_PID_AMRWB_MODE:
- {
- if(*lValue < VOAMRWB_MD66 || *lValue > VOAMRWB_MD2385)
- return VO_ERR_WRONG_PARAM_ID;
- gData->mode = *lValue;
- }
- break;
- /* enable or disable DTX mode */
- case VO_PID_AMRWB_DTX:
- gData->allow_dtx = (Word16)(*lValue);
- break;
+ switch(uParamID)
+ {
+ /* setting AMR-WB frame type*/
+ case VO_PID_AMRWB_FRAMETYPE:
+ if(*lValue < VOAMRWB_DEFAULT || *lValue > VOAMRWB_RFC3267)
+ return VO_ERR_WRONG_PARAM_ID;
+ gData->frameType = *lValue;
+ break;
+ /* setting AMR-WB bit rate */
+ case VO_PID_AMRWB_MODE:
+ {
+ if(*lValue < VOAMRWB_MD66 || *lValue > VOAMRWB_MD2385)
+ return VO_ERR_WRONG_PARAM_ID;
+ gData->mode = *lValue;
+ }
+ break;
+ /* enable or disable DTX mode */
+ case VO_PID_AMRWB_DTX:
+ gData->allow_dtx = (Word16)(*lValue);
+ break;
- case VO_PID_COMMON_HEADDATA:
- break;
+ case VO_PID_COMMON_HEADDATA:
+ break;
/* flush the work buffer */
- case VO_PID_COMMON_FLUSH:
- stream->set_ptr = NULL;
- stream->frame_storelen = 0;
- stream->framebuffer_len = 0;
- stream->set_len = 0;
- break;
+ case VO_PID_COMMON_FLUSH:
+ stream->set_ptr = NULL;
+ stream->frame_storelen = 0;
+ stream->framebuffer_len = 0;
+ stream->set_len = 0;
+ break;
- default:
- return VO_ERR_WRONG_PARAM_ID;
- }
- return VO_ERR_NONE;
+ default:
+ return VO_ERR_WRONG_PARAM_ID;
+ }
+ return VO_ERR_NONE;
}
/**************************************************************************
@@ -1835,52 +1839,52 @@
***************************************************************************/
VO_U32 VO_API voAMRWB_GetParam(
- VO_HANDLE hCodec, /* i: The Codec Handle which was created by Init function */
- VO_S32 uParamID, /* i: The param ID */
- VO_PTR pData /* o: The param value depend on the ID */
- )
+ VO_HANDLE hCodec, /* i: The Codec Handle which was created by Init function */
+ VO_S32 uParamID, /* i: The param ID */
+ VO_PTR pData /* o: The param value depend on the ID */
+ )
{
- int temp;
- Coder_State* gData = (Coder_State*)hCodec;
+ int temp;
+ Coder_State* gData = (Coder_State*)hCodec;
- if (gData==NULL)
- return VO_ERR_INVALID_ARG;
- switch(uParamID)
- {
- /* output audio format */
- case VO_PID_AMRWB_FORMAT:
- {
- VO_AUDIO_FORMAT* fmt = (VO_AUDIO_FORMAT*)pData;
- fmt->Channels = 1;
- fmt->SampleRate = 16000;
- fmt->SampleBits = 16;
- break;
- }
+ if (gData==NULL)
+ return VO_ERR_INVALID_ARG;
+ switch(uParamID)
+ {
+ /* output audio format */
+ case VO_PID_AMRWB_FORMAT:
+ {
+ VO_AUDIO_FORMAT* fmt = (VO_AUDIO_FORMAT*)pData;
+ fmt->Channels = 1;
+ fmt->SampleRate = 16000;
+ fmt->SampleBits = 16;
+ break;
+ }
/* output audio channel number */
- case VO_PID_AMRWB_CHANNELS:
- temp = 1;
- pData = (void *)(&temp);
- break;
+ case VO_PID_AMRWB_CHANNELS:
+ temp = 1;
+ pData = (void *)(&temp);
+ break;
/* output audio sample rate */
- case VO_PID_AMRWB_SAMPLERATE:
- temp = 16000;
- pData = (void *)(&temp);
- break;
- /* output audio frame type */
- case VO_PID_AMRWB_FRAMETYPE:
- temp = gData->frameType;
- pData = (void *)(&temp);
- break;
- /* output audio bit rate */
- case VO_PID_AMRWB_MODE:
- temp = gData->mode;
- pData = (void *)(&temp);
- break;
- default:
- return VO_ERR_WRONG_PARAM_ID;
- }
+ case VO_PID_AMRWB_SAMPLERATE:
+ temp = 16000;
+ pData = (void *)(&temp);
+ break;
+ /* output audio frame type */
+ case VO_PID_AMRWB_FRAMETYPE:
+ temp = gData->frameType;
+ pData = (void *)(&temp);
+ break;
+ /* output audio bit rate */
+ case VO_PID_AMRWB_MODE:
+ temp = gData->mode;
+ pData = (void *)(&temp);
+ break;
+ default:
+ return VO_ERR_WRONG_PARAM_ID;
+ }
- return VO_ERR_NONE;
+ return VO_ERR_NONE;
}
/***********************************************************************************
@@ -1890,32 +1894,32 @@
*************************************************************************************/
VO_U32 VO_API voAMRWB_Uninit(VO_HANDLE hCodec /* i/o: Codec handle pointer */
- )
+ )
{
- Coder_State* gData = (Coder_State*)hCodec;
- VO_MEM_OPERATOR *pMemOP;
- pMemOP = gData->pvoMemop;
+ Coder_State* gData = (Coder_State*)hCodec;
+ VO_MEM_OPERATOR *pMemOP;
+ pMemOP = gData->pvoMemop;
- if(hCodec)
- {
- if(gData->stream)
- {
- if(gData->stream->frame_ptr_bk)
- {
- mem_free(pMemOP, gData->stream->frame_ptr_bk, VO_INDEX_ENC_AMRWB);
- gData->stream->frame_ptr_bk = NULL;
- }
- mem_free(pMemOP, gData->stream, VO_INDEX_ENC_AMRWB);
- gData->stream = NULL;
- }
- wb_vad_exit(&(((Coder_State *) gData)->vadSt), pMemOP);
- dtx_enc_exit(&(((Coder_State *) gData)->dtx_encSt), pMemOP);
+ if(hCodec)
+ {
+ if(gData->stream)
+ {
+ if(gData->stream->frame_ptr_bk)
+ {
+ mem_free(pMemOP, gData->stream->frame_ptr_bk, VO_INDEX_ENC_AMRWB);
+ gData->stream->frame_ptr_bk = NULL;
+ }
+ mem_free(pMemOP, gData->stream, VO_INDEX_ENC_AMRWB);
+ gData->stream = NULL;
+ }
+ wb_vad_exit(&(((Coder_State *) gData)->vadSt), pMemOP);
+ dtx_enc_exit(&(((Coder_State *) gData)->dtx_encSt), pMemOP);
- mem_free(pMemOP, hCodec, VO_INDEX_ENC_AMRWB);
- hCodec = NULL;
- }
+ mem_free(pMemOP, hCodec, VO_INDEX_ENC_AMRWB);
+ hCodec = NULL;
+ }
- return VO_ERR_NONE;
+ return VO_ERR_NONE;
}
/********************************************************************************
@@ -1925,19 +1929,19 @@
********************************************************************************/
VO_S32 VO_API voGetAMRWBEncAPI(
- VO_AUDIO_CODECAPI * pEncHandle /* i/o: Codec handle pointer */
- )
+ VO_AUDIO_CODECAPI * pEncHandle /* i/o: Codec handle pointer */
+ )
{
- if(NULL == pEncHandle)
- return VO_ERR_INVALID_ARG;
- pEncHandle->Init = voAMRWB_Init;
- pEncHandle->SetInputData = voAMRWB_SetInputData;
- pEncHandle->GetOutputData = voAMRWB_GetOutputData;
- pEncHandle->SetParam = voAMRWB_SetParam;
- pEncHandle->GetParam = voAMRWB_GetParam;
- pEncHandle->Uninit = voAMRWB_Uninit;
+ if(NULL == pEncHandle)
+ return VO_ERR_INVALID_ARG;
+ pEncHandle->Init = voAMRWB_Init;
+ pEncHandle->SetInputData = voAMRWB_SetInputData;
+ pEncHandle->GetOutputData = voAMRWB_GetOutputData;
+ pEncHandle->SetParam = voAMRWB_SetParam;
+ pEncHandle->GetParam = voAMRWB_GetParam;
+ pEncHandle->Uninit = voAMRWB_Uninit;
- return VO_ERR_NONE;
+ return VO_ERR_NONE;
}
#ifdef __cplusplus
diff --git a/media/libstagefright/codecs/amrwbenc/src/voicefac.c b/media/libstagefright/codecs/amrwbenc/src/voicefac.c
index d890044..c9f48c2 100644
--- a/media/libstagefright/codecs/amrwbenc/src/voicefac.c
+++ b/media/libstagefright/codecs/amrwbenc/src/voicefac.c
@@ -26,65 +26,65 @@
#include "math_op.h"
Word16 voice_factor( /* (o) Q15 : factor (-1=unvoiced to 1=voiced) */
- Word16 exc[], /* (i) Q_exc : pitch excitation */
- Word16 Q_exc, /* (i) : exc format */
- Word16 gain_pit, /* (i) Q14 : gain of pitch */
- Word16 code[], /* (i) Q9 : Fixed codebook excitation */
- Word16 gain_code, /* (i) Q0 : gain of code */
- Word16 L_subfr /* (i) : subframe length */
- )
+ Word16 exc[], /* (i) Q_exc : pitch excitation */
+ Word16 Q_exc, /* (i) : exc format */
+ Word16 gain_pit, /* (i) Q14 : gain of pitch */
+ Word16 code[], /* (i) Q9 : Fixed codebook excitation */
+ Word16 gain_code, /* (i) Q0 : gain of code */
+ Word16 L_subfr /* (i) : subframe length */
+ )
{
- Word16 tmp, exp, ener1, exp1, ener2, exp2;
- Word32 i, L_tmp;
+ Word16 tmp, exp, ener1, exp1, ener2, exp2;
+ Word32 i, L_tmp;
#ifdef ASM_OPT /* asm optimization branch */
- ener1 = extract_h(Dot_product12_asm(exc, exc, L_subfr, &exp1));
+ ener1 = extract_h(Dot_product12_asm(exc, exc, L_subfr, &exp1));
#else
- ener1 = extract_h(Dot_product12(exc, exc, L_subfr, &exp1));
+ ener1 = extract_h(Dot_product12(exc, exc, L_subfr, &exp1));
#endif
- exp1 = exp1 - (Q_exc + Q_exc);
- L_tmp = vo_L_mult(gain_pit, gain_pit);
- exp = norm_l(L_tmp);
- tmp = extract_h(L_tmp << exp);
- ener1 = vo_mult(ener1, tmp);
- exp1 = exp1 - exp - 10; /* 10 -> gain_pit Q14 to Q9 */
+ exp1 = exp1 - (Q_exc + Q_exc);
+ L_tmp = vo_L_mult(gain_pit, gain_pit);
+ exp = norm_l(L_tmp);
+ tmp = extract_h(L_tmp << exp);
+ ener1 = vo_mult(ener1, tmp);
+ exp1 = exp1 - exp - 10; /* 10 -> gain_pit Q14 to Q9 */
#ifdef ASM_OPT /* asm optimization branch */
- ener2 = extract_h(Dot_product12_asm(code, code, L_subfr, &exp2));
+ ener2 = extract_h(Dot_product12_asm(code, code, L_subfr, &exp2));
#else
- ener2 = extract_h(Dot_product12(code, code, L_subfr, &exp2));
+ ener2 = extract_h(Dot_product12(code, code, L_subfr, &exp2));
#endif
- exp = norm_s(gain_code);
- tmp = gain_code << exp;
- tmp = vo_mult(tmp, tmp);
- ener2 = vo_mult(ener2, tmp);
- exp2 = exp2 - (exp + exp);
+ exp = norm_s(gain_code);
+ tmp = gain_code << exp;
+ tmp = vo_mult(tmp, tmp);
+ ener2 = vo_mult(ener2, tmp);
+ exp2 = exp2 - (exp + exp);
- i = exp1 - exp2;
+ i = exp1 - exp2;
- if (i >= 0)
- {
- ener1 = ener1 >> 1;
- ener2 = ener2 >> (i + 1);
- } else
- {
- ener1 = ener1 >> (1 - i);
- ener2 = ener2 >> 1;
- }
+ if (i >= 0)
+ {
+ ener1 = ener1 >> 1;
+ ener2 = ener2 >> (i + 1);
+ } else
+ {
+ ener1 = ener1 >> (1 - i);
+ ener2 = ener2 >> 1;
+ }
- tmp = vo_sub(ener1, ener2);
- ener1 = add1(add1(ener1, ener2), 1);
+ tmp = vo_sub(ener1, ener2);
+ ener1 = add1(add1(ener1, ener2), 1);
- if (tmp >= 0)
- {
- tmp = div_s(tmp, ener1);
- } else
- {
- tmp = vo_negate(div_s(vo_negate(tmp), ener1));
- }
+ if (tmp >= 0)
+ {
+ tmp = div_s(tmp, ener1);
+ } else
+ {
+ tmp = vo_negate(div_s(vo_negate(tmp), ener1));
+ }
- return (tmp);
+ return (tmp);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/wb_vad.c b/media/libstagefright/codecs/amrwbenc/src/wb_vad.c
index 2beaefd..866a69c 100644
--- a/media/libstagefright/codecs/amrwbenc/src/wb_vad.c
+++ b/media/libstagefright/codecs/amrwbenc/src/wb_vad.c
@@ -44,30 +44,30 @@
*********************************************************************************/
static Word16 ilog2( /* return: output value of the log2 */
- Word16 mant /* i: value to be converted */
- )
+ Word16 mant /* i: value to be converted */
+ )
{
- Word16 ex, ex2, res;
- Word32 i, l_temp;
+ Word16 ex, ex2, res;
+ Word32 i, l_temp;
- if (mant <= 0)
- {
- mant = 1;
- }
- ex = norm_s(mant);
- mant = mant << ex;
+ if (mant <= 0)
+ {
+ mant = 1;
+ }
+ ex = norm_s(mant);
+ mant = mant << ex;
- for (i = 0; i < 3; i++)
- mant = vo_mult(mant, mant);
- l_temp = vo_L_mult(mant, mant);
+ for (i = 0; i < 3; i++)
+ mant = vo_mult(mant, mant);
+ l_temp = vo_L_mult(mant, mant);
- ex2 = norm_l(l_temp);
- mant = extract_h(l_temp << ex2);
+ ex2 = norm_l(l_temp);
+ mant = extract_h(l_temp << ex2);
- res = (ex + 16) << 10;
- res = add1(res, (ex2 << 6));
- res = vo_sub(add1(res, 127), (mant >> 8));
- return (res);
+ res = (ex + 16) << 10;
+ res = add1(res, (ex2 << 6));
+ res = vo_sub(add1(res, 127), (mant >> 8));
+ return (res);
}
/******************************************************************************
@@ -79,23 +79,23 @@
*******************************************************************************/
static void filter5(
- Word16 * in0, /* i/o : input values; output low-pass part */
- Word16 * in1, /* i/o : input values; output high-pass part */
- Word16 data[] /* i/o : filter memory */
- )
+ Word16 * in0, /* i/o : input values; output low-pass part */
+ Word16 * in1, /* i/o : input values; output high-pass part */
+ Word16 data[] /* i/o : filter memory */
+ )
{
- Word16 temp0, temp1, temp2;
+ Word16 temp0, temp1, temp2;
- temp0 = vo_sub(*in0, vo_mult(COEFF5_1, data[0]));
- temp1 = add1(data[0], vo_mult(COEFF5_1, temp0));
- data[0] = temp0;
+ temp0 = vo_sub(*in0, vo_mult(COEFF5_1, data[0]));
+ temp1 = add1(data[0], vo_mult(COEFF5_1, temp0));
+ data[0] = temp0;
- temp0 = vo_sub(*in1, vo_mult(COEFF5_2, data[1]));
- temp2 = add1(data[1], vo_mult(COEFF5_2, temp0));
- data[1] = temp0;
+ temp0 = vo_sub(*in1, vo_mult(COEFF5_2, data[1]));
+ temp2 = add1(data[1], vo_mult(COEFF5_2, temp0));
+ data[1] = temp0;
- *in0 = extract_h((vo_L_add(temp1, temp2) << 15));
- *in1 = extract_h((vo_L_sub(temp1, temp2) << 15));
+ *in0 = extract_h((vo_L_add(temp1, temp2) << 15));
+ *in1 = extract_h((vo_L_sub(temp1, temp2) << 15));
}
/******************************************************************************
@@ -107,19 +107,19 @@
*******************************************************************************/
static void filter3(
- Word16 * in0, /* i/o : input values; output low-pass part */
- Word16 * in1, /* i/o : input values; output high-pass part */
- Word16 * data /* i/o : filter memory */
- )
+ Word16 * in0, /* i/o : input values; output low-pass part */
+ Word16 * in1, /* i/o : input values; output high-pass part */
+ Word16 * data /* i/o : filter memory */
+ )
{
- Word16 temp1, temp2;
+ Word16 temp1, temp2;
- temp1 = vo_sub(*in1, vo_mult(COEFF3, *data));
- temp2 = add1(*data, vo_mult(COEFF3, temp1));
- *data = temp1;
+ temp1 = vo_sub(*in1, vo_mult(COEFF3, *data));
+ temp2 = add1(*data, vo_mult(COEFF3, temp1));
+ *data = temp1;
- *in1 = extract_h((vo_L_sub(*in0, temp2) << 15));
- *in0 = extract_h((vo_L_add(*in0, temp2) << 15));
+ *in1 = extract_h((vo_L_sub(*in0, temp2) << 15));
+ *in0 = extract_h((vo_L_add(*in0, temp2) << 15));
}
/******************************************************************************
@@ -135,36 +135,36 @@
******************************************************************************/
static Word16 level_calculation( /* return: signal level */
- Word16 data[], /* i : signal buffer */
- Word16 * sub_level, /* i : level calculated at the end of the previous frame*/
- /* o : level of signal calculated from the last */
- /* (count2 - count1) samples */
- Word16 count1, /* i : number of samples to be counted */
- Word16 count2, /* i : number of samples to be counted */
- Word16 ind_m, /* i : step size for the index of the data buffer */
- Word16 ind_a, /* i : starting index of the data buffer */
- Word16 scale /* i : scaling for the level calculation */
- )
+ Word16 data[], /* i : signal buffer */
+ Word16 * sub_level, /* i : level calculated at the end of the previous frame*/
+ /* o : level of signal calculated from the last */
+ /* (count2 - count1) samples */
+ Word16 count1, /* i : number of samples to be counted */
+ Word16 count2, /* i : number of samples to be counted */
+ Word16 ind_m, /* i : step size for the index of the data buffer */
+ Word16 ind_a, /* i : starting index of the data buffer */
+ Word16 scale /* i : scaling for the level calculation */
+ )
{
- Word32 i, l_temp1, l_temp2;
- Word16 level;
+ Word32 i, l_temp1, l_temp2;
+ Word16 level;
- l_temp1 = 0L;
- for (i = count1; i < count2; i++)
- {
- l_temp1 += (abs_s(data[ind_m * i + ind_a])<<1);
- }
+ l_temp1 = 0L;
+ for (i = count1; i < count2; i++)
+ {
+ l_temp1 += (abs_s(data[ind_m * i + ind_a])<<1);
+ }
- l_temp2 = vo_L_add(l_temp1, L_shl(*sub_level, 16 - scale));
- *sub_level = extract_h(L_shl(l_temp1, scale));
+ l_temp2 = vo_L_add(l_temp1, L_shl(*sub_level, 16 - scale));
+ *sub_level = extract_h(L_shl(l_temp1, scale));
- for (i = 0; i < count1; i++)
- {
- l_temp2 += (abs_s(data[ind_m * i + ind_a])<<1);
- }
- level = extract_h(L_shl2(l_temp2, scale));
+ for (i = 0; i < count1; i++)
+ {
+ l_temp2 += (abs_s(data[ind_m * i + ind_a])<<1);
+ }
+ level = extract_h(L_shl2(l_temp2, scale));
- return level;
+ return level;
}
/******************************************************************************
@@ -176,75 +176,75 @@
*******************************************************************************/
static void filter_bank(
- VadVars * st, /* i/o : State struct */
- Word16 in[], /* i : input frame */
- Word16 level[] /* o : signal levels at each band */
- )
+ VadVars * st, /* i/o : State struct */
+ Word16 in[], /* i : input frame */
+ Word16 level[] /* o : signal levels at each band */
+ )
{
- Word32 i;
- Word16 tmp_buf[FRAME_LEN];
+ Word32 i;
+ Word16 tmp_buf[FRAME_LEN];
- /* shift input 1 bit down for safe scaling */
- for (i = 0; i < FRAME_LEN; i++)
- {
- tmp_buf[i] = in[i] >> 1;
- }
+ /* shift input 1 bit down for safe scaling */
+ for (i = 0; i < FRAME_LEN; i++)
+ {
+ tmp_buf[i] = in[i] >> 1;
+ }
- /* run the filter bank */
- for (i = 0; i < 128; i++)
- {
- filter5(&tmp_buf[2 * i], &tmp_buf[2 * i + 1], st->a_data5[0]);
- }
- for (i = 0; i < 64; i++)
- {
- filter5(&tmp_buf[4 * i], &tmp_buf[4 * i + 2], st->a_data5[1]);
- filter5(&tmp_buf[4 * i + 1], &tmp_buf[4 * i + 3], st->a_data5[2]);
- }
- for (i = 0; i < 32; i++)
- {
- filter5(&tmp_buf[8 * i], &tmp_buf[8 * i + 4], st->a_data5[3]);
- filter5(&tmp_buf[8 * i + 2], &tmp_buf[8 * i + 6], st->a_data5[4]);
- filter3(&tmp_buf[8 * i + 3], &tmp_buf[8 * i + 7], &st->a_data3[0]);
- }
- for (i = 0; i < 16; i++)
- {
- filter3(&tmp_buf[16 * i + 0], &tmp_buf[16 * i + 8], &st->a_data3[1]);
- filter3(&tmp_buf[16 * i + 4], &tmp_buf[16 * i + 12], &st->a_data3[2]);
- filter3(&tmp_buf[16 * i + 6], &tmp_buf[16 * i + 14], &st->a_data3[3]);
- }
+ /* run the filter bank */
+ for (i = 0; i < 128; i++)
+ {
+ filter5(&tmp_buf[2 * i], &tmp_buf[2 * i + 1], st->a_data5[0]);
+ }
+ for (i = 0; i < 64; i++)
+ {
+ filter5(&tmp_buf[4 * i], &tmp_buf[4 * i + 2], st->a_data5[1]);
+ filter5(&tmp_buf[4 * i + 1], &tmp_buf[4 * i + 3], st->a_data5[2]);
+ }
+ for (i = 0; i < 32; i++)
+ {
+ filter5(&tmp_buf[8 * i], &tmp_buf[8 * i + 4], st->a_data5[3]);
+ filter5(&tmp_buf[8 * i + 2], &tmp_buf[8 * i + 6], st->a_data5[4]);
+ filter3(&tmp_buf[8 * i + 3], &tmp_buf[8 * i + 7], &st->a_data3[0]);
+ }
+ for (i = 0; i < 16; i++)
+ {
+ filter3(&tmp_buf[16 * i + 0], &tmp_buf[16 * i + 8], &st->a_data3[1]);
+ filter3(&tmp_buf[16 * i + 4], &tmp_buf[16 * i + 12], &st->a_data3[2]);
+ filter3(&tmp_buf[16 * i + 6], &tmp_buf[16 * i + 14], &st->a_data3[3]);
+ }
- for (i = 0; i < 8; i++)
- {
- filter3(&tmp_buf[32 * i + 0], &tmp_buf[32 * i + 16], &st->a_data3[4]);
- filter3(&tmp_buf[32 * i + 8], &tmp_buf[32 * i + 24], &st->a_data3[5]);
- }
+ for (i = 0; i < 8; i++)
+ {
+ filter3(&tmp_buf[32 * i + 0], &tmp_buf[32 * i + 16], &st->a_data3[4]);
+ filter3(&tmp_buf[32 * i + 8], &tmp_buf[32 * i + 24], &st->a_data3[5]);
+ }
- /* calculate levels in each frequency band */
+ /* calculate levels in each frequency band */
- /* 4800 - 6400 Hz */
- level[11] = level_calculation(tmp_buf, &st->sub_level[11], 16, 64, 4, 1, 14);
- /* 4000 - 4800 Hz */
- level[10] = level_calculation(tmp_buf, &st->sub_level[10], 8, 32, 8, 7, 15);
- /* 3200 - 4000 Hz */
- level[9] = level_calculation(tmp_buf, &st->sub_level[9],8, 32, 8, 3, 15);
- /* 2400 - 3200 Hz */
- level[8] = level_calculation(tmp_buf, &st->sub_level[8],8, 32, 8, 2, 15);
- /* 2000 - 2400 Hz */
- level[7] = level_calculation(tmp_buf, &st->sub_level[7],4, 16, 16, 14, 16);
- /* 1600 - 2000 Hz */
- level[6] = level_calculation(tmp_buf, &st->sub_level[6],4, 16, 16, 6, 16);
- /* 1200 - 1600 Hz */
- level[5] = level_calculation(tmp_buf, &st->sub_level[5],4, 16, 16, 4, 16);
- /* 800 - 1200 Hz */
- level[4] = level_calculation(tmp_buf, &st->sub_level[4],4, 16, 16, 12, 16);
- /* 600 - 800 Hz */
- level[3] = level_calculation(tmp_buf, &st->sub_level[3],2, 8, 32, 8, 17);
- /* 400 - 600 Hz */
- level[2] = level_calculation(tmp_buf, &st->sub_level[2],2, 8, 32, 24, 17);
- /* 200 - 400 Hz */
- level[1] = level_calculation(tmp_buf, &st->sub_level[1],2, 8, 32, 16, 17);
- /* 0 - 200 Hz */
- level[0] = level_calculation(tmp_buf, &st->sub_level[0],2, 8, 32, 0, 17);
+ /* 4800 - 6400 Hz */
+ level[11] = level_calculation(tmp_buf, &st->sub_level[11], 16, 64, 4, 1, 14);
+ /* 4000 - 4800 Hz */
+ level[10] = level_calculation(tmp_buf, &st->sub_level[10], 8, 32, 8, 7, 15);
+ /* 3200 - 4000 Hz */
+ level[9] = level_calculation(tmp_buf, &st->sub_level[9],8, 32, 8, 3, 15);
+ /* 2400 - 3200 Hz */
+ level[8] = level_calculation(tmp_buf, &st->sub_level[8],8, 32, 8, 2, 15);
+ /* 2000 - 2400 Hz */
+ level[7] = level_calculation(tmp_buf, &st->sub_level[7],4, 16, 16, 14, 16);
+ /* 1600 - 2000 Hz */
+ level[6] = level_calculation(tmp_buf, &st->sub_level[6],4, 16, 16, 6, 16);
+ /* 1200 - 1600 Hz */
+ level[5] = level_calculation(tmp_buf, &st->sub_level[5],4, 16, 16, 4, 16);
+ /* 800 - 1200 Hz */
+ level[4] = level_calculation(tmp_buf, &st->sub_level[4],4, 16, 16, 12, 16);
+ /* 600 - 800 Hz */
+ level[3] = level_calculation(tmp_buf, &st->sub_level[3],2, 8, 32, 8, 17);
+ /* 400 - 600 Hz */
+ level[2] = level_calculation(tmp_buf, &st->sub_level[2],2, 8, 32, 24, 17);
+ /* 200 - 400 Hz */
+ level[1] = level_calculation(tmp_buf, &st->sub_level[1],2, 8, 32, 16, 17);
+ /* 0 - 200 Hz */
+ level[0] = level_calculation(tmp_buf, &st->sub_level[0],2, 8, 32, 0, 17);
}
/******************************************************************************
@@ -255,86 +255,86 @@
*******************************************************************************/
static void update_cntrl(
- VadVars * st, /* i/o : State structure */
- Word16 level[] /* i : sub-band levels of the input frame */
- )
+ VadVars * st, /* i/o : State structure */
+ Word16 level[] /* i : sub-band levels of the input frame */
+ )
{
- Word32 i;
- Word16 num, temp, stat_rat, exp, denom;
- Word16 alpha;
+ Word32 i;
+ Word16 num, temp, stat_rat, exp, denom;
+ Word16 alpha;
- /* if a tone has been detected for a while, initialize stat_count */
- if (sub((Word16) (st->tone_flag & 0x7c00), 0x7c00) == 0)
- {
- st->stat_count = STAT_COUNT;
- } else
- {
- /* if 8 last vad-decisions have been "0", reinitialize stat_count */
- if ((st->vadreg & 0x7f80) == 0)
- {
- st->stat_count = STAT_COUNT;
- } else
- {
- stat_rat = 0;
- for (i = 0; i < COMPLEN; i++)
- {
- if(level[i] > st->ave_level[i])
- {
- num = level[i];
- denom = st->ave_level[i];
- } else
- {
- num = st->ave_level[i];
- denom = level[i];
- }
- /* Limit nimimum value of num and denom to STAT_THR_LEVEL */
- if(num < STAT_THR_LEVEL)
- {
- num = STAT_THR_LEVEL;
- }
- if(denom < STAT_THR_LEVEL)
- {
- denom = STAT_THR_LEVEL;
- }
- exp = norm_s(denom);
- denom = denom << exp;
+ /* if a tone has been detected for a while, initialize stat_count */
+ if (sub((Word16) (st->tone_flag & 0x7c00), 0x7c00) == 0)
+ {
+ st->stat_count = STAT_COUNT;
+ } else
+ {
+ /* if 8 last vad-decisions have been "0", reinitialize stat_count */
+ if ((st->vadreg & 0x7f80) == 0)
+ {
+ st->stat_count = STAT_COUNT;
+ } else
+ {
+ stat_rat = 0;
+ for (i = 0; i < COMPLEN; i++)
+ {
+ if(level[i] > st->ave_level[i])
+ {
+ num = level[i];
+ denom = st->ave_level[i];
+ } else
+ {
+ num = st->ave_level[i];
+ denom = level[i];
+ }
+ /* Limit nimimum value of num and denom to STAT_THR_LEVEL */
+ if(num < STAT_THR_LEVEL)
+ {
+ num = STAT_THR_LEVEL;
+ }
+ if(denom < STAT_THR_LEVEL)
+ {
+ denom = STAT_THR_LEVEL;
+ }
+ exp = norm_s(denom);
+ denom = denom << exp;
- /* stat_rat = num/denom * 64 */
- temp = div_s(num >> 1, denom);
- stat_rat = add1(stat_rat, shr(temp, (8 - exp)));
- }
+ /* stat_rat = num/denom * 64 */
+ temp = div_s(num >> 1, denom);
+ stat_rat = add1(stat_rat, shr(temp, (8 - exp)));
+ }
- /* compare stat_rat with a threshold and update stat_count */
- if(stat_rat > STAT_THR)
- {
- st->stat_count = STAT_COUNT;
- } else
- {
- if ((st->vadreg & 0x4000) != 0)
- {
+ /* compare stat_rat with a threshold and update stat_count */
+ if(stat_rat > STAT_THR)
+ {
+ st->stat_count = STAT_COUNT;
+ } else
+ {
+ if ((st->vadreg & 0x4000) != 0)
+ {
- if (st->stat_count != 0)
- {
- st->stat_count = st->stat_count - 1;
- }
- }
- }
- }
- }
+ if (st->stat_count != 0)
+ {
+ st->stat_count = st->stat_count - 1;
+ }
+ }
+ }
+ }
+ }
- /* Update average amplitude estimate for stationarity estimation */
- alpha = ALPHA4;
- if(st->stat_count == STAT_COUNT)
- {
- alpha = 32767;
- } else if ((st->vadreg & 0x4000) == 0)
- {
- alpha = ALPHA5;
- }
- for (i = 0; i < COMPLEN; i++)
- {
- st->ave_level[i] = add1(st->ave_level[i], vo_mult_r(alpha, vo_sub(level[i], st->ave_level[i])));
- }
+ /* Update average amplitude estimate for stationarity estimation */
+ alpha = ALPHA4;
+ if(st->stat_count == STAT_COUNT)
+ {
+ alpha = 32767;
+ } else if ((st->vadreg & 0x4000) == 0)
+ {
+ alpha = ALPHA5;
+ }
+ for (i = 0; i < COMPLEN; i++)
+ {
+ st->ave_level[i] = add1(st->ave_level[i], vo_mult_r(alpha, vo_sub(level[i], st->ave_level[i])));
+ }
}
/******************************************************************************
@@ -345,38 +345,38 @@
*******************************************************************************/
static Word16 hangover_addition( /* return: VAD_flag indicating final VAD decision */
- VadVars * st, /* i/o : State structure */
- Word16 low_power, /* i : flag power of the input frame */
- Word16 hang_len, /* i : hangover length */
- Word16 burst_len /* i : minimum burst length for hangover addition */
- )
+ VadVars * st, /* i/o : State structure */
+ Word16 low_power, /* i : flag power of the input frame */
+ Word16 hang_len, /* i : hangover length */
+ Word16 burst_len /* i : minimum burst length for hangover addition */
+ )
{
- /* if the input power (pow_sum) is lower than a threshold, clear counters and set VAD_flag to "0" */
- if (low_power != 0)
- {
- st->burst_count = 0;
- st->hang_count = 0;
- return 0;
- }
- /* update the counters (hang_count, burst_count) */
- if ((st->vadreg & 0x4000) != 0)
- {
- st->burst_count = st->burst_count + 1;
- if(st->burst_count >= burst_len)
- {
- st->hang_count = hang_len;
- }
- return 1;
- } else
- {
- st->burst_count = 0;
- if (st->hang_count > 0)
- {
- st->hang_count = st->hang_count - 1;
- return 1;
- }
- }
- return 0;
+ /* if the input power (pow_sum) is lower than a threshold, clear counters and set VAD_flag to "0" */
+ if (low_power != 0)
+ {
+ st->burst_count = 0;
+ st->hang_count = 0;
+ return 0;
+ }
+ /* update the counters (hang_count, burst_count) */
+ if ((st->vadreg & 0x4000) != 0)
+ {
+ st->burst_count = st->burst_count + 1;
+ if(st->burst_count >= burst_len)
+ {
+ st->hang_count = hang_len;
+ }
+ return 1;
+ } else
+ {
+ st->burst_count = 0;
+ if (st->hang_count > 0)
+ {
+ st->hang_count = st->hang_count - 1;
+ return 1;
+ }
+ }
+ return 0;
}
/******************************************************************************
@@ -387,66 +387,66 @@
*******************************************************************************/
static void noise_estimate_update(
- VadVars * st, /* i/o : State structure */
- Word16 level[] /* i : sub-band levels of the input frame */
- )
+ VadVars * st, /* i/o : State structure */
+ Word16 level[] /* i : sub-band levels of the input frame */
+ )
{
- Word32 i;
- Word16 alpha_up, alpha_down, bckr_add = 2;
+ Word32 i;
+ Word16 alpha_up, alpha_down, bckr_add = 2;
- /* Control update of bckr_est[] */
- update_cntrl(st, level);
+ /* Control update of bckr_est[] */
+ update_cntrl(st, level);
- /* Choose update speed */
- if ((0x7800 & st->vadreg) == 0)
- {
- alpha_up = ALPHA_UP1;
- alpha_down = ALPHA_DOWN1;
- } else
- {
- if (st->stat_count == 0)
- {
- alpha_up = ALPHA_UP2;
- alpha_down = ALPHA_DOWN2;
- } else
- {
- alpha_up = 0;
- alpha_down = ALPHA3;
- bckr_add = 0;
- }
- }
+ /* Choose update speed */
+ if ((0x7800 & st->vadreg) == 0)
+ {
+ alpha_up = ALPHA_UP1;
+ alpha_down = ALPHA_DOWN1;
+ } else
+ {
+ if (st->stat_count == 0)
+ {
+ alpha_up = ALPHA_UP2;
+ alpha_down = ALPHA_DOWN2;
+ } else
+ {
+ alpha_up = 0;
+ alpha_down = ALPHA3;
+ bckr_add = 0;
+ }
+ }
- /* Update noise estimate (bckr_est) */
- for (i = 0; i < COMPLEN; i++)
- {
- Word16 temp;
- temp = (st->old_level[i] - st->bckr_est[i]);
+ /* Update noise estimate (bckr_est) */
+ for (i = 0; i < COMPLEN; i++)
+ {
+ Word16 temp;
+ temp = (st->old_level[i] - st->bckr_est[i]);
- if (temp < 0)
- { /* update downwards */
- st->bckr_est[i] = add1(-2, add(st->bckr_est[i],vo_mult_r(alpha_down, temp)));
- /* limit minimum value of the noise estimate to NOISE_MIN */
- if(st->bckr_est[i] < NOISE_MIN)
- {
- st->bckr_est[i] = NOISE_MIN;
- }
- } else
- { /* update upwards */
- st->bckr_est[i] = add1(bckr_add, add1(st->bckr_est[i],vo_mult_r(alpha_up, temp)));
+ if (temp < 0)
+ { /* update downwards */
+ st->bckr_est[i] = add1(-2, add(st->bckr_est[i],vo_mult_r(alpha_down, temp)));
+ /* limit minimum value of the noise estimate to NOISE_MIN */
+ if(st->bckr_est[i] < NOISE_MIN)
+ {
+ st->bckr_est[i] = NOISE_MIN;
+ }
+ } else
+ { /* update upwards */
+ st->bckr_est[i] = add1(bckr_add, add1(st->bckr_est[i],vo_mult_r(alpha_up, temp)));
- /* limit maximum value of the noise estimate to NOISE_MAX */
- if(st->bckr_est[i] > NOISE_MAX)
- {
- st->bckr_est[i] = NOISE_MAX;
- }
- }
- }
+ /* limit maximum value of the noise estimate to NOISE_MAX */
+ if(st->bckr_est[i] > NOISE_MAX)
+ {
+ st->bckr_est[i] = NOISE_MAX;
+ }
+ }
+ }
- /* Update signal levels of the previous frame (old_level) */
- for (i = 0; i < COMPLEN; i++)
- {
- st->old_level[i] = level[i];
- }
+ /* Update signal levels of the previous frame (old_level) */
+ for (i = 0; i < COMPLEN; i++)
+ {
+ st->old_level[i] = level[i];
+ }
}
/******************************************************************************
@@ -457,100 +457,100 @@
*******************************************************************************/
static Word16 vad_decision( /* return value : VAD_flag */
- VadVars * st, /* i/o : State structure */
- Word16 level[COMPLEN], /* i : sub-band levels of the input frame */
- Word32 pow_sum /* i : power of the input frame */
- )
+ VadVars * st, /* i/o : State structure */
+ Word16 level[COMPLEN], /* i : sub-band levels of the input frame */
+ Word32 pow_sum /* i : power of the input frame */
+ )
{
- Word32 i;
- Word32 L_snr_sum;
- Word32 L_temp;
- Word16 vad_thr, temp, noise_level;
- Word16 low_power_flag;
- Word16 hang_len, burst_len;
- Word16 ilog2_speech_level, ilog2_noise_level;
- Word16 temp2;
+ Word32 i;
+ Word32 L_snr_sum;
+ Word32 L_temp;
+ Word16 vad_thr, temp, noise_level;
+ Word16 low_power_flag;
+ Word16 hang_len, burst_len;
+ Word16 ilog2_speech_level, ilog2_noise_level;
+ Word16 temp2;
- /* Calculate squared sum of the input levels (level) divided by the background noise components
- * (bckr_est). */
- L_snr_sum = 0;
- for (i = 0; i < COMPLEN; i++)
- {
- Word16 exp;
+ /* Calculate squared sum of the input levels (level) divided by the background noise components
+ * (bckr_est). */
+ L_snr_sum = 0;
+ for (i = 0; i < COMPLEN; i++)
+ {
+ Word16 exp;
- exp = norm_s(st->bckr_est[i]);
- temp = (st->bckr_est[i] << exp);
- temp = div_s((level[i] >> 1), temp);
- temp = shl(temp, (exp - (UNIRSHFT - 1)));
- L_snr_sum = L_mac(L_snr_sum, temp, temp);
- }
+ exp = norm_s(st->bckr_est[i]);
+ temp = (st->bckr_est[i] << exp);
+ temp = div_s((level[i] >> 1), temp);
+ temp = shl(temp, (exp - (UNIRSHFT - 1)));
+ L_snr_sum = L_mac(L_snr_sum, temp, temp);
+ }
- /* Calculate average level of estimated background noise */
- L_temp = 0;
- for (i = 1; i < COMPLEN; i++) /* ignore lowest band */
- {
- L_temp = vo_L_add(L_temp, st->bckr_est[i]);
- }
+ /* Calculate average level of estimated background noise */
+ L_temp = 0;
+ for (i = 1; i < COMPLEN; i++) /* ignore lowest band */
+ {
+ L_temp = vo_L_add(L_temp, st->bckr_est[i]);
+ }
- noise_level = extract_h((L_temp << 12));
- /* if SNR is lower than a threshold (MIN_SPEECH_SNR), and increase speech_level */
- temp = vo_mult(noise_level, MIN_SPEECH_SNR) << 3;
+ noise_level = extract_h((L_temp << 12));
+ /* if SNR is lower than a threshold (MIN_SPEECH_SNR), and increase speech_level */
+ temp = vo_mult(noise_level, MIN_SPEECH_SNR) << 3;
- if(st->speech_level < temp)
- {
- st->speech_level = temp;
- }
- ilog2_noise_level = ilog2(noise_level);
+ if(st->speech_level < temp)
+ {
+ st->speech_level = temp;
+ }
+ ilog2_noise_level = ilog2(noise_level);
- /* If SNR is very poor, speech_level is probably corrupted by noise level. This is correctred by
- * subtracting MIN_SPEECH_SNR*noise_level from speech level */
- ilog2_speech_level = ilog2(st->speech_level - temp);
+ /* If SNR is very poor, speech_level is probably corrupted by noise level. This is correctred by
+ * subtracting MIN_SPEECH_SNR*noise_level from speech level */
+ ilog2_speech_level = ilog2(st->speech_level - temp);
- temp = add1(vo_mult(NO_SLOPE, (ilog2_noise_level - NO_P1)), THR_HIGH);
+ temp = add1(vo_mult(NO_SLOPE, (ilog2_noise_level - NO_P1)), THR_HIGH);
- temp2 = add1(SP_CH_MIN, vo_mult(SP_SLOPE, (ilog2_speech_level - SP_P1)));
- if (temp2 < SP_CH_MIN)
- {
- temp2 = SP_CH_MIN;
- }
- if (temp2 > SP_CH_MAX)
- {
- temp2 = SP_CH_MAX;
- }
- vad_thr = temp + temp2;
+ temp2 = add1(SP_CH_MIN, vo_mult(SP_SLOPE, (ilog2_speech_level - SP_P1)));
+ if (temp2 < SP_CH_MIN)
+ {
+ temp2 = SP_CH_MIN;
+ }
+ if (temp2 > SP_CH_MAX)
+ {
+ temp2 = SP_CH_MAX;
+ }
+ vad_thr = temp + temp2;
- if(vad_thr < THR_MIN)
- {
- vad_thr = THR_MIN;
- }
- /* Shift VAD decision register */
- st->vadreg = (st->vadreg >> 1);
+ if(vad_thr < THR_MIN)
+ {
+ vad_thr = THR_MIN;
+ }
+ /* Shift VAD decision register */
+ st->vadreg = (st->vadreg >> 1);
- /* Make intermediate VAD decision */
- if(L_snr_sum > vo_L_mult(vad_thr, (512 * COMPLEN)))
- {
- st->vadreg = (Word16) (st->vadreg | 0x4000);
- }
- /* check if the input power (pow_sum) is lower than a threshold" */
- if(pow_sum < VAD_POW_LOW)
- {
- low_power_flag = 1;
- } else
- {
- low_power_flag = 0;
- }
- /* Update background noise estimates */
- noise_estimate_update(st, level);
+ /* Make intermediate VAD decision */
+ if(L_snr_sum > vo_L_mult(vad_thr, (512 * COMPLEN)))
+ {
+ st->vadreg = (Word16) (st->vadreg | 0x4000);
+ }
+ /* check if the input power (pow_sum) is lower than a threshold" */
+ if(pow_sum < VAD_POW_LOW)
+ {
+ low_power_flag = 1;
+ } else
+ {
+ low_power_flag = 0;
+ }
+ /* Update background noise estimates */
+ noise_estimate_update(st, level);
- /* Calculate values for hang_len and burst_len based on vad_thr */
- hang_len = add1(vo_mult(HANG_SLOPE, (vad_thr - HANG_P1)), HANG_HIGH);
- if(hang_len < HANG_LOW)
- {
- hang_len = HANG_LOW;
- }
- burst_len = add1(vo_mult(BURST_SLOPE, (vad_thr - BURST_P1)), BURST_HIGH);
+ /* Calculate values for hang_len and burst_len based on vad_thr */
+ hang_len = add1(vo_mult(HANG_SLOPE, (vad_thr - HANG_P1)), HANG_HIGH);
+ if(hang_len < HANG_LOW)
+ {
+ hang_len = HANG_LOW;
+ }
+ burst_len = add1(vo_mult(BURST_SLOPE, (vad_thr - BURST_P1)), BURST_HIGH);
- return (hangover_addition(st, low_power_flag, hang_len, burst_len));
+ return (hangover_addition(st, low_power_flag, hang_len, burst_len));
}
/******************************************************************************
@@ -566,54 +566,54 @@
*******************************************************************************/
static void Estimate_Speech(
- VadVars * st, /* i/o : State structure */
- Word16 in_level /* level of the input frame */
- )
+ VadVars * st, /* i/o : State structure */
+ Word16 in_level /* level of the input frame */
+ )
{
- Word16 alpha;
+ Word16 alpha;
- /* if the required activity count cannot be achieved, reset counters */
- if((st->sp_est_cnt - st->sp_max_cnt) > (SP_EST_COUNT - SP_ACTIVITY_COUNT))
- {
- st->sp_est_cnt = 0;
- st->sp_max = 0;
- st->sp_max_cnt = 0;
- }
- st->sp_est_cnt += 1;
+ /* if the required activity count cannot be achieved, reset counters */
+ if((st->sp_est_cnt - st->sp_max_cnt) > (SP_EST_COUNT - SP_ACTIVITY_COUNT))
+ {
+ st->sp_est_cnt = 0;
+ st->sp_max = 0;
+ st->sp_max_cnt = 0;
+ }
+ st->sp_est_cnt += 1;
- if (((st->vadreg & 0x4000)||(in_level > st->speech_level)) && (in_level > MIN_SPEECH_LEVEL1))
- {
- /* update sp_max */
- if(in_level > st->sp_max)
- {
- st->sp_max = in_level;
- }
- st->sp_max_cnt += 1;
+ if (((st->vadreg & 0x4000)||(in_level > st->speech_level)) && (in_level > MIN_SPEECH_LEVEL1))
+ {
+ /* update sp_max */
+ if(in_level > st->sp_max)
+ {
+ st->sp_max = in_level;
+ }
+ st->sp_max_cnt += 1;
- if(st->sp_max_cnt >= SP_ACTIVITY_COUNT)
- {
- Word16 tmp;
- /* update speech estimate */
- tmp = (st->sp_max >> 1); /* scale to get "average" speech level */
+ if(st->sp_max_cnt >= SP_ACTIVITY_COUNT)
+ {
+ Word16 tmp;
+ /* update speech estimate */
+ tmp = (st->sp_max >> 1); /* scale to get "average" speech level */
- /* select update speed */
- if(tmp > st->speech_level)
- {
- alpha = ALPHA_SP_UP;
- } else
- {
- alpha = ALPHA_SP_DOWN;
- }
- if(tmp > MIN_SPEECH_LEVEL2)
- {
- st->speech_level = add1(st->speech_level, vo_mult_r(alpha, vo_sub(tmp, st->speech_level)));
- }
- /* clear all counters used for speech estimation */
- st->sp_max = 0;
- st->sp_max_cnt = 0;
- st->sp_est_cnt = 0;
- }
- }
+ /* select update speed */
+ if(tmp > st->speech_level)
+ {
+ alpha = ALPHA_SP_UP;
+ } else
+ {
+ alpha = ALPHA_SP_DOWN;
+ }
+ if(tmp > MIN_SPEECH_LEVEL2)
+ {
+ st->speech_level = add1(st->speech_level, vo_mult_r(alpha, vo_sub(tmp, st->speech_level)));
+ }
+ /* clear all counters used for speech estimation */
+ st->sp_max = 0;
+ st->sp_max_cnt = 0;
+ st->sp_est_cnt = 0;
+ }
+ }
}
/******************************************************************************
@@ -624,30 +624,30 @@
*******************************************************************************/
Word16 wb_vad_init( /* return: non-zero with error, zero for ok. */
- VadVars ** state, /* i/o : State structure */
- VO_MEM_OPERATOR *pMemOP
- )
+ VadVars ** state, /* i/o : State structure */
+ VO_MEM_OPERATOR *pMemOP
+ )
{
- VadVars *s;
+ VadVars *s;
- if (state == (VadVars **) NULL)
- {
- fprintf(stderr, "vad_init: invalid parameter\n");
- return -1;
- }
- *state = NULL;
+ if (state == (VadVars **) NULL)
+ {
+ fprintf(stderr, "vad_init: invalid parameter\n");
+ return -1;
+ }
+ *state = NULL;
- /* allocate memory */
- if ((s = (VadVars *) mem_malloc(pMemOP, sizeof(VadVars), 32, VO_INDEX_ENC_AMRWB)) == NULL)
- {
- fprintf(stderr, "vad_init: can not malloc state structure\n");
- return -1;
- }
- wb_vad_reset(s);
+ /* allocate memory */
+ if ((s = (VadVars *) mem_malloc(pMemOP, sizeof(VadVars), 32, VO_INDEX_ENC_AMRWB)) == NULL)
+ {
+ fprintf(stderr, "vad_init: can not malloc state structure\n");
+ return -1;
+ }
+ wb_vad_reset(s);
- *state = s;
+ *state = s;
- return 0;
+ return 0;
}
/******************************************************************************
@@ -658,51 +658,51 @@
*******************************************************************************/
Word16 wb_vad_reset( /* return: non-zero with error, zero for ok. */
- VadVars * state /* i/o : State structure */
- )
+ VadVars * state /* i/o : State structure */
+ )
{
- Word32 i, j;
+ Word32 i, j;
- if (state == (VadVars *) NULL)
- {
- fprintf(stderr, "vad_reset: invalid parameter\n");
- return -1;
- }
- state->tone_flag = 0;
- state->vadreg = 0;
- state->hang_count = 0;
- state->burst_count = 0;
- state->hang_count = 0;
+ if (state == (VadVars *) NULL)
+ {
+ fprintf(stderr, "vad_reset: invalid parameter\n");
+ return -1;
+ }
+ state->tone_flag = 0;
+ state->vadreg = 0;
+ state->hang_count = 0;
+ state->burst_count = 0;
+ state->hang_count = 0;
- /* initialize memory used by the filter bank */
- for (i = 0; i < F_5TH_CNT; i++)
- {
- for (j = 0; j < 2; j++)
- {
- state->a_data5[i][j] = 0;
- }
- }
+ /* initialize memory used by the filter bank */
+ for (i = 0; i < F_5TH_CNT; i++)
+ {
+ for (j = 0; j < 2; j++)
+ {
+ state->a_data5[i][j] = 0;
+ }
+ }
- for (i = 0; i < F_3TH_CNT; i++)
- {
- state->a_data3[i] = 0;
- }
+ for (i = 0; i < F_3TH_CNT; i++)
+ {
+ state->a_data3[i] = 0;
+ }
- /* initialize the rest of the memory */
- for (i = 0; i < COMPLEN; i++)
- {
- state->bckr_est[i] = NOISE_INIT;
- state->old_level[i] = NOISE_INIT;
- state->ave_level[i] = NOISE_INIT;
- state->sub_level[i] = 0;
- }
+ /* initialize the rest of the memory */
+ for (i = 0; i < COMPLEN; i++)
+ {
+ state->bckr_est[i] = NOISE_INIT;
+ state->old_level[i] = NOISE_INIT;
+ state->ave_level[i] = NOISE_INIT;
+ state->sub_level[i] = 0;
+ }
- state->sp_est_cnt = 0;
- state->sp_max = 0;
- state->sp_max_cnt = 0;
- state->speech_level = SPEECH_LEVEL_INIT;
- state->prev_pow_sum = 0;
- return 0;
+ state->sp_est_cnt = 0;
+ state->sp_max = 0;
+ state->sp_max_cnt = 0;
+ state->speech_level = SPEECH_LEVEL_INIT;
+ state->prev_pow_sum = 0;
+ return 0;
}
/******************************************************************************
@@ -713,16 +713,16 @@
*******************************************************************************/
void wb_vad_exit(
- VadVars ** state, /* i/o : State structure */
- VO_MEM_OPERATOR *pMemOP
- )
+ VadVars ** state, /* i/o : State structure */
+ VO_MEM_OPERATOR *pMemOP
+ )
{
- if (state == NULL || *state == NULL)
- return;
- /* deallocate memory */
- mem_free(pMemOP, *state, VO_INDEX_ENC_AMRWB);
- *state = NULL;
- return;
+ if (state == NULL || *state == NULL)
+ return;
+ /* deallocate memory */
+ mem_free(pMemOP, *state, VO_INDEX_ENC_AMRWB);
+ *state = NULL;
+ return;
}
/******************************************************************************
@@ -735,18 +735,18 @@
*******************************************************************************/
void wb_vad_tone_detection(
- VadVars * st, /* i/o : State struct */
- Word16 p_gain /* pitch gain */
- )
+ VadVars * st, /* i/o : State struct */
+ Word16 p_gain /* pitch gain */
+ )
{
- /* update tone flag */
- st->tone_flag = (st->tone_flag >> 1);
+ /* update tone flag */
+ st->tone_flag = (st->tone_flag >> 1);
- /* if (pitch_gain > TONE_THR) set tone flag */
- if (p_gain > TONE_THR)
- {
- st->tone_flag = (Word16) (st->tone_flag | 0x4000);
- }
+ /* if (pitch_gain > TONE_THR) set tone flag */
+ if (p_gain > TONE_THR)
+ {
+ st->tone_flag = (Word16) (st->tone_flag | 0x4000);
+ }
}
/******************************************************************************
@@ -757,50 +757,50 @@
*******************************************************************************/
Word16 wb_vad( /* Return value : VAD Decision, 1 = speech, 0 = noise */
- VadVars * st, /* i/o : State structure */
- Word16 in_buf[] /* i : samples of the input frame */
- )
+ VadVars * st, /* i/o : State structure */
+ Word16 in_buf[] /* i : samples of the input frame */
+ )
{
- Word16 level[COMPLEN];
- Word32 i;
- Word16 VAD_flag, temp;
- Word32 L_temp, pow_sum;
+ Word16 level[COMPLEN];
+ Word32 i;
+ Word16 VAD_flag, temp;
+ Word32 L_temp, pow_sum;
- /* Calculate power of the input frame. */
- L_temp = 0L;
- for (i = 0; i < FRAME_LEN; i++)
- {
- L_temp = L_mac(L_temp, in_buf[i], in_buf[i]);
- }
+ /* Calculate power of the input frame. */
+ L_temp = 0L;
+ for (i = 0; i < FRAME_LEN; i++)
+ {
+ L_temp = L_mac(L_temp, in_buf[i], in_buf[i]);
+ }
- /* pow_sum = power of current frame and previous frame */
- pow_sum = L_add(L_temp, st->prev_pow_sum);
+ /* pow_sum = power of current frame and previous frame */
+ pow_sum = L_add(L_temp, st->prev_pow_sum);
- /* save power of current frame for next call */
- st->prev_pow_sum = L_temp;
+ /* save power of current frame for next call */
+ st->prev_pow_sum = L_temp;
- /* If input power is very low, clear tone flag */
- if (pow_sum < POW_TONE_THR)
- {
- st->tone_flag = (Word16) (st->tone_flag & 0x1fff);
- }
- /* Run the filter bank and calculate signal levels at each band */
- filter_bank(st, in_buf, level);
+ /* If input power is very low, clear tone flag */
+ if (pow_sum < POW_TONE_THR)
+ {
+ st->tone_flag = (Word16) (st->tone_flag & 0x1fff);
+ }
+ /* Run the filter bank and calculate signal levels at each band */
+ filter_bank(st, in_buf, level);
- /* compute VAD decision */
- VAD_flag = vad_decision(st, level, pow_sum);
+ /* compute VAD decision */
+ VAD_flag = vad_decision(st, level, pow_sum);
- /* Calculate input level */
- L_temp = 0;
- for (i = 1; i < COMPLEN; i++) /* ignore lowest band */
- {
- L_temp = vo_L_add(L_temp, level[i]);
- }
+ /* Calculate input level */
+ L_temp = 0;
+ for (i = 1; i < COMPLEN; i++) /* ignore lowest band */
+ {
+ L_temp = vo_L_add(L_temp, level[i]);
+ }
- temp = extract_h(L_temp << 12);
+ temp = extract_h(L_temp << 12);
- Estimate_Speech(st, temp); /* Estimate speech level */
- return (VAD_flag);
+ Estimate_Speech(st, temp); /* Estimate speech level */
+ return (VAD_flag);
}
diff --git a/media/libstagefright/codecs/amrwbenc/src/weight_a.c b/media/libstagefright/codecs/amrwbenc/src/weight_a.c
index a02b48d..23b774e 100644
--- a/media/libstagefright/codecs/amrwbenc/src/weight_a.c
+++ b/media/libstagefright/codecs/amrwbenc/src/weight_a.c
@@ -18,7 +18,7 @@
* File: weight_a.c *
* *
* Description:Weighting of LPC coefficients *
-* ap[i] = a[i] * (gamma ** i) *
+* ap[i] = a[i] * (gamma ** i) *
* *
************************************************************************/
@@ -26,22 +26,22 @@
#include "basic_op.h"
void Weight_a(
- Word16 a[], /* (i) Q12 : a[m+1] LPC coefficients */
- Word16 ap[], /* (o) Q12 : Spectral expanded LPC coefficients */
- Word16 gamma, /* (i) Q15 : Spectral expansion factor. */
- Word16 m /* (i) : LPC order. */
- )
+ Word16 a[], /* (i) Q12 : a[m+1] LPC coefficients */
+ Word16 ap[], /* (o) Q12 : Spectral expanded LPC coefficients */
+ Word16 gamma, /* (i) Q15 : Spectral expansion factor. */
+ Word16 m /* (i) : LPC order. */
+ )
{
- Word32 num = m - 1, fac;
- *ap++ = *a++;
- fac = gamma;
- do{
- *ap++ =(Word16)(((vo_L_mult((*a++), fac)) + 0x8000) >> 16);
- fac = (vo_L_mult(fac, gamma) + 0x8000) >> 16;
- }while(--num != 0);
+ Word32 num = m - 1, fac;
+ *ap++ = *a++;
+ fac = gamma;
+ do{
+ *ap++ =(Word16)(((vo_L_mult((*a++), fac)) + 0x8000) >> 16);
+ fac = (vo_L_mult(fac, gamma) + 0x8000) >> 16;
+ }while(--num != 0);
- *ap++ = (Word16)(((vo_L_mult((*a++), fac)) + 0x8000) >> 16);
- return;
+ *ap++ = (Word16)(((vo_L_mult((*a++), fac)) + 0x8000) >> 16);
+ return;
}
diff --git a/media/libstagefright/codecs/avc/common/Android.mk b/media/libstagefright/codecs/avc/common/Android.mk
index 844ef0a..ed0f8ca 100644
--- a/media/libstagefright/codecs/avc/common/Android.mk
+++ b/media/libstagefright/codecs/avc/common/Android.mk
@@ -17,5 +17,7 @@
$(LOCAL_PATH)/include
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk
index 2ceebc8..8ff2f35 100644
--- a/media/libstagefright/codecs/avc/enc/Android.mk
+++ b/media/libstagefright/codecs/avc/enc/Android.mk
@@ -31,6 +31,8 @@
-DOSCL_IMPORT_REF= -D"OSCL_UNUSED_ARG(x)=(void)(x)" -DOSCL_EXPORT_REF=
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_STATIC_LIBRARY)
@@ -72,5 +74,37 @@
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_SHARED_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ test/h264_enc_test.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../common/include \
+ $(LOCAL_PATH)/../common
+
+LOCAL_CFLAGS := \
+ -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_avcenc
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright_avc_common
+
+LOCAL_MODULE := libstagefright_h264enc_test
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp b/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp
index 0b8d9e2..d0bbee2 100644
--- a/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp
+++ b/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp
@@ -23,19 +23,6 @@
#define PREF_16_VEC 129 /* 1MV bias versus 4MVs*/
-const static int distance_tab[9][9] = /* [hp_guess][k] */
-{
- {0, 1, 1, 1, 1, 1, 1, 1, 1},
- {1, 0, 1, 2, 3, 4, 3, 2, 1},
- {1, 0, 0, 0, 1, 2, 3, 2, 1},
- {1, 2, 1, 0, 1, 2, 3, 4, 3},
- {1, 2, 1, 0, 0, 0, 1, 2, 3},
- {1, 4, 3, 2, 1, 0, 1, 2, 3},
- {1, 2, 3, 2, 1, 0, 0, 0, 1},
- {1, 2, 3, 4, 3, 2, 1, 0, 1},
- {1, 0, 1, 2, 3, 2, 1, 0, 0}
-};
-
#define CLIP_RESULT(x) if((uint)x > 0xFF){ \
x = 0xFF & (~(x>>31));}
diff --git a/media/libstagefright/codecs/avc/enc/test/h264_enc_test.cpp b/media/libstagefright/codecs/avc/enc/test/h264_enc_test.cpp
new file mode 100644
index 0000000..7a782a8
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/test/h264_enc_test.cpp
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "avcenc_api.h"
+#include "avcenc_int.h"
+
+// Constants.
+enum {
+ kMaxWidth = 720,
+ kMaxHeight = 480,
+ kMaxFrameRate = 30,
+ kMaxBitrate = 2048, // in kbps.
+ kInputBufferSize = (kMaxWidth * kMaxHeight * 3) / 2, // For YUV 420 format.
+ kOutputBufferSize = kInputBufferSize,
+ kMaxDpbBuffers = 17,
+ kIDRFrameRefreshIntervalInSec = 1,
+};
+
+
+static void *MallocCb(void * /*userData*/, int32_t size, int32_t /*attrs*/) {
+ void *ptr = calloc(size, 1);
+ return ptr;
+}
+
+static void FreeCb(void * /*userData*/, void *ptr) {
+ free(ptr);
+}
+
+static int32_t DpbAllocCb(void * /*userData*/,
+ unsigned int sizeInMbs, unsigned int numBuffers) {
+
+ size_t frameSize = (sizeInMbs << 7) * 3;
+ if(numBuffers < kMaxDpbBuffers && frameSize <= kInputBufferSize) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int32_t BindFrameCb(void *userData, int32_t index, uint8_t **yuv) {
+ assert(index < kMaxDpbBuffers);
+ uint8_t** dpbBuffer = static_cast<uint8_t**>(userData);
+ *yuv = dpbBuffer[index];
+ return 1;
+}
+
+static void UnbindFrameCb(void * /*userData*/, int32_t /*index*/) {
+}
+
+int main(int argc, char *argv[]) {
+
+ if (argc < 7) {
+ fprintf(stderr, "Usage %s <input yuv> <output file> <width> <height>"
+ " <frame rate> <bitrate in kbps>\n", argv[0]);
+ fprintf(stderr, "Max width %d\n", kMaxWidth);
+ fprintf(stderr, "Max height %d\n", kMaxHeight);
+ fprintf(stderr, "Max framerate %d\n", kMaxFrameRate);
+ fprintf(stderr, "Max bitrate %d kbps\n", kMaxBitrate);
+ return EXIT_FAILURE;
+ }
+
+ // Read height and width.
+ int32_t width;
+ int32_t height;
+ width = atoi(argv[3]);
+ height = atoi(argv[4]);
+ if (width > kMaxWidth || height > kMaxHeight || width <= 0 || height <= 0) {
+ fprintf(stderr, "Unsupported dimensions %dx%d\n", width, height);
+ return EXIT_FAILURE;
+ }
+
+ if (width % 16 != 0 || height % 16 != 0) {
+ fprintf(stderr, "Video frame size %dx%d must be a multiple of 16\n",
+ width, height);
+ return EXIT_FAILURE;
+ }
+
+ // Read frame rate.
+ int32_t frameRate;
+ frameRate = atoi(argv[5]);
+ if (frameRate > kMaxFrameRate || frameRate <= 0) {
+ fprintf(stderr, "Unsupported frame rate %d\n", frameRate);
+ return EXIT_FAILURE;
+ }
+
+ // Read bit rate.
+ int32_t bitrate;
+ bitrate = atoi(argv[6]);
+ if (bitrate > kMaxBitrate || bitrate <= 0) {
+ fprintf(stderr, "Unsupported bitrate %d\n", bitrate);
+ return EXIT_FAILURE;
+ }
+ bitrate *= 1024; // kbps to bps.
+
+ // Open the input file.
+ FILE *fpInput = fopen(argv[1], "rb");
+ if (!fpInput) {
+ fprintf(stderr, "Could not open %s\n", argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ // Open the output file.
+ FILE *fpOutput = fopen(argv[2], "wb");
+ if (!fpOutput) {
+ fprintf(stderr, "Could not open %s\n", argv[2]);
+ fclose(fpInput);
+ return EXIT_FAILURE;
+ }
+
+ // Allocate input buffer.
+ uint8_t *inputBuf = (uint8_t *)malloc(kInputBufferSize);
+ assert(inputBuf != NULL);
+
+ // Allocate output buffer.
+ uint8_t *outputBuf = (uint8_t *)malloc(kOutputBufferSize);
+ assert(outputBuf != NULL);
+
+ // Allocate dpb buffers.
+ uint8_t * dpbBuffers[kMaxDpbBuffers];
+ for (int i = 0; i < kMaxDpbBuffers; ++i) {
+ dpbBuffers[i] = (uint8_t *)malloc(kInputBufferSize);
+ assert(dpbBuffers[i] != NULL);
+ }
+
+ // Initialize the encoder parameters.
+ tagAVCEncParam encParams;
+ memset(&encParams, 0, sizeof(tagAVCEncParam));
+ encParams.rate_control = AVC_ON;
+ encParams.initQP = 0;
+ encParams.init_CBP_removal_delay = 1600;
+
+ encParams.intramb_refresh = 0;
+ encParams.auto_scd = AVC_ON;
+ encParams.out_of_band_param_set = AVC_ON;
+ encParams.poc_type = 2;
+ encParams.log2_max_poc_lsb_minus_4 = 12;
+ encParams.delta_poc_zero_flag = 0;
+ encParams.offset_poc_non_ref = 0;
+ encParams.offset_top_bottom = 0;
+ encParams.num_ref_in_cycle = 0;
+ encParams.offset_poc_ref = NULL;
+
+ encParams.num_ref_frame = 1;
+ encParams.num_slice_group = 1;
+ encParams.fmo_type = 0;
+
+ encParams.db_filter = AVC_ON;
+ encParams.disable_db_idc = 0;
+
+ encParams.alpha_offset = 0;
+ encParams.beta_offset = 0;
+ encParams.constrained_intra_pred = AVC_OFF;
+
+ encParams.data_par = AVC_OFF;
+ encParams.fullsearch = AVC_OFF;
+ encParams.search_range = 16;
+ encParams.sub_pel = AVC_OFF;
+ encParams.submb_pred = AVC_OFF;
+ encParams.rdopt_mode = AVC_OFF;
+ encParams.bidir_pred = AVC_OFF;
+
+ encParams.use_overrun_buffer = AVC_OFF;
+
+ encParams.width = width;
+ encParams.height = height;
+ encParams.bitrate = bitrate;
+ encParams.frame_rate = 1000 * frameRate; // In frames/ms.
+ encParams.CPB_size = (uint32_t) (bitrate >> 1);
+
+ int32_t IDRFrameRefreshIntervalInSec = kIDRFrameRefreshIntervalInSec;
+ if (IDRFrameRefreshIntervalInSec == 0) {
+ encParams.idr_period = 1; // All I frames.
+ } else {
+ encParams.idr_period = (IDRFrameRefreshIntervalInSec * frameRate);
+ }
+
+ int32_t nMacroBlocks = ((((width + 15) >> 4) << 4) *
+ (((height + 15) >> 4) << 4)) >> 8;
+ uint32_t *sliceGroup = (uint32_t *) malloc(sizeof(uint32_t) * nMacroBlocks);
+ assert(sliceGroup != NULL);
+ for (int i = 0, idx = 0; i < nMacroBlocks; ++i) {
+ sliceGroup[i] = idx++;
+ if (idx >= encParams.num_slice_group) {
+ idx = 0;
+ }
+ }
+ encParams.slice_group = sliceGroup;
+ encParams.profile = AVC_BASELINE;
+ encParams.level = AVC_LEVEL2;
+
+ // Initialize the handle.
+ tagAVCHandle handle;
+ memset(&handle, 0, sizeof(tagAVCHandle));
+ handle.AVCObject = NULL;
+ handle.userData = dpbBuffers;
+ handle.CBAVC_DPBAlloc = DpbAllocCb;
+ handle.CBAVC_FrameBind = BindFrameCb;
+ handle.CBAVC_FrameUnbind = UnbindFrameCb;
+ handle.CBAVC_Malloc = MallocCb;
+ handle.CBAVC_Free = FreeCb;
+
+ // Initialize the encoder.
+ AVCEnc_Status status;
+ status = PVAVCEncInitialize(&handle, &encParams, NULL, NULL);
+ if (status != AVCENC_SUCCESS) {
+ fprintf(stderr, "Failed to initialize the encoder\n");
+
+ // Release resources.
+ fclose(fpInput);
+ fclose(fpOutput);
+ free(sliceGroup);
+ free(inputBuf);
+ free(outputBuf);
+ for (int i = 0; i < kMaxDpbBuffers; ++i) {
+ free(dpbBuffers[i]);
+ }
+ return EXIT_FAILURE;
+ }
+
+ // Encode Sequence Parameter Set.
+ uint32_t dataLength = kOutputBufferSize;
+ int32_t type;
+ status = PVAVCEncodeNAL(&handle, outputBuf, &dataLength, &type);
+ assert(type == AVC_NALTYPE_SPS);
+ fwrite("\x00\x00\x00\x01", 1, 4, fpOutput); // Start Code.
+ fwrite(outputBuf, 1, dataLength, fpOutput); // SPS.
+
+ // Encode Picture Paramater Set.
+ dataLength = kOutputBufferSize;
+ status = PVAVCEncodeNAL(&handle, outputBuf, &dataLength, &type);
+ assert(type == AVC_NALTYPE_PPS);
+ fwrite("\x00\x00\x00\x01", 1, 4, fpOutput); // Start Code.
+ fwrite(outputBuf, 1, dataLength, fpOutput); // PPS.
+
+ // Core loop.
+ int32_t retVal = EXIT_SUCCESS;
+ int32_t frameSize = (width * height * 3) / 2;
+ int32_t numInputFrames = 0;
+ int32_t numNalEncoded = 0;
+ bool readyForNextFrame = true;
+
+ while (1) {
+ if (readyForNextFrame == true) {
+ // Read the input frame.
+ int32_t bytesRead;
+ bytesRead = fread(inputBuf, 1, frameSize, fpInput);
+ if (bytesRead != frameSize) {
+ break; // End of file.
+ }
+
+ // Set the input frame.
+ AVCFrameIO vin;
+ memset(&vin, 0, sizeof(vin));
+ vin.height = ((height + 15) >> 4) << 4;
+ vin.pitch = ((width + 15) >> 4) << 4;
+ vin.coding_timestamp = (numInputFrames * 1000) / frameRate; // in ms
+ vin.YCbCr[0] = inputBuf;
+ vin.YCbCr[1] = vin.YCbCr[0] + vin.height * vin.pitch;
+ vin.YCbCr[2] = vin.YCbCr[1] + ((vin.height * vin.pitch) >> 2);
+ vin.disp_order = numInputFrames;
+
+ status = PVAVCEncSetInput(&handle, &vin);
+ if (status == AVCENC_SUCCESS || status == AVCENC_NEW_IDR) {
+ readyForNextFrame = false;
+ ++numInputFrames;
+ } else if (status < AVCENC_SUCCESS) {
+ fprintf(stderr, "Error %d while setting input frame\n", status);
+ retVal = EXIT_FAILURE;
+ break;
+ } else {
+ fprintf(stderr, "Frame drop\n");
+ readyForNextFrame = true;
+ ++numInputFrames;
+ continue;
+ }
+ }
+
+ // Encode the input frame.
+ dataLength = kOutputBufferSize;
+ status = PVAVCEncodeNAL(&handle, outputBuf, &dataLength, &type);
+ if (status == AVCENC_SUCCESS) {
+ PVAVCEncGetOverrunBuffer(&handle);
+ } else if (status == AVCENC_PICTURE_READY) {
+ PVAVCEncGetOverrunBuffer(&handle);
+ readyForNextFrame = true;
+ AVCFrameIO recon;
+ if (PVAVCEncGetRecon(&handle, &recon) == AVCENC_SUCCESS) {
+ PVAVCEncReleaseRecon(&handle, &recon);
+ }
+ } else {
+ dataLength = 0;
+ readyForNextFrame = true;
+ }
+
+ if (status < AVCENC_SUCCESS) {
+ fprintf(stderr, "Error %d while encoding frame\n", status);
+ retVal = EXIT_FAILURE;
+ break;
+ }
+
+ numNalEncoded++;
+
+ // Write the output.
+ if (dataLength > 0) {
+ fwrite("\x00\x00\x00\x01", 1, 4, fpOutput); // Start Code.
+ fwrite(outputBuf, 1, dataLength, fpOutput); // NAL.
+ printf("NAL %d of size %d written\n", numNalEncoded, dataLength + 4);
+ }
+ }
+
+ // Close input and output file.
+ fclose(fpInput);
+ fclose(fpOutput);
+
+ // Free allocated memory.
+ free(sliceGroup);
+ free(inputBuf);
+ free(outputBuf);
+ for (int i = 0; i < kMaxDpbBuffers; ++i) {
+ free(dpbBuffers[i]);
+ }
+
+ // Close encoder instance.
+ PVAVCCleanUpEncoder(&handle);
+
+ return retVal;
+}
diff --git a/media/libstagefright/codecs/avcdec/Android.mk b/media/libstagefright/codecs/avcdec/Android.mk
index 902ab57..ef0dbfd 100644
--- a/media/libstagefright/codecs/avcdec/Android.mk
+++ b/media/libstagefright/codecs/avcdec/Android.mk
@@ -20,6 +20,9 @@
LOCAL_SHARED_LIBRARIES += libutils
LOCAL_SHARED_LIBRARIES += liblog
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
+
LOCAL_LDFLAGS := -Wl,-Bsymbolic
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/avcenc/Android.mk b/media/libstagefright/codecs/avcenc/Android.mk
index 24a4db9..70e531b 100644
--- a/media/libstagefright/codecs/avcenc/Android.mk
+++ b/media/libstagefright/codecs/avcenc/Android.mk
@@ -23,6 +23,9 @@
LOCAL_SHARED_LIBRARIES += libutils
LOCAL_SHARED_LIBRARIES += liblog
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
+
LOCAL_LDFLAGS := -Wl,-Bsymbolic
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
index 387d17d..e378a62 100644
--- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
+++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
@@ -28,6 +28,8 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <OMX_IndexExt.h>
+#include <OMX_VideoExt.h>
#include <ui/Rect.h>
#include "ih264_typedefs.h"
@@ -157,8 +159,7 @@
kProfileLevels, NELEM(kProfileLevels),
176 /* width */, 144 /* height */,
callbacks, appData, component),
- mBitrateUpdated(false),
- mKeyFrameRequested(false),
+ mUpdateFlag(0),
mIvVideoColorFormat(IV_YUV_420P),
mAVCEncProfile(IV_PROFILE_BASE),
mAVCEncLevel(41),
@@ -1027,9 +1028,29 @@
}
}
+OMX_ERRORTYPE SoftAVC::getConfig(
+ OMX_INDEXTYPE index, OMX_PTR _params) {
+ switch ((int)index) {
+ case OMX_IndexConfigAndroidIntraRefresh:
+ {
+ OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *intraRefreshParams =
+ (OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *)_params;
+ if (intraRefreshParams->nPortIndex != kOutputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ intraRefreshParams->nRefreshPeriod = mAIRRefreshPeriod;
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SoftVideoEncoderOMXComponent::getConfig(index, _params);
+ }
+}
+
OMX_ERRORTYPE SoftAVC::setConfig(
OMX_INDEXTYPE index, const OMX_PTR _params) {
- switch (index) {
+ switch ((int)index) {
case OMX_IndexConfigVideoIntraVOPRefresh:
{
OMX_CONFIG_INTRAREFRESHVOPTYPE *params =
@@ -1039,7 +1060,9 @@
return OMX_ErrorBadPortIndex;
}
- mKeyFrameRequested = params->IntraRefreshVOP;
+ if (params->IntraRefreshVOP) {
+ mUpdateFlag |= kRequestKeyFrame;
+ }
return OMX_ErrorNone;
}
@@ -1054,11 +1077,30 @@
if (mBitrate != params->nEncodeBitrate) {
mBitrate = params->nEncodeBitrate;
- mBitrateUpdated = true;
+ mUpdateFlag |= kUpdateBitrate;
}
return OMX_ErrorNone;
}
+ case OMX_IndexConfigAndroidIntraRefresh:
+ {
+ const OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *intraRefreshParams =
+ (const OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *)_params;
+ if (intraRefreshParams->nPortIndex != kOutputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (intraRefreshParams->nRefreshPeriod == 0) {
+ mAIRMode = IVE_AIR_MODE_NONE;
+ mAIRRefreshPeriod = 0;
+ } else if (intraRefreshParams->nRefreshPeriod > 0) {
+ mAIRMode = IVE_AIR_MODE_CYCLIC;
+ mAIRRefreshPeriod = intraRefreshParams->nRefreshPeriod;
+ }
+ mUpdateFlag |= kUpdateAIRMode;
+ return OMX_ErrorNone;
+ }
+
default:
return SimpleSoftOMXComponent::setConfig(index, _params);
}
@@ -1071,7 +1113,7 @@
}
mBitrate = bitrate->nTargetBitrate;
- mBitrateUpdated = true;
+ mUpdateFlag |= kUpdateBitrate;
return OMX_ErrorNone;
}
@@ -1291,12 +1333,19 @@
return;
}
- if (mBitrateUpdated) {
- setBitRate();
- }
-
- if (mKeyFrameRequested) {
- setFrameType(IV_IDR_FRAME);
+ if (mUpdateFlag) {
+ if (mUpdateFlag & kUpdateBitrate) {
+ setBitRate();
+ }
+ if (mUpdateFlag & kRequestKeyFrame) {
+ setFrameType(IV_IDR_FRAME);
+ }
+ if (mUpdateFlag & kUpdateAIRMode) {
+ setAirParams();
+ notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
+ OMX_IndexConfigAndroidIntraRefresh, NULL);
+ }
+ mUpdateFlag = 0;
}
if ((inputBufferHeader != NULL)
diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.h b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h
index 4418a7f..232c6e0 100644
--- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.h
+++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h
@@ -142,6 +142,12 @@
kNumBuffers = 2,
};
+ enum {
+ kUpdateBitrate = 1 << 0,
+ kRequestKeyFrame = 1 << 1,
+ kUpdateAIRMode = 1 << 2,
+ };
+
// OMX input buffer's timestamp and flags
typedef struct {
int64_t mTimeUs;
@@ -153,11 +159,7 @@
struct timeval mTimeStart; // Time at the start of decode()
struct timeval mTimeEnd; // Time at the end of decode()
-
- // If a request for a change it bitrate has been received.
- bool mBitrateUpdated;
-
- bool mKeyFrameRequested;
+ int mUpdateFlag;
#ifdef FILE_DUMP_ENABLE
char mInFile[200];
@@ -218,6 +220,9 @@
OMX_ERRORTYPE setConfig(
OMX_INDEXTYPE index, const OMX_PTR _params);
+ OMX_ERRORTYPE getConfig(
+ OMX_INDEXTYPE index, const OMX_PTR _params);
+
// Handles port definition changes.
OMX_ERRORTYPE internalSetPortParams(
const OMX_PARAM_PORTDEFINITIONTYPE *port);
diff --git a/media/libstagefright/codecs/common/Config.mk b/media/libstagefright/codecs/common/Config.mk
deleted file mode 100644
index a843cef..0000000
--- a/media/libstagefright/codecs/common/Config.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# This configure file is just for Linux projects against Android
-#
-
-VOPRJ :=
-VONJ :=
-
-# WARNING:
-# Using v7 breaks generic build
-ifeq ($(TARGET_ARCH),arm)
-VOTT := v5
-else
-VOTT := pc
-endif
-
-# Do we also need to check on ARCH_ARM_HAVE_ARMV7A? - probably not
-ifeq ($(TARGET_ARCH),arm)
- ifeq ($(ARCH_ARM_HAVE_NEON),true)
- VOTT := v7
- endif
-endif
-
-VOTEST := 0
-
diff --git a/media/libstagefright/codecs/flac/enc/Android.mk b/media/libstagefright/codecs/flac/enc/Android.mk
index 59a11de..7e6e015 100644
--- a/media/libstagefright/codecs/flac/enc/Android.mk
+++ b/media/libstagefright/codecs/flac/enc/Android.mk
@@ -10,6 +10,8 @@
external/flac/include
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
LOCAL_SHARED_LIBRARIES := \
libstagefright libstagefright_omx libstagefright_foundation libutils liblog
diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk
index a0112e1..b36c99d 100644
--- a/media/libstagefright/codecs/g711/dec/Android.mk
+++ b/media/libstagefright/codecs/g711/dec/Android.mk
@@ -15,5 +15,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
index 015515e..e342d7c 100644
--- a/media/libstagefright/codecs/g711/dec/SoftG711.cpp
+++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
@@ -262,7 +262,8 @@
// static
void SoftG711::DecodeALaw(
int16_t *out, const uint8_t *in, size_t inSize) {
- while (inSize-- > 0) {
+ while (inSize > 0) {
+ inSize--;
int32_t x = *in++;
int32_t ix = x ^ 0x55;
@@ -288,7 +289,8 @@
// static
void SoftG711::DecodeMLaw(
int16_t *out, const uint8_t *in, size_t inSize) {
- while (inSize-- > 0) {
+ while (inSize > 0) {
+ inSize--;
int32_t x = *in++;
int32_t mantissa = ~x;
diff --git a/media/libstagefright/codecs/gsm/dec/Android.mk b/media/libstagefright/codecs/gsm/dec/Android.mk
index 30868d5..fe8c830 100644
--- a/media/libstagefright/codecs/gsm/dec/Android.mk
+++ b/media/libstagefright/codecs/gsm/dec/Android.mk
@@ -10,6 +10,8 @@
external/libgsm/inc
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
LOCAL_SHARED_LIBRARIES := \
libstagefright libstagefright_omx libstagefright_foundation libutils liblog
diff --git a/media/libstagefright/codecs/hevcdec/Android.mk b/media/libstagefright/codecs/hevcdec/Android.mk
index c0c694e..78c4637 100644
--- a/media/libstagefright/codecs/hevcdec/Android.mk
+++ b/media/libstagefright/codecs/hevcdec/Android.mk
@@ -13,6 +13,8 @@
LOCAL_C_INCLUDES += $(TOP)/external/libhevc/common
LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include
LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
LOCAL_SHARED_LIBRARIES := libstagefright
LOCAL_SHARED_LIBRARIES += libstagefright_omx
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
index 1d232c6..eb39b44 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
@@ -47,6 +47,8 @@
LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF=
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_STATIC_LIBRARY)
@@ -75,5 +77,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.mk b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
index 7117692..ab079e8 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
@@ -34,6 +34,8 @@
$(TOP)/frameworks/native/include/media/openmax
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_STATIC_LIBRARY)
@@ -75,5 +77,29 @@
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_SHARED_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ test/m4v_h263_enc_test.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include
+
+LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF= -DBX_RC
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_m4vh263enc
+
+LOCAL_MODULE := libstagefright_m4vh263enc_test
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/m4v_h263/enc/src/fastcodemb.cpp b/media/libstagefright/codecs/m4v_h263/enc/src/fastcodemb.cpp
index 0ad39a6..50c8161 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/src/fastcodemb.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/src/fastcodemb.cpp
@@ -527,6 +527,9 @@
/* Modified : */
/* 8/15/01, - do 4 pixel at a time assuming 32 bit register */
/* ======================================================================== */
+#ifdef __clang__
+__attribute((no_sanitize("integer")))
+#endif
Int Sad8x8(UChar *cur, UChar *prev, Int width)
{
UChar *end = cur + (width << 3);
@@ -590,7 +593,9 @@
/* Modified : */
/* 8/15/01, - SIMD 4 pixels at a time */
/* ======================================================================== */
-
+#ifdef __clang__
+__attribute((no_sanitize("integer")))
+#endif
Int getBlockSum(UChar *cur, Int width)
{
Int sad = 0, sum4 = 0, sum2 = 0;
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp b/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp
new file mode 100644
index 0000000..db2c61a
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "mp4enc_api.h"
+
+// Constants.
+enum {
+ kMaxWidth = 720,
+ kMaxHeight = 480,
+ kMaxFrameRate = 30,
+ kMaxBitrate = 2048, // in kbps.
+ kOutputBufferSize = 250 * 1024,
+ kIDRFrameRefreshIntervalInSec = 1, // in seconds.
+};
+
+int main(int argc, char *argv[]) {
+
+ if (argc < 8) {
+ fprintf(stderr, "Usage %s <input yuv> <output file> <mode> <width> "
+ "<height> <frame rate> <bitrate in kbps>\n", argv[0]);
+ fprintf(stderr, "mode : h263 or mpeg4\n");
+ fprintf(stderr, "Max width %d\n", kMaxWidth);
+ fprintf(stderr, "Max height %d\n", kMaxHeight);
+ fprintf(stderr, "Max framerate %d\n", kMaxFrameRate);
+ fprintf(stderr, "Max bitrate %d kbps\n", kMaxBitrate);
+ return EXIT_FAILURE;
+ }
+
+ // Read mode.
+ bool isH263mode;
+ if (strcmp(argv[3], "mpeg4") == 0) {
+ isH263mode = false;
+ } else if (strcmp(argv[3], "h263") == 0) {
+ isH263mode = true;
+ } else {
+ fprintf(stderr, "Unsupported mode %s\n", argv[3]);
+ return EXIT_FAILURE;
+ }
+
+ // Read height and width.
+ int32_t width;
+ int32_t height;
+ width = atoi(argv[4]);
+ height = atoi(argv[5]);
+ if (width > kMaxWidth || height > kMaxHeight || width <= 0 || height <= 0) {
+ fprintf(stderr, "Unsupported dimensions %dx%d\n", width, height);
+ return EXIT_FAILURE;
+ }
+
+ if (width % 16 != 0 || height % 16 != 0) {
+ fprintf(stderr, "Video frame size %dx%d must be a multiple of 16\n",
+ width, height);
+ return EXIT_FAILURE;
+ }
+
+ // Read frame rate.
+ int32_t frameRate;
+ frameRate = atoi(argv[6]);
+ if (frameRate > kMaxFrameRate || frameRate <= 0) {
+ fprintf(stderr, "Unsupported frame rate %d\n", frameRate);
+ return EXIT_FAILURE;
+ }
+
+ // Read bitrate.
+ int32_t bitrate;
+ bitrate = atoi(argv[7]);
+ if (bitrate > kMaxBitrate || bitrate <= 0) {
+ fprintf(stderr, "Unsupported bitrate %d\n", bitrate);
+ return EXIT_FAILURE;
+ }
+
+ // Allocate input buffer.
+ uint8_t *inputBuf = (uint8_t *)malloc((width * height * 3) / 2);
+ assert(inputBuf != NULL);
+
+ // Allocate output buffer.
+ uint8_t *outputBuf = (uint8_t *)malloc(kOutputBufferSize);
+ assert(outputBuf != NULL);
+
+ // Open the input file.
+ FILE *fpInput = fopen(argv[1], "rb");
+ if (fpInput == NULL) {
+ fprintf(stderr, "Could not open %s\n", argv[1]);
+ free(inputBuf);
+ free(outputBuf);
+ return EXIT_FAILURE;
+ }
+
+ // Open the output file.
+ FILE *fpOutput = fopen(argv[2], "wb");
+ if (fpOutput == NULL) {
+ fprintf(stderr, "Could not open %s\n", argv[2]);
+ free(inputBuf);
+ free(outputBuf);
+ fclose(fpInput);
+ return EXIT_FAILURE;
+ }
+
+ // Initialize the encoder parameters.
+ tagvideoEncOptions encParams;
+ memset(&encParams, 0, sizeof(tagvideoEncOptions));
+ if (!PVGetDefaultEncOption(&encParams, 0)) {
+ fprintf(stderr, "Failed to get default encoding parameters\n");
+ free(inputBuf);
+ free(outputBuf);
+ fclose(fpInput);
+ fclose(fpOutput);
+ return EXIT_FAILURE;
+ }
+
+ if (isH263mode == false) {
+ encParams.encMode = COMBINE_MODE_WITH_ERR_RES;
+ } else {
+ encParams.encMode = H263_MODE;
+ }
+ encParams.encWidth[0] = width;
+ encParams.encHeight[0] = height;
+ encParams.encFrameRate[0] = frameRate;
+ encParams.rcType = VBR_1;
+ encParams.vbvDelay = 5.0f;
+ encParams.profile_level = CORE_PROFILE_LEVEL2;
+ encParams.packetSize = 32;
+ encParams.rvlcEnable = PV_OFF;
+ encParams.numLayers = 1;
+ encParams.timeIncRes = 1000;
+ encParams.tickPerSrc = encParams.timeIncRes / frameRate;
+
+ encParams.bitRate[0] = bitrate * 1024;
+ encParams.iQuant[0] = 15;
+ encParams.pQuant[0] = 12;
+ encParams.quantType[0] = 0;
+ encParams.noFrameSkipped = PV_OFF;
+
+ int32_t IDRFrameRefreshIntervalInSec = kIDRFrameRefreshIntervalInSec;
+ if (IDRFrameRefreshIntervalInSec == 0) {
+ encParams.intraPeriod = 1; // All I frames.
+ } else {
+ encParams.intraPeriod = (IDRFrameRefreshIntervalInSec * frameRate);
+ }
+
+ encParams.numIntraMB = 0;
+ encParams.sceneDetect = PV_ON;
+ encParams.searchRange = 16;
+ encParams.mv8x8Enable = PV_OFF;
+ encParams.gobHeaderInterval = 0;
+ encParams.useACPred = PV_ON;
+ encParams.intraDCVlcTh = 0;
+
+ // Initialize the handle.
+ tagvideoEncControls handle;
+ memset(&handle, 0, sizeof(tagvideoEncControls));
+
+ // Initialize the encoder.
+ if (!PVInitVideoEncoder(&handle, &encParams)) {
+ fprintf(stderr, "Failed to initialize the encoder\n");
+ return EXIT_FAILURE;
+ }
+
+ // Generate the header.
+ int32_t headerLength = kOutputBufferSize;
+ if (!PVGetVolHeader(&handle, outputBuf, &headerLength, 0)) {
+ fprintf(stderr, "Failed to get VOL header\n");
+ return EXIT_FAILURE;
+ }
+ fwrite(outputBuf, 1, headerLength, fpOutput);
+
+ // Core loop.
+ int32_t retVal = EXIT_SUCCESS;
+ int32_t frameSize = (width * height * 3) / 2;
+ int32_t numFramesEncoded = 0;
+
+ while (1) {
+ // Read the input frame.
+ int32_t bytesRead;
+ bytesRead = fread(inputBuf, 1, frameSize, fpInput);
+ if (bytesRead != frameSize) {
+ break; // End of file.
+ }
+
+ // Encode the input frame.
+ VideoEncFrameIO vin, vout;
+ memset(&vin, 0, sizeof(vin));
+ memset(&vout, 0, sizeof(vout));
+ vin.height = height; // height is multiple of 16.
+ vin.pitch = width; // width is multiple of 16.
+ vin.timestamp = (numFramesEncoded * 1000) / frameRate; // in ms.
+ vin.yChan = inputBuf;
+ vin.uChan = vin.yChan + vin.height * vin.pitch;
+ vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2);
+
+ uint32_t modTimeMs = 0;
+ int32_t nLayer = 0;
+ MP4HintTrack hintTrack;
+ int32_t dataLength = kOutputBufferSize;
+ if (!PVEncodeVideoFrame(&handle, &vin, &vout,
+ &modTimeMs, outputBuf, &dataLength, &nLayer) ||
+ !PVGetHintTrack(&handle, &hintTrack)) {
+ fprintf(stderr, "Failed to encode frame or get hink track at "
+ " frame %d\n", numFramesEncoded);
+ retVal = EXIT_FAILURE;
+ break;
+ }
+ PVGetOverrunBuffer(&handle);
+ numFramesEncoded++;
+
+ // Write the output.
+ fwrite(outputBuf, 1, dataLength, fpOutput);
+ }
+
+ // Close input and output file.
+ fclose(fpInput);
+ fclose(fpOutput);
+
+ // Free allocated memory.
+ free(inputBuf);
+ free(outputBuf);
+
+ // Close encoder instance.
+ PVCleanUpVideoEncoder(&handle);
+ return retVal;
+}
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index 948ae29..11581c1 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -28,19 +28,22 @@
src/pvmp3_stereo_proc.cpp \
src/pvmp3_reorder.cpp \
-ifeq ($(TARGET_ARCH),arm)
-LOCAL_SRC_FILES += \
+LOCAL_SRC_FILES_arm += \
src/asm/pvmp3_polyphase_filter_window_gcc.s \
src/asm/pvmp3_mdct_18_gcc.s \
src/asm/pvmp3_dct_9_gcc.s \
src/asm/pvmp3_dct_16_gcc.s
-else
-LOCAL_SRC_FILES += \
+LOCAL_SRC_FILES_other_archs := \
src/pvmp3_polyphase_filter_window.cpp \
src/pvmp3_mdct_18.cpp \
src/pvmp3_dct_9.cpp \
src/pvmp3_dct_16.cpp
-endif
+
+LOCAL_SRC_FILES_arm64 := $(LOCAL_SRC_FILES_other_archs)
+LOCAL_SRC_FILES_mips := $(LOCAL_SRC_FILES_other_archs)
+LOCAL_SRC_FILES_mips64 := $(LOCAL_SRC_FILES_other_archs)
+LOCAL_SRC_FILES_x86 := $(LOCAL_SRC_FILES_other_archs)
+LOCAL_SRC_FILES_x86_64 := $(LOCAL_SRC_FILES_other_archs)
LOCAL_C_INCLUDES := \
frameworks/av/media/libstagefright/include \
@@ -51,6 +54,8 @@
-D"OSCL_UNUSED_ARG(x)=(void)(x)"
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
LOCAL_MODULE := libstagefright_mp3dec
@@ -72,6 +77,8 @@
$(LOCAL_PATH)/include
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
LOCAL_SHARED_LIBRARIES := \
libstagefright libstagefright_omx libstagefright_foundation libutils liblog
@@ -83,3 +90,27 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
+
+################################################################################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ test/mp3dec_test.cpp \
+ test/mp3reader.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/test/include \
+ $(call include-path-for, audio-utils)
+
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_mp3dec libsndfile
+
+LOCAL_SHARED_LIBRARIES := libaudioutils
+
+LOCAL_MODULE := libstagefright_mp3dec_test
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/mp3dec/test/mp3dec_test.cpp b/media/libstagefright/codecs/mp3dec/test/mp3dec_test.cpp
new file mode 100644
index 0000000..26d62f3
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/mp3dec_test.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#include "pvmp3decoder_api.h"
+#include "mp3reader.h"
+#include <audio_utils/sndfile.h>
+
+using namespace std;
+
+enum {
+ kInputBufferSize = 10 * 1024,
+ kOutputBufferSize = 4608 * 2,
+};
+
+int main(int argc, const char **argv) {
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage %s <input file> <output file>\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ // Initialize the config.
+ tPVMP3DecoderExternal config;
+ config.equalizerType = flat;
+ config.crcEnabled = false;
+
+ // Allocate the decoder memory.
+ uint32_t memRequirements = pvmp3_decoderMemRequirements();
+ void *decoderBuf = malloc(memRequirements);
+ assert(decoderBuf != NULL);
+
+ // Initialize the decoder.
+ pvmp3_InitDecoder(&config, decoderBuf);
+
+ // Open the input file.
+ Mp3Reader mp3Reader;
+ bool success = mp3Reader.init(argv[1]);
+ if (!success) {
+ fprintf(stderr, "Encountered error reading %s\n", argv[1]);
+ free(decoderBuf);
+ return EXIT_FAILURE;
+ }
+
+ // Open the output file.
+ SF_INFO sfInfo;
+ memset(&sfInfo, 0, sizeof(SF_INFO));
+ sfInfo.channels = mp3Reader.getNumChannels();
+ sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ sfInfo.samplerate = mp3Reader.getSampleRate();
+ SNDFILE *handle = sf_open(argv[2], SFM_WRITE, &sfInfo);
+ if (handle == NULL) {
+ fprintf(stderr, "Encountered error writing %s\n", argv[2]);
+ mp3Reader.close();
+ free(decoderBuf);
+ return EXIT_FAILURE;
+ }
+
+ // Allocate input buffer.
+ uint8_t *inputBuf = static_cast<uint8_t*>(malloc(kInputBufferSize));
+ assert(inputBuf != NULL);
+
+ // Allocate output buffer.
+ int16_t *outputBuf = static_cast<int16_t*>(malloc(kOutputBufferSize));
+ assert(outputBuf != NULL);
+
+ // Decode loop.
+ int retVal = EXIT_SUCCESS;
+ while (1) {
+ // Read input from the file.
+ uint32_t bytesRead;
+ bool success = mp3Reader.getFrame(inputBuf, &bytesRead);
+ if (!success) break;
+
+ // Set the input config.
+ config.inputBufferCurrentLength = bytesRead;
+ config.inputBufferMaxLength = 0;
+ config.inputBufferUsedLength = 0;
+ config.pInputBuffer = inputBuf;
+ config.pOutputBuffer = outputBuf;
+ config.outputFrameSize = kOutputBufferSize / sizeof(int16_t);
+
+ ERROR_CODE decoderErr;
+ decoderErr = pvmp3_framedecoder(&config, decoderBuf);
+ if (decoderErr != NO_DECODING_ERROR) {
+ fprintf(stderr, "Decoder encountered error\n");
+ retVal = EXIT_FAILURE;
+ break;
+ }
+ sf_writef_short(handle, outputBuf,
+ config.outputFrameSize / sfInfo.channels);
+ }
+
+ // Close input reader and output writer.
+ mp3Reader.close();
+ sf_close(handle);
+
+ // Free allocated memory.
+ free(inputBuf);
+ free(outputBuf);
+ free(decoderBuf);
+
+ return retVal;
+}
diff --git a/media/libstagefright/codecs/mp3dec/test/mp3reader.cpp b/media/libstagefright/codecs/mp3dec/test/mp3reader.cpp
new file mode 100644
index 0000000..b3138ec
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/mp3reader.cpp
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdint.h>
+#include "mp3reader.h"
+
+static uint32_t U32_AT(const uint8_t *ptr) {
+ return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
+}
+
+static bool parseHeader(
+ uint32_t header, size_t *frame_size,
+ uint32_t *out_sampling_rate = NULL, uint32_t *out_channels = NULL ,
+ uint32_t *out_bitrate = NULL, uint32_t *out_num_samples = NULL) {
+ *frame_size = 0;
+
+ if (out_sampling_rate) {
+ *out_sampling_rate = 0;
+ }
+
+ if (out_channels) {
+ *out_channels = 0;
+ }
+
+ if (out_bitrate) {
+ *out_bitrate = 0;
+ }
+
+ if (out_num_samples) {
+ *out_num_samples = 1152;
+ }
+
+ if ((header & 0xffe00000) != 0xffe00000) {
+ return false;
+ }
+
+ unsigned version = (header >> 19) & 3;
+
+ if (version == 0x01) {
+ return false;
+ }
+
+ unsigned layer = (header >> 17) & 3;
+
+ if (layer == 0x00) {
+ return false;
+ }
+
+ unsigned bitrate_index = (header >> 12) & 0x0f;
+
+ if (bitrate_index == 0 || bitrate_index == 0x0f) {
+ // Disallow "free" bitrate.
+ return false;
+ }
+
+ unsigned sampling_rate_index = (header >> 10) & 3;
+
+ if (sampling_rate_index == 3) {
+ return false;
+ }
+
+ static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
+ int sampling_rate = kSamplingRateV1[sampling_rate_index];
+ if (version == 2 /* V2 */) {
+ sampling_rate /= 2;
+ } else if (version == 0 /* V2.5 */) {
+ sampling_rate /= 4;
+ }
+
+ unsigned padding = (header >> 9) & 1;
+
+ if (layer == 3) {
+ // layer I
+
+ static const int kBitrateV1[] = {
+ 32, 64, 96, 128, 160, 192, 224, 256,
+ 288, 320, 352, 384, 416, 448
+ };
+
+ static const int kBitrateV2[] = {
+ 32, 48, 56, 64, 80, 96, 112, 128,
+ 144, 160, 176, 192, 224, 256
+ };
+
+ int bitrate =
+ (version == 3 /* V1 */)
+ ? kBitrateV1[bitrate_index - 1]
+ : kBitrateV2[bitrate_index - 1];
+
+ if (out_bitrate) {
+ *out_bitrate = bitrate;
+ }
+
+ *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
+
+ if (out_num_samples) {
+ *out_num_samples = 384;
+ }
+ } else {
+ // layer II or III
+
+ static const int kBitrateV1L2[] = {
+ 32, 48, 56, 64, 80, 96, 112, 128,
+ 160, 192, 224, 256, 320, 384
+ };
+
+ static const int kBitrateV1L3[] = {
+ 32, 40, 48, 56, 64, 80, 96, 112,
+ 128, 160, 192, 224, 256, 320
+ };
+
+ static const int kBitrateV2[] = {
+ 8, 16, 24, 32, 40, 48, 56, 64,
+ 80, 96, 112, 128, 144, 160
+ };
+
+ int bitrate;
+ if (version == 3 /* V1 */) {
+ bitrate = (layer == 2 /* L2 */)
+ ? kBitrateV1L2[bitrate_index - 1]
+ : kBitrateV1L3[bitrate_index - 1];
+
+ if (out_num_samples) {
+ *out_num_samples = 1152;
+ }
+ } else {
+ // V2 (or 2.5)
+
+ bitrate = kBitrateV2[bitrate_index - 1];
+ if (out_num_samples) {
+ *out_num_samples = (layer == 1 /* L3 */) ? 576 : 1152;
+ }
+ }
+
+ if (out_bitrate) {
+ *out_bitrate = bitrate;
+ }
+
+ if (version == 3 /* V1 */) {
+ *frame_size = 144000 * bitrate / sampling_rate + padding;
+ } else {
+ // V2 or V2.5
+ size_t tmp = (layer == 1 /* L3 */) ? 72000 : 144000;
+ *frame_size = tmp * bitrate / sampling_rate + padding;
+ }
+ }
+
+ if (out_sampling_rate) {
+ *out_sampling_rate = sampling_rate;
+ }
+
+ if (out_channels) {
+ int channel_mode = (header >> 6) & 3;
+
+ *out_channels = (channel_mode == 3) ? 1 : 2;
+ }
+
+ return true;
+}
+
+// Mask to extract the version, layer, sampling rate parts of the MP3 header,
+// which should be same for all MP3 frames.
+static const uint32_t kMask = 0xfffe0c00;
+
+static ssize_t sourceReadAt(FILE *fp, off64_t offset, void *data, size_t size) {
+ int retVal = fseek(fp, offset, SEEK_SET);
+ if (retVal != EXIT_SUCCESS) {
+ return 0;
+ } else {
+ return fread(data, 1, size, fp);
+ }
+}
+
+// Resync to next valid MP3 frame in the file.
+static bool resync(
+ FILE *fp, uint32_t match_header,
+ off64_t *inout_pos, uint32_t *out_header) {
+
+ if (*inout_pos == 0) {
+ // Skip an optional ID3 header if syncing at the very beginning
+ // of the datasource.
+
+ for (;;) {
+ uint8_t id3header[10];
+ int retVal = sourceReadAt(fp, *inout_pos, id3header,
+ sizeof(id3header));
+ if (retVal < (ssize_t)sizeof(id3header)) {
+ // If we can't even read these 10 bytes, we might as well bail
+ // out, even if there _were_ 10 bytes of valid mp3 audio data...
+ return false;
+ }
+
+ if (memcmp("ID3", id3header, 3)) {
+ break;
+ }
+
+ // Skip the ID3v2 header.
+
+ size_t len =
+ ((id3header[6] & 0x7f) << 21)
+ | ((id3header[7] & 0x7f) << 14)
+ | ((id3header[8] & 0x7f) << 7)
+ | (id3header[9] & 0x7f);
+
+ len += 10;
+
+ *inout_pos += len;
+ }
+
+ }
+
+ off64_t pos = *inout_pos;
+ bool valid = false;
+
+ const int32_t kMaxReadBytes = 1024;
+ const int32_t kMaxBytesChecked = 128 * 1024;
+ uint8_t buf[kMaxReadBytes];
+ ssize_t bytesToRead = kMaxReadBytes;
+ ssize_t totalBytesRead = 0;
+ ssize_t remainingBytes = 0;
+ bool reachEOS = false;
+ uint8_t *tmp = buf;
+
+ do {
+ if (pos >= *inout_pos + kMaxBytesChecked) {
+ // Don't scan forever.
+ break;
+ }
+
+ if (remainingBytes < 4) {
+ if (reachEOS) {
+ break;
+ } else {
+ memcpy(buf, tmp, remainingBytes);
+ bytesToRead = kMaxReadBytes - remainingBytes;
+
+ /*
+ * The next read position should start from the end of
+ * the last buffer, and thus should include the remaining
+ * bytes in the buffer.
+ */
+ totalBytesRead = sourceReadAt(fp, pos + remainingBytes,
+ buf + remainingBytes, bytesToRead);
+
+ if (totalBytesRead <= 0) {
+ break;
+ }
+ reachEOS = (totalBytesRead != bytesToRead);
+ remainingBytes += totalBytesRead;
+ tmp = buf;
+ continue;
+ }
+ }
+
+ uint32_t header = U32_AT(tmp);
+
+ if (match_header != 0 && (header & kMask) != (match_header & kMask)) {
+ ++pos;
+ ++tmp;
+ --remainingBytes;
+ continue;
+ }
+
+ size_t frame_size;
+ uint32_t sample_rate, num_channels, bitrate;
+ if (!parseHeader(
+ header, &frame_size,
+ &sample_rate, &num_channels, &bitrate)) {
+ ++pos;
+ ++tmp;
+ --remainingBytes;
+ continue;
+ }
+
+ // We found what looks like a valid frame,
+ // now find its successors.
+
+ off64_t test_pos = pos + frame_size;
+
+ valid = true;
+ const int FRAME_MATCH_REQUIRED = 3;
+ for (int j = 0; j < FRAME_MATCH_REQUIRED; ++j) {
+ uint8_t tmp[4];
+ ssize_t retval = sourceReadAt(fp, test_pos, tmp, sizeof(tmp));
+ if (retval < (ssize_t)sizeof(tmp)) {
+ valid = false;
+ break;
+ }
+
+ uint32_t test_header = U32_AT(tmp);
+
+ if ((test_header & kMask) != (header & kMask)) {
+ valid = false;
+ break;
+ }
+
+ size_t test_frame_size;
+ if (!parseHeader(test_header, &test_frame_size)) {
+ valid = false;
+ break;
+ }
+
+ test_pos += test_frame_size;
+ }
+
+ if (valid) {
+ *inout_pos = pos;
+
+ if (out_header != NULL) {
+ *out_header = header;
+ }
+ }
+
+ ++pos;
+ ++tmp;
+ --remainingBytes;
+ } while (!valid);
+
+ return valid;
+}
+
+Mp3Reader::Mp3Reader() : mFp(NULL) {
+}
+
+// Initialize the MP3 reader.
+bool Mp3Reader::init(const char *file) {
+
+ // Open the file.
+ mFp = fopen(file, "rb");
+ if (mFp == NULL) return false;
+
+ // Sync to the first valid frame.
+ off64_t pos = 0;
+ uint32_t header;
+ bool success = resync(mFp, 0 /*match_header*/, &pos, &header);
+ if (success == false) return false;
+
+ mCurrentPos = pos;
+ mFixedHeader = header;
+
+ size_t frame_size;
+ return parseHeader(header, &frame_size, &mSampleRate,
+ &mNumChannels, &mBitrate);
+}
+
+// Get the next valid MP3 frame.
+bool Mp3Reader::getFrame(void *buffer, uint32_t *size) {
+
+ size_t frame_size;
+ uint32_t bitrate;
+ uint32_t num_samples;
+ uint32_t sample_rate;
+ for (;;) {
+ ssize_t n = sourceReadAt(mFp, mCurrentPos, buffer, 4);
+ if (n < 4) {
+ return false;
+ }
+
+ uint32_t header = U32_AT((const uint8_t *)buffer);
+
+ if ((header & kMask) == (mFixedHeader & kMask)
+ && parseHeader(
+ header, &frame_size, &sample_rate, NULL /*out_channels*/,
+ &bitrate, &num_samples)) {
+ break;
+ }
+
+ // Lost sync.
+ off64_t pos = mCurrentPos;
+ if (!resync(mFp, mFixedHeader, &pos, NULL /*out_header*/)) {
+ // Unable to resync. Signalling end of stream.
+ return false;
+ }
+
+ mCurrentPos = pos;
+
+ // Try again with the new position.
+ }
+ ssize_t n = sourceReadAt(mFp, mCurrentPos, buffer, frame_size);
+ if (n < (ssize_t)frame_size) {
+ return false;
+ }
+
+ *size = frame_size;
+ mCurrentPos += frame_size;
+ return true;
+}
+
+// Close the MP3 reader.
+void Mp3Reader::close() {
+ assert(mFp != NULL);
+ fclose(mFp);
+}
+
+Mp3Reader::~Mp3Reader() {
+}
diff --git a/media/libstagefright/codecs/mp3dec/test/mp3reader.h b/media/libstagefright/codecs/mp3dec/test/mp3reader.h
new file mode 100644
index 0000000..871f664
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/mp3reader.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef MP3READER_H_
+#define MP3READER_H_
+
+class Mp3Reader {
+public:
+ Mp3Reader();
+ bool init(const char *file);
+ bool getFrame(void *buffer, uint32_t *size);
+ uint32_t getSampleRate() { return mSampleRate;}
+ uint32_t getNumChannels() { return mNumChannels;}
+ void close();
+ ~Mp3Reader();
+private:
+ FILE *mFp;
+ uint32_t mFixedHeader;
+ off64_t mCurrentPos;
+ uint32_t mSampleRate;
+ uint32_t mNumChannels;
+ uint32_t mBitrate;
+};
+
+
+#endif /* MP3READER_H_ */
diff --git a/media/libstagefright/codecs/mpeg2dec/Android.mk b/media/libstagefright/codecs/mpeg2dec/Android.mk
index 23b126d..f1c1719 100644
--- a/media/libstagefright/codecs/mpeg2dec/Android.mk
+++ b/media/libstagefright/codecs/mpeg2dec/Android.mk
@@ -21,6 +21,8 @@
LOCAL_SHARED_LIBRARIES += liblog
LOCAL_LDFLAGS := -Wl,-Bsymbolic
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk
index 93ff64c..76f7600 100644
--- a/media/libstagefright/codecs/on2/dec/Android.mk
+++ b/media/libstagefright/codecs/on2/dec/Android.mk
@@ -21,5 +21,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
index e161fb8..6106a93 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
@@ -17,6 +17,8 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "SoftVPX"
#include <utils/Log.h>
+#include <utils/misc.h>
+#include "OMX_VideoExt.h"
#include "SoftVPX.h"
@@ -26,6 +28,11 @@
namespace android {
+// Only need to declare the highest supported profile and level here.
+static const CodecProfileLevel kVP9ProfileLevels[] = {
+ { OMX_VIDEO_VP9Profile0, OMX_VIDEO_VP9Level5 },
+};
+
SoftVPX::SoftVPX(
const char *name,
const char *componentRole,
@@ -35,7 +42,8 @@
OMX_COMPONENTTYPE **component)
: SoftVideoDecoderOMXComponent(
name, componentRole, codingType,
- NULL /* profileLevels */, 0 /* numProfileLevels */,
+ codingType == OMX_VIDEO_CodingVP8 ? NULL : kVP9ProfileLevels,
+ codingType == OMX_VIDEO_CodingVP8 ? 0 : NELEM(kVP9ProfileLevels),
320 /* width */, 240 /* height */, callbacks, appData, component),
mMode(codingType == OMX_VIDEO_CodingVP8 ? MODE_VP8 : MODE_VP9),
mEOSStatus(INPUT_DATA_AVAILABLE),
@@ -102,7 +110,6 @@
}
bool SoftVPX::outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset) {
- List<BufferInfo *> &inQueue = getPortQueue(0);
List<BufferInfo *> &outQueue = getPortQueue(1);
BufferInfo *outInfo = NULL;
OMX_BUFFERHEADERTYPE *outHeader = NULL;
@@ -193,7 +200,6 @@
List<BufferInfo *> &inQueue = getPortQueue(0);
List<BufferInfo *> &outQueue = getPortQueue(1);
bool EOSseen = false;
- vpx_codec_err_t err;
bool portWillReset = false;
while ((mEOSStatus == INPUT_EOS_SEEN || !inQueue.empty())
@@ -211,28 +217,36 @@
mEOSStatus == INPUT_EOS_SEEN) {
return;
}
+ // Continue as outQueue may be empty now.
+ continue;
}
BufferInfo *inInfo = *inQueue.begin();
OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
mTimeStamps[mTimeStampIdx] = inHeader->nTimeStamp;
- BufferInfo *outInfo = *outQueue.begin();
- OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
mEOSStatus = INPUT_EOS_SEEN;
EOSseen = true;
}
- if (inHeader->nFilledLen > 0 &&
- vpx_codec_decode((vpx_codec_ctx_t *)mCtx,
- inHeader->pBuffer + inHeader->nOffset,
- inHeader->nFilledLen,
- &mTimeStamps[mTimeStampIdx], 0)) {
- ALOGE("on2 decoder failed to decode frame.");
- notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- return;
+ if (inHeader->nFilledLen > 0) {
+ vpx_codec_err_t err = vpx_codec_decode(
+ (vpx_codec_ctx_t *)mCtx, inHeader->pBuffer + inHeader->nOffset,
+ inHeader->nFilledLen, &mTimeStamps[mTimeStampIdx], 0);
+ if (err == VPX_CODEC_OK) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ } else {
+ ALOGE("on2 decoder failed to decode frame.");
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ return;
+ }
}
+
mTimeStampIdx = (mTimeStampIdx + 1) % kNumBuffers;
if (!outputBuffers(
@@ -244,12 +258,6 @@
if (portWillReset) {
return;
}
-
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
}
}
diff --git a/media/libstagefright/codecs/on2/enc/Android.mk b/media/libstagefright/codecs/on2/enc/Android.mk
index 253fa04..1de318a 100644
--- a/media/libstagefright/codecs/on2/enc/Android.mk
+++ b/media/libstagefright/codecs/on2/enc/Android.mk
@@ -11,6 +11,9 @@
frameworks/av/media/libstagefright/include \
frameworks/native/include/media/openmax \
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
+
LOCAL_STATIC_LIBRARIES := \
libvpx
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index 410f9d0..0f28e8d 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -106,24 +106,24 @@
status_t SoftVPXEncoder::initEncoder() {
vpx_codec_err_t codec_return;
+ status_t result = UNKNOWN_ERROR;
- mCodecContext = new vpx_codec_ctx_t;
- mCodecConfiguration = new vpx_codec_enc_cfg_t;
mCodecInterface = vpx_codec_vp8_cx();
-
if (mCodecInterface == NULL) {
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
ALOGD("VP8: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u",
(uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
mMinQuantizer, mMaxQuantizer);
+
+ mCodecConfiguration = new vpx_codec_enc_cfg_t;
codec_return = vpx_codec_enc_config_default(mCodecInterface,
mCodecConfiguration,
0); // Codec specific flags
if (codec_return != VPX_CODEC_OK) {
ALOGE("Error populating default configuration for vpx encoder.");
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
mCodecConfiguration->g_w = mWidth;
@@ -250,7 +250,7 @@
default:
{
ALOGE("Wrong number of temporal layers %zu", mTemporalLayers);
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
}
@@ -272,6 +272,7 @@
mCodecConfiguration->rc_max_quantizer = mMaxQuantizer;
}
+ mCodecContext = new vpx_codec_ctx_t;
codec_return = vpx_codec_enc_init(mCodecContext,
mCodecInterface,
mCodecConfiguration,
@@ -279,7 +280,7 @@
if (codec_return != VPX_CODEC_OK) {
ALOGE("Error initializing vpx encoder");
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
codec_return = vpx_codec_control(mCodecContext,
@@ -287,7 +288,7 @@
mDCTPartitions);
if (codec_return != VPX_CODEC_OK) {
ALOGE("Error setting dct partitions for vpx encoder.");
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
// Extra CBR settings
@@ -313,7 +314,7 @@
}
if (codec_return != VPX_CODEC_OK) {
ALOGE("Error setting cbr parameters for vpx encoder.");
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
}
@@ -321,16 +322,20 @@
free(mConversionBuffer);
mConversionBuffer = NULL;
if (((uint64_t)mWidth * mHeight) > ((uint64_t)INT32_MAX / 3)) {
- ALOGE("b/25812794, Buffer size is too big.");
- return UNKNOWN_ERROR;
+ ALOGE("b/25812794, Buffer size is too big, width=%d, height=%d.", mWidth, mHeight);
+ goto CLEAN_UP;
}
mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2);
if (mConversionBuffer == NULL) {
ALOGE("Allocating conversion buffer failed.");
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
}
return OK;
+
+CLEAN_UP:
+ releaseEncoder();
+ return result;
}
diff --git a/media/libstagefright/codecs/on2/h264dec/Android.mk b/media/libstagefright/codecs/on2/h264dec/Android.mk
index e63b6b1..7159674 100644
--- a/media/libstagefright/codecs/on2/h264dec/Android.mk
+++ b/media/libstagefright/codecs/on2/h264dec/Android.mk
@@ -84,21 +84,20 @@
./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S \
./omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S \
-ifeq ($(TARGET_ARCH),arm)
- ifeq ($(ARCH_ARM_HAVE_NEON),true)
+
+ifeq ($(ARCH_ARM_HAVE_NEON),true)
LOCAL_ARM_NEON := true
-# LOCAL_CFLAGS := -std=c99 -D._NEON -D._OMXDL
- LOCAL_CFLAGS := -DH264DEC_NEON -DH264DEC_OMXDL
- LOCAL_SRC_FILES += $(MY_ASM) $(MY_OMXDL_C_SRC) $(MY_OMXDL_ASM_SRC)
- LOCAL_C_INCLUDES += $(LOCAL_PATH)/./source/arm_neon_asm_gcc
- LOCAL_C_INCLUDES += $(LOCAL_PATH)/./omxdl/arm_neon/api \
+ LOCAL_CFLAGS_arm := -DH264DEC_NEON -DH264DEC_OMXDL
+ LOCAL_SRC_FILES_arm := $(MY_ASM) $(MY_OMXDL_C_SRC) $(MY_OMXDL_ASM_SRC)
+ LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/./source/arm_neon_asm_gcc
+ LOCAL_C_INCLUDES_arm += $(LOCAL_PATH)/./omxdl/arm_neon/api \
$(LOCAL_PATH)/./omxdl/arm_neon/vc/api \
$(LOCAL_PATH)/./omxdl/arm_neon/vc/m4p10/api
- # h264bsdWriteMacroblock.S does not compile with Clang.
- LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
- endif
endif
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
+
LOCAL_SHARED_LIBRARIES := \
libstagefright libstagefright_omx libstagefright_foundation libutils liblog \
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM.h
index 91e38b8..1992885 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM.h
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM.h
@@ -86,7 +86,7 @@
/* Alignment operation */
-#define armAlignToBytes(Ptr,N) (Ptr + ( ((N-(int)Ptr)&(N-1)) / sizeof(*Ptr) ))
+#define armAlignToBytes(Ptr,N) (Ptr + ( ((N-(intptr_t)Ptr)&(N-1)) / sizeof(*Ptr) ))
#define armAlignTo2Bytes(Ptr) armAlignToBytes(Ptr,2)
#define armAlignTo4Bytes(Ptr) armAlignToBytes(Ptr,4)
#define armAlignTo8Bytes(Ptr) armAlignToBytes(Ptr,8)
@@ -98,8 +98,8 @@
#define armRetDataErrIf(condition, code) if(condition) { return (code); }
#ifndef ALIGNMENT_DOESNT_MATTER
-#define armIsByteAligned(Ptr,N) ((((int)(Ptr)) % N)==0)
-#define armNotByteAligned(Ptr,N) ((((int)(Ptr)) % N)!=0)
+#define armIsByteAligned(Ptr,N) ((((intptr_t)(Ptr)) % N)==0)
+#define armNotByteAligned(Ptr,N) ((((intptr_t)(Ptr)) % N)!=0)
#else
#define armIsByteAligned(Ptr,N) (1)
#define armNotByteAligned(Ptr,N) (0)
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Average_4x_Align_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Average_4x_Align_unsafe_s.S
index 46e0018..e1ffb09 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Average_4x_Align_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Average_4x_Align_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_Average_4x4_Align0_unsafe
- .func armVCM4P10_Average_4x4_Align0_unsafe
armVCM4P10_Average_4x4_Align0_unsafe:
PUSH {r4-r6,lr}
LDR r7, =0x80808080
@@ -55,10 +54,8 @@
EOR r4,r4,r7
STR r4,[r2],r3
POP {r4-r6,pc}
- .endfunc
.global armVCM4P10_Average_4x4_Align2_unsafe
- .func armVCM4P10_Average_4x4_Align2_unsafe
armVCM4P10_Average_4x4_Align2_unsafe:
PUSH {r4-r6,lr}
LDR r7, =0x80808080
@@ -99,10 +96,8 @@
EOR r4,r4,r7
STR r4,[r2],r3
POP {r4-r6,pc}
- .endfunc
.global armVCM4P10_Average_4x4_Align3_unsafe
- .func armVCM4P10_Average_4x4_Align3_unsafe
armVCM4P10_Average_4x4_Align3_unsafe:
PUSH {r4-r6,lr}
LDR r7, =0x80808080
@@ -143,7 +138,6 @@
EOR r4,r4,r7
STR r4,[r2],r3
POP {r4-r6,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingChroma_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingChroma_unsafe_s.S
index ca64a02..40ea4a9 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingChroma_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingChroma_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_DeblockingChromabSLT4_unsafe
- .func armVCM4P10_DeblockingChromabSLT4_unsafe
armVCM4P10_DeblockingChromabSLT4_unsafe:
VLD1.32 {d18[0]},[r5]!
VSUBL.U8 q11,d5,d9
@@ -50,10 +49,8 @@
VQMOVUN.S16 d29,q14
VQMOVUN.S16 d24,q12
BX lr
- .endfunc
.global armVCM4P10_DeblockingChromabSGE4_unsafe
- .func armVCM4P10_DeblockingChromabSGE4_unsafe
armVCM4P10_DeblockingChromabSGE4_unsafe:
VHADD.U8 d13,d4,d9
VHADD.U8 d31,d8,d5
@@ -63,7 +60,6 @@
VRHADD.U8 d13,d13,d5
VRHADD.U8 d31,d31,d9
BX lr
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingLuma_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingLuma_unsafe_s.S
index 193bc5e..05fb2c5 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingLuma_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingLuma_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_DeblockingLumabSLT4_unsafe
- .func armVCM4P10_DeblockingLumabSLT4_unsafe
armVCM4P10_DeblockingLumabSLT4_unsafe:
VSUBL.U8 q11,d5,d9
VLD1.8 {d18[]},[r5]!
@@ -66,10 +65,8 @@
VBIF d24,d8,d16
VBIF d25,d9,d12
BX lr
- .endfunc
.global armVCM4P10_DeblockingLumabSGE4_unsafe
- .func armVCM4P10_DeblockingLumabSGE4_unsafe
armVCM4P10_DeblockingLumabSGE4_unsafe:
VSHR.U8 d19,d0,#2
VADD.I8 d19,d19,d15
@@ -111,7 +108,6 @@
VBIF d24,d8,d16
VBIF d28,d10,d12
BX lr
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S
index 8e0db37..27c0452 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S
@@ -42,7 +42,6 @@
.hidden armVCM4P10_ZigZag_4x4
.global armVCM4P10_DecodeCoeffsToPair
- .func armVCM4P10_DecodeCoeffsToPair
armVCM4P10_DecodeCoeffsToPair:
PUSH {r4-r12,lr}
SUB sp,sp,#0x40
@@ -302,7 +301,6 @@
L0x35c:
ADD sp,sp,#0x40
POP {r4-r12,pc}
- .endfunc
.LarmVCM4P10_CAVLCCoeffTokenTables:
.word armVCM4P10_CAVLCCoeffTokenTables-(P0+8)
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Align_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Align_unsafe_s.S
index 7206d76..1de9004 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Align_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Align_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_HorAlign9x_unsafe
- .func armVCM4P10_InterpolateLuma_HorAlign9x_unsafe
armVCM4P10_InterpolateLuma_HorAlign9x_unsafe:
MOV r12,r8
AND r7,r0,#3
@@ -83,10 +82,8 @@
MOV r0,r12
MOV r1,#0xc
BX lr
- .endfunc
.global armVCM4P10_InterpolateLuma_VerAlign4x_unsafe
- .func armVCM4P10_InterpolateLuma_VerAlign4x_unsafe
armVCM4P10_InterpolateLuma_VerAlign4x_unsafe:
AND r7,r0,#3
BIC r0,r0,#3
@@ -132,7 +129,6 @@
SUB r0,r8,#0x1c
MOV r1,#4
BX lr
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Copy_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Copy_unsafe_s.S
index e41d662..7ba2890 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Copy_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Copy_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_Copy4x4_unsafe
- .func armVCM4P10_InterpolateLuma_Copy4x4_unsafe
armVCM4P10_InterpolateLuma_Copy4x4_unsafe:
PUSH {r4-r6,lr}
AND r12,r0,#3
@@ -114,7 +113,6 @@
STR r8,[r2],r3
Copy4x4End:
POP {r4-r6,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_DiagCopy_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_DiagCopy_unsafe_s.S
index c8f5cda..8b2c678 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_DiagCopy_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_DiagCopy_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_HorDiagCopy_unsafe
- .func armVCM4P10_InterpolateLuma_HorDiagCopy_unsafe
armVCM4P10_InterpolateLuma_HorDiagCopy_unsafe:
PUSH {r4-r6,lr}
MOV lr,#4
@@ -57,10 +56,8 @@
SUB r0,r7,#0x20
MOV r1,#8
POP {r4-r6,pc}
- .endfunc
.global armVCM4P10_InterpolateLuma_VerDiagCopy_unsafe
- .func armVCM4P10_InterpolateLuma_VerDiagCopy_unsafe
armVCM4P10_InterpolateLuma_VerDiagCopy_unsafe:
PUSH {r4-r6,lr}
LDR r6, =0xfe00fe0
@@ -116,7 +113,6 @@
SUB r0,r7,#0x18
MOV r1,#4
POP {r4-r6,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe_s.S
index f5868c0..77aa927 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe
- .func armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe
armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe:
PUSH {r4-r12,lr}
VLD1.8 {d0,d1},[r0],r1
@@ -173,7 +172,6 @@
VQMOVN.U16 d4,q2
VQMOVN.U16 d6,q3
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe_s.S
index 065995d..e5f7f1c 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe
- .func armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe
armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe:
PUSH {r4-r12,lr}
VLD1.8 {d0,d1},[r0],r1
@@ -128,7 +127,6 @@
VQMOVN.U16 d4,q2
VQMOVN.U16 d6,q3
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe_s.S
index 1e2d16b..393d385 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe
- .func armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe
armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe:
PUSH {r4-r12,lr}
VLD1.8 {d22,d23},[r0],r1
@@ -81,7 +80,6 @@
VQRSHRUN.S16 d26,q13,#5
VQRSHRUN.S16 d28,q14,#5
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe_s.S
index c7def2a..698e7b5 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe
- .func armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe
armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe:
PUSH {r4-r12,lr}
VLD1.8 {d7},[r0],r1
@@ -67,7 +66,6 @@
VQRSHRUN.S16 d4,q2,#5
VQRSHRUN.S16 d6,q3,#5
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S
index 2f4293f..e469516 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S
@@ -38,7 +38,6 @@
.word WidthIs8MVIsZero-(P0+8)
.global armVCM4P10_Interpolate_Chroma
- .func armVCM4P10_Interpolate_Chroma
armVCM4P10_Interpolate_Chroma:
PUSH {r4-r12,lr}
VPUSH {d8-d15}
@@ -183,7 +182,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_TransformResidual4x4_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_TransformResidual4x4_s.S
index d4cedb5..e18bec7 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_TransformResidual4x4_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_TransformResidual4x4_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_TransformResidual4x4
- .func armVCM4P10_TransformResidual4x4
armVCM4P10_TransformResidual4x4:
VPUSH {d8}
VLD4.16 {d0,d1,d2,d3},[r1]
@@ -61,7 +60,6 @@
VST1.16 {d0,d1,d2,d3},[r0]
VPOP {d8}
BX lr
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_UnpackBlock4x4_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_UnpackBlock4x4_s.S
index 1652dc6..b97efcb 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_UnpackBlock4x4_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_UnpackBlock4x4_s.S
@@ -24,9 +24,9 @@
.arm
.fpu neon
.text
+ .syntax unified
.global armVCM4P10_UnpackBlock4x4
- .func armVCM4P10_UnpackBlock4x4
armVCM4P10_UnpackBlock4x4:
PUSH {r4-r8,lr}
LDR r2,[r0,#0]
@@ -40,16 +40,15 @@
STRD r4,r5,[r1,#0x18]
unpackLoop:
TST r3,#0x10
- LDRNESB r5,[r2,#1]
- LDRNEB r4,[r2],#2
+ LDRSBNE r5,[r2,#1]
+ LDRBNE r4,[r2],#2
AND r6,r7,r3,LSL #1
- LDREQSB r4,[r2],#1
+ LDRSBEQ r4,[r2],#1
ORRNE r4,r4,r5,LSL #8
TST r3,#0x20
- LDREQB r3,[r2],#1
+ LDRBEQ r3,[r2],#1
STRH r4,[r1,r6]
BEQ unpackLoop
STR r2,[r0,#0]
POP {r4-r8,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DeblockLuma_I.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DeblockLuma_I.S
index 90b0947..6a99bde 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DeblockLuma_I.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DeblockLuma_I.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_DeblockLuma_I
- .func omxVCM4P10_DeblockLuma_I
omxVCM4P10_DeblockLuma_I:
PUSH {r4-r9,lr}
MOVS r6,r0
@@ -76,7 +75,6 @@
BL omxVCM4P10_FilterDeblockingLuma_HorEdge_I
ADD sp,sp,#0xc
POP {r4-r9,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S
index 4a74594..17c5d8b 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_DequantTransformResidualFromPairAndAdd
- .func omxVCM4P10_DequantTransformResidualFromPairAndAdd
omxVCM4P10_DequantTransformResidualFromPairAndAdd:
PUSH {r4-r12,lr}
VPUSH {d8-d9}
@@ -131,7 +130,6 @@
ADD sp,sp,#0x20
VPOP {d8-d9}
POP {r4-r12,pc}
- .endfunc
.LarmVCM4P10_QPModuloTable:
.word armVCM4P10_QPModuloTable-(P0+8)
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_HorEdge_I_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_HorEdge_I_s.S
index f20fb78..4a83516 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_HorEdge_I_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_HorEdge_I_s.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_FilterDeblockingChroma_HorEdge_I
- .func omxVCM4P10_FilterDeblockingChroma_HorEdge_I
omxVCM4P10_FilterDeblockingChroma_HorEdge_I:
PUSH {r4-r10,lr}
VPUSH {d8-d15}
@@ -96,7 +95,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r10,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_VerEdge_I_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_VerEdge_I_s.S
index 003526e..fe10931 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_VerEdge_I_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_VerEdge_I_s.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_FilterDeblockingChroma_VerEdge_I
- .func omxVCM4P10_FilterDeblockingChroma_VerEdge_I
omxVCM4P10_FilterDeblockingChroma_VerEdge_I:
PUSH {r4-r12,lr}
VPUSH {d8-d15}
@@ -132,7 +131,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_HorEdge_I_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_HorEdge_I_s.S
index 7ddc42e..84ffad2 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_HorEdge_I_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_HorEdge_I_s.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_FilterDeblockingLuma_HorEdge_I
- .func omxVCM4P10_FilterDeblockingLuma_HorEdge_I
omxVCM4P10_FilterDeblockingLuma_HorEdge_I:
PUSH {r4-r12,lr}
VPUSH {d8-d15}
@@ -116,7 +115,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_VerEdge_I_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_VerEdge_I_s.S
index f71aceb..f2a3682 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_VerEdge_I_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_VerEdge_I_s.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_FilterDeblockingLuma_VerEdge_I
- .func omxVCM4P10_FilterDeblockingLuma_VerEdge_I
omxVCM4P10_FilterDeblockingLuma_VerEdge_I:
PUSH {r4-r12,lr}
VPUSH {d8-d15}
@@ -166,7 +165,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_InterpolateLuma_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_InterpolateLuma_s.S
index 000fbeb..314eabd 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_InterpolateLuma_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_InterpolateLuma_s.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_InterpolateLuma
- .func omxVCM4P10_InterpolateLuma
omxVCM4P10_InterpolateLuma:
PUSH {r4-r12,lr}
VPUSH {d8-d15}
@@ -332,7 +331,6 @@
ADD sp,sp,#0x10
VPOP {d8-d15}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S
index 4e2cff6..50d1350 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S
@@ -36,7 +36,6 @@
.hword 1, 2, 3,4
.global omxVCM4P10_PredictIntraChroma_8x8
- .func omxVCM4P10_PredictIntraChroma_8x8
omxVCM4P10_PredictIntraChroma_8x8:
PUSH {r4-r10,lr}
VPUSH {d8-d15}
@@ -226,7 +225,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r10,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S
index c71c93b..0044636 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S
@@ -42,7 +42,6 @@
.global omxVCM4P10_PredictIntra_16x16
- .func omxVCM4P10_PredictIntra_16x16
omxVCM4P10_PredictIntra_16x16:
PUSH {r4-r12,lr}
VPUSH {d8-d15}
@@ -246,7 +245,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S
index cd5d356..d4c8485 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S
@@ -35,7 +35,6 @@
.word OMX_VC_4x4_HU-(P0+8)
.global omxVCM4P10_PredictIntra_4x4
- .func omxVCM4P10_PredictIntra_4x4
omxVCM4P10_PredictIntra_4x4:
PUSH {r4-r12,lr}
VPUSH {d8-d12}
@@ -270,6 +269,5 @@
MOV r0,#0
VPOP {d8-d12}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S
index 5570892..74f5103 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S
@@ -24,9 +24,9 @@
.arm
.fpu neon
.text
+ .syntax unified
.global omxVCM4P10_TransformDequantChromaDCFromPair
- .func omxVCM4P10_TransformDequantChromaDCFromPair
omxVCM4P10_TransformDequantChromaDCFromPair:
push {r4-r10, lr}
ldr r9, [r0,#0]
@@ -36,13 +36,13 @@
ldrb r6, [r9], #1
unpackLoop:
tst r6, #0x10
- ldrnesb r5, [r9, #1]
- ldrneb r4, [r9], #2
+ ldrsbne r5, [r9, #1]
+ ldrbne r4, [r9], #2
and r7, r8, r6, lsl #1
- ldreqsb r4, [r9], #1
+ ldrsbeq r4, [r9], #1
orrne r4, r4, r5, lsl #8
tst r6, #0x20
- ldreqb r6, [r9], #1
+ ldrbeq r6, [r9], #1
strh r4, [r1, r7]
beq unpackLoop
ldmia r1, {r3, r4}
@@ -66,7 +66,6 @@
vst1.16 {d2}, [r1]
mov r0, #0
pop {r4-r10, pc}
- .endfunc
.LarmVCM4P10_QPDivTable:
.word armVCM4P10_QPDivTable-(P0+8)
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S
index 5b6eee0..a01030a 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InvTransformDequantLumaDC4x4
- .func armVCM4P10_InvTransformDequantLumaDC4x4
armVCM4P10_InvTransformDequantLumaDC4x4:
PUSH {r4-r6,lr}
VPUSH {d8-d13}
@@ -73,7 +72,6 @@
VST1.16 {d0,d1,d2,d3},[r0]
VPOP {d8-d13}
POP {r4-r6,pc}
- .endfunc
.LarmVCM4P10_QPDivTable:
.word armVCM4P10_QPDivTable-(P0+8)
@@ -81,7 +79,6 @@
.word armVCM4P10_VMatrixQPModTable-(P1+8)
.global omxVCM4P10_TransformDequantLumaDCFromPair
-.func omxVCM4P10_TransformDequantLumaDCFromPair
omxVCM4P10_TransformDequantLumaDCFromPair:
PUSH {r4-r6,lr}
MOV r4,r1
@@ -92,7 +89,6 @@
BL armVCM4P10_InvTransformDequantLumaDC4x4
MOV r0,#0
POP {r4-r6,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/reference/api/armCOMM.h b/media/libstagefright/codecs/on2/h264dec/omxdl/reference/api/armCOMM.h
index fbb97e2..7304863 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/reference/api/armCOMM.h
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/reference/api/armCOMM.h
@@ -86,7 +86,7 @@
/* Alignment operation */
-#define armAlignToBytes(Ptr,N) (Ptr + ( ((N-(int)Ptr)&(N-1)) / sizeof(*Ptr) ))
+#define armAlignToBytes(Ptr,N) (Ptr + ( ((N-(intptr_t)Ptr)&(N-1)) / sizeof(*Ptr) ))
#define armAlignTo2Bytes(Ptr) armAlignToBytes(Ptr,2)
#define armAlignTo4Bytes(Ptr) armAlignToBytes(Ptr,4)
#define armAlignTo8Bytes(Ptr) armAlignToBytes(Ptr,8)
@@ -98,8 +98,8 @@
#define armRetDataErrIf(condition, code) if(condition) { return (code); }
#ifndef ALIGNMENT_DOESNT_MATTER
-#define armIsByteAligned(Ptr,N) ((((int)(Ptr)) % N)==0)
-#define armNotByteAligned(Ptr,N) ((((int)(Ptr)) % N)!=0)
+#define armIsByteAligned(Ptr,N) ((((intptr_t)(Ptr)) % N)==0)
+#define armNotByteAligned(Ptr,N) ((((intptr_t)(Ptr)) % N)!=0)
#else
#define armIsByteAligned(Ptr,N) (1)
#define armNotByteAligned(Ptr,N) (0)
diff --git a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/asm_common.S b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/asm_common.S
index f39f5c4..969a75c 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/asm_common.S
+++ b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/asm_common.S
@@ -31,11 +31,9 @@
.global \name
.endif
.type \name, %function
- .func \name
\name:
.endm
.macro endfunction
- .endfunc
.endm
diff --git a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdClearMbLayer.S b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdClearMbLayer.S
index c8a940e..3c2752f 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdClearMbLayer.S
+++ b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdClearMbLayer.S
@@ -16,7 +16,7 @@
#include "asm_common.S"
- preserve8
+ PRESERVE8
.fpu neon
.text
@@ -29,7 +29,7 @@
/* -- NEON registers -- */
-#define qZero Q0.U8
+#define qZero Q0
/*------------------------------------------------------------------------------
@@ -47,17 +47,17 @@
function h264bsdClearMbLayer, export=1
- VMOV qZero, #0
+ VMOV.I8 qZero, #0
ADD pTmp, pMbLayer, #16
MOV step, #32
SUBS size, size, #64
loop:
- VST1 {qZero}, [pMbLayer], step
+ VST1.8 {qZero}, [pMbLayer], step
SUBS size, size, #64
- VST1 {qZero}, [pTmp], step
- VST1 {qZero}, [pMbLayer], step
- VST1 {qZero}, [pTmp], step
+ VST1.8 {qZero}, [pTmp], step
+ VST1.8 {qZero}, [pMbLayer], step
+ VST1.8 {qZero}, [pTmp], step
BCS loop
BX lr
diff --git a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdCountLeadingZeros.S b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdCountLeadingZeros.S
index 05253d0..b1c9f60 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdCountLeadingZeros.S
+++ b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdCountLeadingZeros.S
@@ -15,7 +15,7 @@
@
#include "asm_common.S"
- preserve8
+ PRESERVE8
.arm
.text
diff --git a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFillRow7.S b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFillRow7.S
index 6955b9a..6ed6227 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFillRow7.S
+++ b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFillRow7.S
@@ -16,7 +16,7 @@
#include "asm_common.S"
- preserve8
+ PRESERVE8
.fpu neon
.text
@@ -33,12 +33,12 @@
/* -- NEON registers -- */
-#define qTmp0 Q0.U8
-#define qTmp1 Q1.U8
-#define dTmp0 D0.U8
-#define dTmp1 D1.U8
-#define dTmp2 D2.U8
-#define dTmp3 D3.U8
+#define qTmp0 Q0
+#define qTmp1 Q1
+#define dTmp0 D0
+#define dTmp1 D1
+#define dTmp2 D2
+#define dTmp3 D3
/*
void h264bsdFillRow7(const u8 * ref, u8 * fill, i32 left, i32 center,
@@ -74,40 +74,40 @@
B case_8
case_8:
- VLD1 {qTmp0, qTmp1}, [ref]!
+ VLD1.8 {qTmp0, qTmp1}, [ref]!
SUB center, center, #32
- VST1 {qTmp0}, [fill]!
- VST1 {qTmp1}, [fill]!
+ VST1.8 {qTmp0}, [fill]!
+ VST1.8 {qTmp1}, [fill]!
B loop_center
case_7:
- VLD1 {dTmp0,dTmp1,dTmp2}, [ref]!
+ VLD1.8 {dTmp0,dTmp1,dTmp2}, [ref]!
SUB center, center, #28
LDR tmp2, [ref], #4
- VST1 {dTmp0,dTmp1,dTmp2}, [fill]!
+ VST1.8 {dTmp0,dTmp1,dTmp2}, [fill]!
STR tmp2, [fill],#4
B loop_center
case_6:
- VLD1 {dTmp0,dTmp1,dTmp2}, [ref]!
+ VLD1.8 {dTmp0,dTmp1,dTmp2}, [ref]!
SUB center, center, #24
- VST1 {dTmp0,dTmp1,dTmp2}, [fill]!
+ VST1.8 {dTmp0,dTmp1,dTmp2}, [fill]!
B loop_center
case_5:
- VLD1 {qTmp0}, [ref]!
+ VLD1.8 {qTmp0}, [ref]!
SUB center, center, #20
LDR tmp2, [ref], #4
- VST1 {qTmp0}, [fill]!
+ VST1.8 {qTmp0}, [fill]!
STR tmp2, [fill],#4
B loop_center
case_4:
- VLD1 {qTmp0}, [ref]!
+ VLD1.8 {qTmp0}, [ref]!
SUB center, center, #16
- VST1 {qTmp0}, [fill]!
+ VST1.8 {qTmp0}, [fill]!
B loop_center
case_3:
- VLD1 {dTmp0}, [ref]!
+ VLD1.8 {dTmp0}, [ref]!
SUB center, center, #12
LDR tmp2, [ref], #4
- VST1 dTmp0, [fill]!
+ VST1.8 dTmp0, [fill]!
STR tmp2, [fill],#4
B loop_center
case_2:
diff --git a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFlushBits.S b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFlushBits.S
index b3f3191..aa88471 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFlushBits.S
+++ b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFlushBits.S
@@ -16,7 +16,7 @@
#include "asm_common.S"
- preserve8
+ PRESERVE8
.arm
.text
diff --git a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdWriteMacroblock.S b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdWriteMacroblock.S
index 495d560..4093b92 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdWriteMacroblock.S
+++ b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdWriteMacroblock.S
@@ -16,8 +16,8 @@
#include "asm_common.S"
- require8
- preserve8
+ REQUIRE8
+ PRESERVE8
.arm
.fpu neon
@@ -34,39 +34,39 @@
/* -- NEON registers -- */
-#define qRow0 Q0.U8
-#define qRow1 Q1.U8
-#define qRow2 Q2.U8
-#define qRow3 Q3.U8
-#define qRow4 Q4.U8
-#define qRow5 Q5.U8
-#define qRow6 Q6.U8
-#define qRow7 Q7.U8
-#define qRow8 Q8.U8
-#define qRow9 Q9.U8
-#define qRow10 Q10.U8
-#define qRow11 Q11.U8
-#define qRow12 Q12.U8
-#define qRow13 Q13.U8
-#define qRow14 Q14.U8
-#define qRow15 Q15.U8
+#define qRow0 Q0
+#define qRow1 Q1
+#define qRow2 Q2
+#define qRow3 Q3
+#define qRow4 Q4
+#define qRow5 Q5
+#define qRow6 Q6
+#define qRow7 Q7
+#define qRow8 Q8
+#define qRow9 Q9
+#define qRow10 Q10
+#define qRow11 Q11
+#define qRow12 Q12
+#define qRow13 Q13
+#define qRow14 Q14
+#define qRow15 Q15
-#define dRow0 D0.U8
-#define dRow1 D1.U8
-#define dRow2 D2.U8
-#define dRow3 D3.U8
-#define dRow4 D4.U8
-#define dRow5 D5.U8
-#define dRow6 D6.U8
-#define dRow7 D7.U8
-#define dRow8 D8.U8
-#define dRow9 D9.U8
-#define dRow10 D10.U8
-#define dRow11 D11.U8
-#define dRow12 D12.U8
-#define dRow13 D13.U8
-#define dRow14 D14.U8
-#define dRow15 D15.U8
+#define dRow0 D0
+#define dRow1 D1
+#define dRow2 D2
+#define dRow3 D3
+#define dRow4 D4
+#define dRow5 D5
+#define dRow6 D6
+#define dRow7 D7
+#define dRow8 D8
+#define dRow9 D9
+#define dRow10 D10
+#define dRow11 D11
+#define dRow12 D12
+#define dRow13 D13
+#define dRow14 D14
+#define dRow15 D15
/*------------------------------------------------------------------------------
@@ -99,59 +99,58 @@
@ Write luma
- VLD1 {qRow0, qRow1}, [data]!
+ VLD1.8 {qRow0, qRow1}, [data]!
LSL width, width, #4
- VLD1 {qRow2, qRow3}, [data]!
+ VLD1.8 {qRow2, qRow3}, [data]!
LSR cwidth, width, #1
- VST1 {qRow0}, [luma,:128], width
- VLD1 {qRow4, qRow5}, [data]!
- VST1 {qRow1}, [luma,:128], width
- VLD1 {qRow6, qRow7}, [data]!
- VST1 {qRow2}, [luma,:128], width
- VLD1 {qRow8, qRow9}, [data]!
- VST1 {qRow3}, [luma,:128], width
- VLD1 {qRow10, qRow11}, [data]!
- VST1 {qRow4}, [luma,:128], width
- VLD1 {qRow12, qRow13}, [data]!
- VST1 {qRow5}, [luma,:128], width
- VLD1 {qRow14, qRow15}, [data]!
- VST1 {qRow6}, [luma,:128], width
+ VST1.8 {qRow0}, [luma,:128], width
+ VLD1.8 {qRow4, qRow5}, [data]!
+ VST1.8 {qRow1}, [luma,:128], width
+ VLD1.8 {qRow6, qRow7}, [data]!
+ VST1.8 {qRow2}, [luma,:128], width
+ VLD1.8 {qRow8, qRow9}, [data]!
+ VST1.8 {qRow3}, [luma,:128], width
+ VLD1.8 {qRow10, qRow11}, [data]!
+ VST1.8 {qRow4}, [luma,:128], width
+ VLD1.8 {qRow12, qRow13}, [data]!
+ VST1.8 {qRow5}, [luma,:128], width
+ VLD1.8 {qRow14, qRow15}, [data]!
+ VST1.8 {qRow6}, [luma,:128], width
- VLD1 {qRow0, qRow1}, [data]! ;//cb rows 0,1,2,3
- VST1 {qRow7}, [luma,:128], width
- VLD1 {qRow2, qRow3}, [data]! ;//cb rows 4,5,6,7
- VST1 {qRow8}, [luma,:128], width
- VLD1 {qRow4, qRow5}, [data]! ;//cr rows 0,1,2,3
- VST1 {qRow9}, [luma,:128], width
- VLD1 {qRow6, qRow7}, [data]! ;//cr rows 4,5,6,7
- VST1 {qRow10}, [luma,:128], width
- VST1 {dRow0}, [cb,:64], cwidth
- VST1 {dRow8}, [cr,:64], cwidth
- VST1 {qRow11}, [luma,:128], width
- VST1 {dRow1}, [cb,:64], cwidth
- VST1 {dRow9}, [cr,:64], cwidth
- VST1 {qRow12}, [luma,:128], width
- VST1 {dRow2}, [cb,:64], cwidth
- VST1 {dRow10}, [cr,:64], cwidth
- VST1 {qRow13}, [luma,:128], width
- VST1 {dRow3}, [cb,:64], cwidth
- VST1 {dRow11}, [cr,:64], cwidth
- VST1 {qRow14}, [luma,:128], width
- VST1 {dRow4}, [cb,:64], cwidth
- VST1 {dRow12}, [cr,:64], cwidth
- VST1 {qRow15}, [luma]
- VST1 {dRow5}, [cb,:64], cwidth
- VST1 {dRow13}, [cr,:64], cwidth
- VST1 {dRow6}, [cb,:64], cwidth
- VST1 {dRow14}, [cr,:64], cwidth
- VST1 {dRow7}, [cb,:64]
- VST1 {dRow15}, [cr,:64]
+ VLD1.8 {qRow0, qRow1}, [data]! ;//cb rows 0,1,2,3
+ VST1.8 {qRow7}, [luma,:128], width
+ VLD1.8 {qRow2, qRow3}, [data]! ;//cb rows 4,5,6,7
+ VST1.8 {qRow8}, [luma,:128], width
+ VLD1.8 {qRow4, qRow5}, [data]! ;//cr rows 0,1,2,3
+ VST1.8 {qRow9}, [luma,:128], width
+ VLD1.8 {qRow6, qRow7}, [data]! ;//cr rows 4,5,6,7
+ VST1.8 {qRow10}, [luma,:128], width
+ VST1.8 {dRow0}, [cb,:64], cwidth
+ VST1.8 {dRow8}, [cr,:64], cwidth
+ VST1.8 {qRow11}, [luma,:128], width
+ VST1.8 {dRow1}, [cb,:64], cwidth
+ VST1.8 {dRow9}, [cr,:64], cwidth
+ VST1.8 {qRow12}, [luma,:128], width
+ VST1.8 {dRow2}, [cb,:64], cwidth
+ VST1.8 {dRow10}, [cr,:64], cwidth
+ VST1.8 {qRow13}, [luma,:128], width
+ VST1.8 {dRow3}, [cb,:64], cwidth
+ VST1.8 {dRow11}, [cr,:64], cwidth
+ VST1.8 {qRow14}, [luma,:128], width
+ VST1.8 {dRow4}, [cb,:64], cwidth
+ VST1.8 {dRow12}, [cr,:64], cwidth
+ VST1.8 {qRow15}, [luma]
+ VST1.8 {dRow5}, [cb,:64], cwidth
+ VST1.8 {dRow13}, [cr,:64], cwidth
+ VST1.8 {dRow6}, [cb,:64], cwidth
+ VST1.8 {dRow14}, [cr,:64], cwidth
+ VST1.8 {dRow7}, [cb,:64]
+ VST1.8 {dRow15}, [cr,:64]
VPOP {q4-q7}
POP {r4-r6,pc}
@ BX lr
- .endfunc
diff --git a/media/libstagefright/codecs/opus/dec/Android.mk b/media/libstagefright/codecs/opus/dec/Android.mk
index 2379c5f..f272763 100644
--- a/media/libstagefright/codecs/opus/dec/Android.mk
+++ b/media/libstagefright/codecs/opus/dec/Android.mk
@@ -13,7 +13,10 @@
libopus libstagefright libstagefright_omx \
libstagefright_foundation libutils liblog
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
+
LOCAL_MODULE := libstagefright_soft_opusdec
LOCAL_MODULE_TAGS := optional
-include $(BUILD_SHARED_LIBRARY)
\ No newline at end of file
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/raw/Android.mk b/media/libstagefright/codecs/raw/Android.mk
index 87080e7..e454c84 100644
--- a/media/libstagefright/codecs/raw/Android.mk
+++ b/media/libstagefright/codecs/raw/Android.mk
@@ -9,6 +9,8 @@
frameworks/native/include/media/openmax
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
LOCAL_SHARED_LIBRARIES := \
libstagefright_omx libstagefright_foundation libutils liblog
diff --git a/media/libstagefright/codecs/raw/SoftRaw.cpp b/media/libstagefright/codecs/raw/SoftRaw.cpp
index 9d514a6..9d3bab8 100644
--- a/media/libstagefright/codecs/raw/SoftRaw.cpp
+++ b/media/libstagefright/codecs/raw/SoftRaw.cpp
@@ -159,7 +159,16 @@
}
default:
- return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ {
+ OMX_ERRORTYPE err = SimpleSoftOMXComponent::internalSetParameter(
+ index, params);
+ // In case inPort->mDef.nBufferSize changed, the output buffer size
+ // should match the input buffer size.
+ PortInfo *inPort = editPortInfo(0);
+ PortInfo *outPort = editPortInfo(1);
+ outPort->mDef.nBufferSize = inPort->mDef.nBufferSize;
+ return err;
+ }
}
}
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk
index 217a6d2..039be6f 100644
--- a/media/libstagefright/codecs/vorbis/dec/Android.mk
+++ b/media/libstagefright/codecs/vorbis/dec/Android.mk
@@ -17,5 +17,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS += -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index c559682..3b1b2dc 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -56,6 +56,7 @@
mNumFramesLeftOnPage(-1),
mSawInputEos(false),
mSignalledOutputEos(false),
+ mSignalledError(false),
mOutputPortSettingsChange(NONE) {
initPorts();
CHECK_EQ(initDecoder(), (status_t)OK);
@@ -247,7 +248,7 @@
List<BufferInfo *> &inQueue = getPortQueue(0);
List<BufferInfo *> &outQueue = getPortQueue(1);
- if (mOutputPortSettingsChange != NONE) {
+ if (mSignalledError || mOutputPortSettingsChange != NONE) {
return;
}
@@ -271,9 +272,19 @@
mVi = new vorbis_info;
vorbis_info_init(mVi);
- CHECK_EQ(0, _vorbis_unpack_info(mVi, &bits));
+ int ret = _vorbis_unpack_info(mVi, &bits);
+ if (ret != 0) {
+ notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
+ mSignalledError = true;
+ return;
+ }
} else {
- CHECK_EQ(0, _vorbis_unpack_books(mVi, &bits));
+ 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;
@@ -418,6 +429,9 @@
// depend on fragments from the last one decoded.
mNumFramesOutput = 0;
+ mSawInputEos = false;
+ mSignalledOutputEos = false;
+ mNumFramesLeftOnPage = -1;
vorbis_dsp_restart(mState);
}
}
@@ -439,6 +453,7 @@
mSawInputEos = false;
mSignalledOutputEos = false;
+ mSignalledError = false;
mOutputPortSettingsChange = NONE;
}
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
index 1d00816..30d137b 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
@@ -61,6 +61,7 @@
int32_t mNumFramesLeftOnPage;
bool mSawInputEos;
bool mSignalledOutputEos;
+ bool mSignalledError;
enum {
NONE,
diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk
index 4f7c48f..32e2dfd 100644
--- a/media/libstagefright/colorconversion/Android.mk
+++ b/media/libstagefright/colorconversion/Android.mk
@@ -11,6 +11,7 @@
LOCAL_CFLAGS += -Werror
LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
LOCAL_MODULE:= libstagefright_color_conversion
diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml
index 81a6d00..b03c769 100644
--- a/media/libstagefright/data/media_codecs_google_video.xml
+++ b/media/libstagefright/data/media_codecs_google_video.xml
@@ -84,6 +84,7 @@
<Limit name="block-size" value="16x16" />
<Limit name="blocks-per-second" range="1-244800" />
<Limit name="bitrate" range="1-12000000" />
+ <Feature name="intra-refresh" />
</MediaCodec>
<MediaCodec name="OMX.google.mpeg4.encoder" type="video/mp4v-es">
<!-- profiles and levels: ProfileCore : Level2 -->
diff --git a/media/libstagefright/filters/GraphicBufferListener.cpp b/media/libstagefright/filters/GraphicBufferListener.cpp
index a606315..c1aaa17 100644
--- a/media/libstagefright/filters/GraphicBufferListener.cpp
+++ b/media/libstagefright/filters/GraphicBufferListener.cpp
@@ -101,11 +101,11 @@
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
// shouldn't happen, since we track num frames available
ALOGE("frame was not available");
- item.mBuf = -1;
+ item.mSlot = -1;
return item;
} else if (err != OK) {
ALOGE("acquireBuffer returned err=%d", err);
- item.mBuf = -1;
+ item.mSlot = -1;
return item;
}
@@ -119,8 +119,8 @@
// If this is the first time we're seeing this buffer, add it to our
// slot table.
if (item.mGraphicBuffer != NULL) {
- ALOGV("setting mBufferSlot %d", item.mBuf);
- mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+ ALOGV("setting mBufferSlot %d", item.mSlot);
+ mBufferSlot[item.mSlot] = item.mGraphicBuffer;
}
return item;
@@ -128,24 +128,24 @@
sp<GraphicBuffer> GraphicBufferListener::getBuffer(BufferItem item) {
sp<GraphicBuffer> buf;
- if (item.mBuf < 0 || item.mBuf >= BufferQueue::NUM_BUFFER_SLOTS) {
- ALOGE("getBuffer() received invalid BufferItem: mBuf==%d", item.mBuf);
+ if (item.mSlot < 0 || item.mSlot >= BufferQueue::NUM_BUFFER_SLOTS) {
+ ALOGE("getBuffer() received invalid BufferItem: mSlot==%d", item.mSlot);
return buf;
}
- buf = mBufferSlot[item.mBuf];
+ buf = mBufferSlot[item.mSlot];
CHECK(buf.get() != NULL);
return buf;
}
status_t GraphicBufferListener::releaseBuffer(BufferItem item) {
- if (item.mBuf < 0 || item.mBuf >= BufferQueue::NUM_BUFFER_SLOTS) {
- ALOGE("getBuffer() received invalid BufferItem: mBuf==%d", item.mBuf);
+ if (item.mSlot < 0 || item.mSlot >= BufferQueue::NUM_BUFFER_SLOTS) {
+ ALOGE("getBuffer() received invalid BufferItem: mSlot==%d", item.mSlot);
return ERROR_OUT_OF_RANGE;
}
- mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber,
+ mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
return OK;
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index 0cf6b06..cd69418 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -773,7 +773,7 @@
convertRGBAToARGB(
(uint8_t*)bufPtr, buf->getWidth(), buf->getHeight(),
buf->getStride(), inputInfo->mData->data());
- inputInfo->mBufferID = item.mBuf;
+ inputInfo->mBufferID = item.mSlot;
inputInfo->mGeneration = mGeneration;
inputInfo->mOutputFlags = 0;
inputInfo->mStatus = BufferInfo::OWNED_BY_US;
diff --git a/media/libstagefright/foundation/ABuffer.cpp b/media/libstagefright/foundation/ABuffer.cpp
index a5b81a8..804046a 100644
--- a/media/libstagefright/foundation/ABuffer.cpp
+++ b/media/libstagefright/foundation/ABuffer.cpp
@@ -67,10 +67,6 @@
}
}
- if (mFarewell != NULL) {
- mFarewell->post();
- }
-
setMediaBufferBase(NULL);
}
@@ -82,10 +78,6 @@
mRangeLength = size;
}
-void ABuffer::setFarewellMessage(const sp<AMessage> msg) {
- mFarewell = msg;
-}
-
sp<AMessage> ABuffer::meta() {
if (mMeta == NULL) {
mMeta = new AMessage;
diff --git a/media/libstagefright/foundation/ANetworkSession.cpp b/media/libstagefright/foundation/ANetworkSession.cpp
index b230400..4bcb1f6 100644
--- a/media/libstagefright/foundation/ANetworkSession.cpp
+++ b/media/libstagefright/foundation/ANetworkSession.cpp
@@ -1318,7 +1318,8 @@
List<sp<Session> > sessionsToAdd;
- for (size_t i = mSessions.size(); res > 0 && i-- > 0;) {
+ for (size_t i = mSessions.size(); res > 0 && i > 0;) {
+ i--;
const sp<Session> &session = mSessions.valueAt(i);
int s = session->socket();
@@ -1409,4 +1410,3 @@
}
} // namespace android
-
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index c68264c..711601f 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -15,6 +15,9 @@
AString.cpp \
AStringUtils.cpp \
AWakeLock.cpp \
+ MediaBuffer.cpp \
+ MediaBufferGroup.cpp \
+ MetaData.cpp \
ParsedMessage.cpp \
base64.cpp \
hexdump.cpp
@@ -31,6 +34,7 @@
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_MODULE:= libstagefright_foundation
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
similarity index 86%
rename from media/libstagefright/MediaBuffer.cpp
rename to media/libstagefright/foundation/MediaBuffer.cpp
index 1f80a47..fa8e241 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/foundation/MediaBuffer.cpp
@@ -47,13 +47,29 @@
: mObserver(NULL),
mNextBuffer(NULL),
mRefCount(0),
- mData(malloc(size)),
+ mData(NULL),
mSize(size),
mRangeOffset(0),
mRangeLength(size),
mOwnsData(true),
mMetaData(new MetaData),
mOriginal(NULL) {
+ if (size < kSharedMemThreshold) {
+ mData = malloc(size);
+ } else {
+ sp<MemoryDealer> memoryDealer = new MemoryDealer(size, "MediaBuffer");
+ mMemory = memoryDealer->allocate(size);
+ if (mMemory == NULL) {
+ ALOGW("Failed to allocate shared memory, trying regular allocation!");
+ mData = malloc(size);
+ if (mData == NULL) {
+ ALOGE("Out of memory");
+ }
+ } else {
+ mData = mMemory->pointer();
+ ALOGV("Allocated shared mem buffer of size %zu @ %p", size, mData);
+ }
+ }
}
MediaBuffer::MediaBuffer(const sp<GraphicBuffer>& graphicBuffer)
@@ -158,7 +174,7 @@
MediaBuffer::~MediaBuffer() {
CHECK(mObserver == NULL);
- if (mOwnsData && mData != NULL) {
+ if (mOwnsData && mData != NULL && mMemory == NULL) {
free(mData);
mData = NULL;
}
diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
new file mode 100644
index 0000000..9022324
--- /dev/null
+++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
@@ -0,0 +1,132 @@
+/*
+ * 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_TAG "MediaBufferGroup"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+
+namespace android {
+
+MediaBufferGroup::MediaBufferGroup()
+ : mFirstBuffer(NULL),
+ mLastBuffer(NULL) {
+}
+
+MediaBufferGroup::~MediaBufferGroup() {
+ MediaBuffer *next;
+ for (MediaBuffer *buffer = mFirstBuffer; buffer != NULL;
+ buffer = next) {
+ next = buffer->nextBuffer();
+
+ CHECK_EQ(buffer->refcount(), 0);
+
+ buffer->setObserver(NULL);
+ buffer->release();
+ }
+}
+
+void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ buffer->setObserver(this);
+
+ if (mLastBuffer) {
+ mLastBuffer->setNextBuffer(buffer);
+ } else {
+ mFirstBuffer = buffer;
+ }
+
+ mLastBuffer = buffer;
+}
+
+status_t MediaBufferGroup::acquire_buffer(
+ MediaBuffer **out, bool nonBlocking, size_t requestedSize) {
+ Mutex::Autolock autoLock(mLock);
+
+ for (;;) {
+ MediaBuffer *freeBuffer = NULL;
+ MediaBuffer *freeBufferPrevious = NULL;
+ MediaBuffer *buffer = NULL;
+ MediaBuffer *bufferPrevious = NULL;
+ size_t smallest = requestedSize;
+ for (buffer = mFirstBuffer;
+ buffer != NULL; buffer = buffer->nextBuffer()) {
+ if (buffer->refcount() == 0) {
+ if (buffer->size() >= requestedSize) {
+ break;
+ } else if (buffer->size() < smallest) {
+ freeBuffer = buffer;
+ freeBufferPrevious = bufferPrevious;
+ }
+ }
+ bufferPrevious = buffer;
+ }
+
+ if (buffer == NULL && freeBuffer != NULL) {
+ ALOGV("allocate new buffer, requested size %zu vs available %zu",
+ requestedSize, freeBuffer->size());
+ size_t allocateSize = requestedSize;
+ if (requestedSize < SIZE_MAX / 3) {
+ allocateSize = requestedSize * 3 / 2;
+ }
+ MediaBuffer *newBuffer = new MediaBuffer(allocateSize);
+ newBuffer->setObserver(this);
+ if (freeBuffer == mFirstBuffer) {
+ mFirstBuffer = newBuffer;
+ }
+ if (freeBuffer == mLastBuffer) {
+ mLastBuffer = newBuffer;
+ }
+ newBuffer->setNextBuffer(freeBuffer->nextBuffer());
+ if (freeBufferPrevious != NULL) {
+ freeBufferPrevious->setNextBuffer(newBuffer);
+ }
+ freeBuffer->setObserver(NULL);
+ freeBuffer->release();
+
+ buffer = newBuffer;
+ }
+
+ if (buffer != NULL) {
+ buffer->add_ref();
+ buffer->reset();
+
+ *out = buffer;
+ goto exit;
+ }
+
+ if (nonBlocking) {
+ *out = NULL;
+ return WOULD_BLOCK;
+ }
+
+ // All buffers are in use. Block until one of them is returned to us.
+ mCondition.wait(mLock);
+ }
+
+exit:
+ return OK;
+}
+
+void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
+ Mutex::Autolock autoLock(mLock);
+ mCondition.signal();
+}
+
+} // namespace android
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/foundation/MetaData.cpp
similarity index 84%
rename from media/libstagefright/MetaData.cpp
rename to media/libstagefright/foundation/MetaData.cpp
index 1a11c1e..b847eed 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/foundation/MetaData.cpp
@@ -107,7 +107,7 @@
}
bool MetaData::findInt32(uint32_t key, int32_t *value) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
@@ -122,7 +122,7 @@
}
bool MetaData::findInt64(uint32_t key, int64_t *value) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
@@ -137,7 +137,7 @@
}
bool MetaData::findFloat(uint32_t key, float *value) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
@@ -152,7 +152,7 @@
}
bool MetaData::findPointer(uint32_t key, void **value) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
@@ -170,7 +170,7 @@
uint32_t key,
int32_t *left, int32_t *top,
int32_t *right, int32_t *bottom) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_RECT) {
@@ -377,5 +377,57 @@
}
}
+status_t MetaData::writeToParcel(Parcel &parcel) {
+ size_t numItems = mItems.size();
+ parcel.writeUint32(uint32_t(numItems));
+ for (size_t i = 0; i < numItems; i++) {
+ int32_t key = mItems.keyAt(i);
+ const typed_data &item = mItems.valueAt(i);
+ uint32_t type;
+ const void *data;
+ size_t size;
+ item.getData(&type, &data, &size);
+ parcel.writeInt32(key);
+ parcel.writeUint32(type);
+ parcel.writeByteArray(size, (uint8_t*)data);
+ }
+ return OK;
+}
+
+status_t MetaData::updateFromParcel(const Parcel &parcel) {
+ uint32_t numItems;
+ if (parcel.readUint32(&numItems) == OK) {
+
+ for (size_t i = 0; i < numItems; i++) {
+ int32_t key;
+ uint32_t type;
+ uint32_t size;
+ status_t ret = parcel.readInt32(&key);
+ ret |= parcel.readUint32(&type);
+ ret |= parcel.readUint32(&size);
+ if (ret != OK) {
+ break;
+ }
+ // copy data directly from Parcel storage, then advance position
+ setData(key, type, parcel.readInplace(size), size);
+ }
+
+ return OK;
+ }
+ ALOGW("no metadata in parcel");
+ return UNKNOWN_ERROR;
+}
+
+
+/* static */
+sp<MetaData> MetaData::createFromParcel(const Parcel &parcel) {
+
+ sp<MetaData> meta = new MetaData();
+ meta->updateFromParcel(parcel);
+ return meta;
+}
+
+
+
} // namespace android
diff --git a/media/libstagefright/http/Android.mk b/media/libstagefright/http/Android.mk
index 5fb51c1..bc71134 100644
--- a/media/libstagefright/http/Android.mk
+++ b/media/libstagefright/http/Android.mk
@@ -23,6 +23,7 @@
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/httplive/Android.mk b/media/libstagefright/httplive/Android.mk
index fc85835..f904212 100644
--- a/media/libstagefright/httplive/Android.mk
+++ b/media/libstagefright/httplive/Android.mk
@@ -15,6 +15,7 @@
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_SHARED_LIBRARIES := \
libbinder \
diff --git a/media/libstagefright/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
index 3b44bae..861b85a 100644
--- a/media/libstagefright/httplive/HTTPDownloader.cpp
+++ b/media/libstagefright/httplive/HTTPDownloader.cpp
@@ -31,6 +31,7 @@
#include <openssl/aes.h>
#include <openssl/md5.h>
#include <utils/Mutex.h>
+#include <inttypes.h>
namespace android {
@@ -165,7 +166,10 @@
size_t maxBytesToRead = bufferRemaining;
if (range_length >= 0) {
int64_t bytesLeftInRange = range_length - buffer->size();
- if (bytesLeftInRange < (int64_t)maxBytesToRead) {
+ if (bytesLeftInRange < 0) {
+ ALOGE("range_length %" PRId64 " wrapped around", range_length);
+ return ERROR_OUT_OF_RANGE;
+ } else if (bytesLeftInRange < (int64_t)maxBytesToRead) {
maxBytesToRead = bytesLeftInRange;
if (bytesLeftInRange == 0) {
@@ -237,7 +241,7 @@
// MD5 functionality is not available on the simulator, treat all
// playlists as changed.
-#if defined(HAVE_ANDROID_OS)
+#if defined(__ANDROID__)
uint8_t hash[16];
MD5_CTX m;
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 1557401..cebf95c 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -477,7 +477,7 @@
sp<MetaData> meta = packetSource->getFormat();
if (meta == NULL) {
- return -EAGAIN;
+ return -EWOULDBLOCK;
}
if (stream == STREAMTYPE_AUDIO) {
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 72d832e..37847e3 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -1628,7 +1628,8 @@
if (mSegmentFirstPTS < 0ll) {
// get the smallest first PTS from all streams present in this parser
- for (size_t i = mPacketSources.size(); i-- > 0;) {
+ for (size_t i = mPacketSources.size(); i > 0;) {
+ i--;
const LiveSession::StreamType stream = mPacketSources.keyAt(i);
if (stream == LiveSession::STREAMTYPE_SUBTITLES) {
ALOGE("MPEG2 Transport streams do not contain subtitles.");
@@ -1683,7 +1684,8 @@
}
status_t err = OK;
- for (size_t i = mPacketSources.size(); i-- > 0;) {
+ for (size_t i = mPacketSources.size(); i > 0;) {
+ i--;
sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
const LiveSession::StreamType stream = mPacketSources.keyAt(i);
@@ -1807,7 +1809,8 @@
}
if (err != OK) {
- for (size_t i = mPacketSources.size(); i-- > 0;) {
+ for (size_t i = mPacketSources.size(); i > 0;) {
+ i--;
sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
packetSource->clear();
}
@@ -1902,6 +1905,9 @@
while (!it.done()) {
size_t length;
const uint8_t *data = it.getData(&length);
+ if (!data) {
+ return ERROR_MALFORMED;
+ }
static const char *kMatchName =
"com.apple.streaming.transportStreamTimestamp";
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index 68bd017..2cfba44 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -6,6 +6,7 @@
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_MODULE := libstagefright_id3
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 4410579..35691b9 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -618,6 +618,11 @@
return NULL;
}
+ // Prevent integer underflow
+ if (mFrameSize < getHeaderLength()) {
+ return NULL;
+ }
+
*length = mFrameSize - getHeaderLength();
return mFrameData;
@@ -832,6 +837,9 @@
while (!it.done()) {
size_t size;
const uint8_t *data = it.getData(&size);
+ if (!data) {
+ return NULL;
+ }
if (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) {
uint8_t encoding = data[0];
diff --git a/media/libstagefright/include/AACEncoder.h b/media/libstagefright/include/AACEncoder.h
index 52beb0e..462e905 100644
--- a/media/libstagefright/include/AACEncoder.h
+++ b/media/libstagefright/include/AACEncoder.h
@@ -27,9 +27,9 @@
class MediaBufferGroup;
-class AACEncoder: public MediaSource {
+class AACEncoder: public BnMediaSource {
public:
- AACEncoder(const sp<MediaSource> &source, const sp<MetaData> &meta);
+ AACEncoder(const sp<IMediaSource> &source, const sp<MetaData> &meta);
virtual status_t start(MetaData *params);
virtual status_t stop();
@@ -42,7 +42,7 @@
virtual ~AACEncoder();
private:
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
sp<MetaData> mMeta;
bool mStarted;
MediaBufferGroup *mBufferGroup;
diff --git a/media/libstagefright/include/AACExtractor.h b/media/libstagefright/include/AACExtractor.h
index e98ca82..e231e62 100644
--- a/media/libstagefright/include/AACExtractor.h
+++ b/media/libstagefright/include/AACExtractor.h
@@ -32,7 +32,7 @@
AACExtractor(const sp<DataSource> &source, const sp<AMessage> &meta);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h
index 4a1c827..0770397 100644
--- a/media/libstagefright/include/AMRExtractor.h
+++ b/media/libstagefright/include/AMRExtractor.h
@@ -32,7 +32,7 @@
AMRExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
deleted file mode 100644
index 758b2c9..0000000
--- a/media/libstagefright/include/AwesomePlayer.h
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AWESOME_PLAYER_H_
-
-#define AWESOME_PLAYER_H_
-
-#include "HTTPBase.h"
-#include "TimedEventQueue.h"
-
-#include <media/AudioResamplerPublic.h>
-#include <media/MediaPlayerInterface.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/TimeSource.h>
-#include <media/stagefright/MetaData.h>
-#include <utils/threads.h>
-#include <drm/DrmManagerClient.h>
-
-namespace android {
-
-class AudioPlayer;
-struct ClockEstimator;
-class IDataSource;
-class MediaBuffer;
-struct MediaExtractor;
-struct MediaSource;
-struct NuCachedSource2;
-class IGraphicBufferProducer;
-
-class DrmManagerClinet;
-class DecryptHandle;
-
-class TimedTextDriver;
-class WVMExtractor;
-
-struct AwesomeRenderer : public RefBase {
- AwesomeRenderer() {}
-
- virtual void render(MediaBuffer *buffer) = 0;
-
-private:
- AwesomeRenderer(const AwesomeRenderer &);
- AwesomeRenderer &operator=(const AwesomeRenderer &);
-};
-
-struct AwesomePlayer {
- AwesomePlayer();
- ~AwesomePlayer();
-
- void setListener(const wp<MediaPlayerBase> &listener);
- void setUID(uid_t uid);
-
- status_t setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers = NULL);
-
- status_t setDataSource(int fd, int64_t offset, int64_t length);
-
- status_t setDataSource(const sp<IStreamSource> &source);
-
- void reset();
-
- status_t prepare();
- status_t prepare_l();
- status_t prepareAsync();
- status_t prepareAsync_l();
-
- status_t play();
- status_t pause();
-
- bool isPlaying() const;
-
- status_t setSurfaceTexture(const sp<IGraphicBufferProducer> &bufferProducer);
- void setAudioSink(const sp<MediaPlayerBase::AudioSink> &audioSink);
- status_t setLooping(bool shouldLoop);
-
- status_t getDuration(int64_t *durationUs);
- status_t getPosition(int64_t *positionUs);
-
- status_t setParameter(int key, const Parcel &request);
- status_t getParameter(int key, Parcel *reply);
- status_t setPlaybackSettings(const AudioPlaybackRate &rate);
- status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
- status_t invoke(const Parcel &request, Parcel *reply);
- status_t setCacheStatCollectFreq(const Parcel &request);
-
- status_t seekTo(int64_t timeUs);
-
- // This is a mask of MediaExtractor::Flags.
- uint32_t flags() const;
-
- void postAudioEOS(int64_t delayUs = 0ll);
- void postAudioSeekComplete();
- void postAudioTearDown();
- status_t dump(int fd, const Vector<String16> &args) const;
-
-private:
- friend struct AwesomeEvent;
- friend struct PreviewPlayer;
-
- enum {
- PLAYING = 0x01,
- LOOPING = 0x02,
- FIRST_FRAME = 0x04,
- PREPARING = 0x08,
- PREPARED = 0x10,
- AT_EOS = 0x20,
- PREPARE_CANCELLED = 0x40,
- CACHE_UNDERRUN = 0x80,
- AUDIO_AT_EOS = 0x0100,
- VIDEO_AT_EOS = 0x0200,
- AUTO_LOOPING = 0x0400,
-
- // We are basically done preparing but are currently buffering
- // sufficient data to begin playback and finish the preparation phase
- // for good.
- PREPARING_CONNECTED = 0x0800,
-
- // We're triggering a single video event to display the first frame
- // after the seekpoint.
- SEEK_PREVIEW = 0x1000,
-
- AUDIO_RUNNING = 0x2000,
- AUDIOPLAYER_STARTED = 0x4000,
-
- INCOGNITO = 0x8000,
-
- TEXT_RUNNING = 0x10000,
- TEXTPLAYER_INITIALIZED = 0x20000,
-
- SLOW_DECODER_HACK = 0x40000,
- };
-
- mutable Mutex mLock;
- Mutex mMiscStateLock;
- mutable Mutex mStatsLock;
- Mutex mAudioLock;
-
- OMXClient mClient;
- TimedEventQueue mQueue;
- bool mQueueStarted;
- wp<MediaPlayerBase> mListener;
- bool mUIDValid;
- uid_t mUID;
-
- sp<ANativeWindow> mNativeWindow;
- sp<MediaPlayerBase::AudioSink> mAudioSink;
-
- SystemTimeSource mSystemTimeSource;
- TimeSource *mTimeSource;
-
- sp<IMediaHTTPService> mHTTPService;
- String8 mUri;
- KeyedVector<String8, String8> mUriHeaders;
-
- sp<DataSource> mFileSource;
-
- sp<MediaSource> mVideoTrack;
- sp<MediaSource> mVideoSource;
- sp<AwesomeRenderer> mVideoRenderer;
- bool mVideoRenderingStarted;
- bool mVideoRendererIsPreview;
- int32_t mMediaRenderingStartGeneration;
- int32_t mStartGeneration;
-
- ssize_t mActiveAudioTrackIndex;
- sp<MediaSource> mAudioTrack;
- sp<MediaSource> mOmxSource;
- sp<MediaSource> mAudioSource;
- AudioPlayer *mAudioPlayer;
- AudioPlaybackRate mPlaybackSettings;
- int64_t mDurationUs;
-
- int32_t mDisplayWidth;
- int32_t mDisplayHeight;
- int32_t mVideoScalingMode;
-
- uint32_t mFlags;
- uint32_t mExtractorFlags;
- uint32_t mSinceLastDropped;
-
- int64_t mTimeSourceDeltaUs;
- int64_t mVideoTimeUs;
-
- enum SeekType {
- NO_SEEK,
- SEEK,
- SEEK_VIDEO_ONLY
- };
- SeekType mSeeking;
-
- bool mSeekNotificationSent;
- int64_t mSeekTimeUs;
-
- int64_t mBitrate; // total bitrate of the file (in bps) or -1 if unknown.
-
- bool mWatchForAudioSeekComplete;
- bool mWatchForAudioEOS;
-
- sp<TimedEventQueue::Event> mVideoEvent;
- bool mVideoEventPending;
- sp<TimedEventQueue::Event> mStreamDoneEvent;
- bool mStreamDoneEventPending;
- sp<TimedEventQueue::Event> mBufferingEvent;
- bool mBufferingEventPending;
- sp<TimedEventQueue::Event> mCheckAudioStatusEvent;
- bool mAudioStatusEventPending;
- sp<TimedEventQueue::Event> mVideoLagEvent;
- bool mVideoLagEventPending;
- sp<TimedEventQueue::Event> mAudioTearDownEvent;
- bool mAudioTearDownEventPending;
- sp<TimedEventQueue::Event> mAsyncPrepareEvent;
- Condition mPreparedCondition;
- bool mIsAsyncPrepare;
- status_t mPrepareResult;
- status_t mStreamDoneStatus;
-
- void postVideoEvent_l(int64_t delayUs = -1);
- void postBufferingEvent_l();
- void postStreamDoneEvent_l(status_t status);
- void postCheckAudioStatusEvent(int64_t delayUs);
- void postVideoLagEvent_l();
- void postAudioTearDownEvent(int64_t delayUs);
-
- status_t play_l();
-
- MediaBuffer *mVideoBuffer;
-
- sp<ClockEstimator> mClockEstimator;
- sp<HTTPBase> mConnectingDataSource;
- sp<NuCachedSource2> mCachedSource;
-
- DrmManagerClient *mDrmManagerClient;
- sp<DecryptHandle> mDecryptHandle;
-
- int64_t mLastVideoTimeUs;
- TimedTextDriver *mTextDriver;
-
- sp<WVMExtractor> mWVMExtractor;
- sp<MediaExtractor> mExtractor;
-
- status_t setDataSource_l(
- const sp<IMediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers = NULL);
-
- status_t setDataSource_l(const sp<DataSource> &dataSource);
- status_t setDataSource_l(const sp<MediaExtractor> &extractor);
- void reset_l();
- status_t seekTo_l(int64_t timeUs);
- status_t pause_l(bool at_eos = false);
- void initRenderer_l();
- void notifyVideoSize_l();
- void seekAudioIfNecessary_l();
-
- void cancelPlayerEvents(bool keepNotifications = false);
-
- void setAudioSource(sp<MediaSource> source);
- status_t initAudioDecoder();
-
-
- void setVideoSource(sp<MediaSource> source);
- status_t initVideoDecoder(uint32_t flags = 0);
-
- void addTextSource_l(size_t trackIndex, const sp<MediaSource>& source);
-
- void onStreamDone();
-
- void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0);
-
- void onVideoEvent();
- void onBufferingUpdate();
- void onCheckAudioStatus();
- void onPrepareAsyncEvent();
- void abortPrepare(status_t err);
- void finishAsyncPrepare_l();
- void onVideoLagUpdate();
- void onAudioTearDownEvent();
-
- void beginPrepareAsync_l();
-
- bool getCachedDuration_l(int64_t *durationUs, bool *eos);
-
- status_t finishSetDataSource_l();
-
- static bool ContinuePreparation(void *cookie);
-
- bool getBitrate(int64_t *bitrate);
-
- int64_t estimateRealTimeUs(TimeSource *ts, int64_t systemTimeUs);
- void finishSeekIfNecessary(int64_t videoTimeUs);
- void ensureCacheIsFetching_l();
-
- void notifyIfMediaStarted_l();
- void createAudioPlayer_l();
- status_t startAudioPlayer_l(bool sendErrorNotification = true);
-
- void shutdownVideoDecoder_l();
- status_t setNativeWindow_l(const sp<ANativeWindow> &native);
-
- bool isStreamingHTTP() const;
- void sendCacheStats();
- void checkDrmStatus(const sp<DataSource>& dataSource);
-
- enum FlagMode {
- SET,
- CLEAR,
- ASSIGN
- };
- void modifyFlags(unsigned value, FlagMode mode);
-
- struct TrackStat {
- String8 mMIME;
- String8 mDecoderName;
- };
-
- // protected by mStatsLock
- struct Stats {
- int mFd;
- String8 mURI;
- int64_t mBitrate;
-
- // FIXME:
- // These two indices are just 0 or 1 for now
- // They are not representing the actual track
- // indices in the stream.
- ssize_t mAudioTrackIndex;
- ssize_t mVideoTrackIndex;
-
- int64_t mNumVideoFramesDecoded;
- int64_t mNumVideoFramesDropped;
- int32_t mVideoWidth;
- int32_t mVideoHeight;
- uint32_t mFlags;
- Vector<TrackStat> mTracks;
- } mStats;
-
- bool mOffloadAudio;
- bool mAudioTearDown;
- bool mAudioTearDownWasPlaying;
- int64_t mAudioTearDownPosition;
-
- status_t setVideoScalingMode(int32_t mode);
- status_t setVideoScalingMode_l(int32_t mode);
- status_t getTrackInfo(Parcel* reply) const;
-
- status_t selectAudioTrack_l(const sp<MediaSource>& source, size_t trackIndex);
-
- // when select is true, the given track is selected.
- // otherwise, the given track is unselected.
- status_t selectTrack(size_t trackIndex, bool select);
-
- size_t countTracks() const;
-
- AwesomePlayer(const AwesomePlayer &);
- AwesomePlayer &operator=(const AwesomePlayer &);
-};
-
-} // namespace android
-
-#endif // AWESOME_PLAYER_H_
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index 1a21dd3..8c6fd8f 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -36,6 +36,7 @@
virtual status_t initCheck() const;
virtual ssize_t readAt(off64_t offset, void *data, size_t size);
virtual status_t getSize(off64_t *size);
+ virtual uint32_t flags();
private:
sp<IDataSource> mIDataSource;
diff --git a/media/libstagefright/include/DRMExtractor.h b/media/libstagefright/include/DRMExtractor.h
index b4e4afb..a035d8c 100644
--- a/media/libstagefright/include/DRMExtractor.h
+++ b/media/libstagefright/include/DRMExtractor.h
@@ -18,6 +18,7 @@
#define DRM_EXTRACTOR_H_
+#include <media/IMediaSource.h>
#include <media/stagefright/MediaExtractor.h>
#include <drm/DrmManagerClient.h>
@@ -34,7 +35,7 @@
DRMExtractor(const sp<DataSource> &source, const char *mime);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
@@ -44,7 +45,7 @@
private:
sp<DataSource> mDataSource;
- sp<MediaExtractor> mOriginalExtractor;
+ sp<IMediaExtractor> mOriginalExtractor;
sp<DecryptHandle> mDecryptHandle;
DrmManagerClient* mDrmManagerClient;
diff --git a/media/libstagefright/include/FLACExtractor.h b/media/libstagefright/include/FLACExtractor.h
index ded91c2..a6e6c1d 100644
--- a/media/libstagefright/include/FLACExtractor.h
+++ b/media/libstagefright/include/FLACExtractor.h
@@ -32,7 +32,7 @@
FLACExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/HevcUtils.h b/media/libstagefright/include/HevcUtils.h
new file mode 100644
index 0000000..0d7bb2f
--- /dev/null
+++ b/media/libstagefright/include/HevcUtils.h
@@ -0,0 +1,93 @@
+/*
+ * 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 HEVC_UTILS_H_
+
+#define HEVC_UTILS_H_
+
+#include <stdint.h>
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+enum {
+ kHevcNalUnitTypeVps = 32,
+ kHevcNalUnitTypeSps = 33,
+ kHevcNalUnitTypePps = 34,
+ kHevcNalUnitTypePrefixSei = 39,
+ kHevcNalUnitTypeSuffixSei = 40,
+};
+
+enum {
+ // uint8_t
+ kGeneralProfileSpace,
+ // uint8_t
+ kGeneralTierFlag,
+ // uint8_t
+ kGeneralProfileIdc,
+ // uint32_t
+ kGeneralProfileCompatibilityFlags,
+ // uint64_t
+ kGeneralConstraintIndicatorFlags,
+ // uint8_t
+ kGeneralLevelIdc,
+ // uint8_t
+ kChromaFormatIdc,
+ // uint8_t
+ kBitDepthLumaMinus8,
+ // uint8_t
+ kBitDepthChromaMinus8,
+};
+
+class HevcParameterSets {
+public:
+ HevcParameterSets();
+
+ status_t addNalUnit(const uint8_t* data, size_t size);
+
+ bool findParam8(uint32_t key, uint8_t *param);
+ bool findParam16(uint32_t key, uint16_t *param);
+ bool findParam32(uint32_t key, uint32_t *param);
+ bool findParam64(uint32_t key, uint64_t *param);
+
+ inline size_t getNumNalUnits() { return mNalUnits.size(); }
+ size_t getNumNalUnitsOfType(uint8_t type);
+ uint8_t getType(size_t index);
+ size_t getSize(size_t index);
+ // Note that this method does not write the start code.
+ bool write(size_t index, uint8_t* dest, size_t size);
+ status_t makeHvcc(uint8_t *hvcc, size_t *hvccSize, size_t nalSizeLength);
+
+private:
+ status_t parseVps(const uint8_t* data, size_t size);
+ status_t parseSps(const uint8_t* data, size_t size);
+ status_t parsePps(const uint8_t* data, size_t size);
+
+ KeyedVector<uint32_t, uint64_t> mParams;
+ Vector<sp<ABuffer>> mNalUnits;
+
+ DISALLOW_EVIL_CONSTRUCTORS(HevcParameterSets);
+};
+
+} // namespace android
+
+#endif // HEVC_UTILS_H_
diff --git a/media/libstagefright/include/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h
index c83d9e80..2fd04f2 100644
--- a/media/libstagefright/include/MP3Extractor.h
+++ b/media/libstagefright/include/MP3Extractor.h
@@ -34,10 +34,11 @@
MP3Extractor(const sp<DataSource> &source, const sp<AMessage> &meta);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
+ virtual const char * name() { return "MP3Extractor"; }
private:
status_t mInitCheck;
diff --git a/media/libstagefright/include/MPEG2PSExtractor.h b/media/libstagefright/include/MPEG2PSExtractor.h
index 22cb02d..e815f0e 100644
--- a/media/libstagefright/include/MPEG2PSExtractor.h
+++ b/media/libstagefright/include/MPEG2PSExtractor.h
@@ -34,7 +34,7 @@
MPEG2PSExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index 8eb8f6c..9907572 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -38,7 +38,7 @@
MPEG2TSExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index 3067c3d..cff976d 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -53,7 +53,7 @@
MPEG4Extractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/MidiExtractor.h b/media/libstagefright/include/MidiExtractor.h
index 9a2abc0..333277b 100644
--- a/media/libstagefright/include/MidiExtractor.h
+++ b/media/libstagefright/include/MidiExtractor.h
@@ -56,7 +56,7 @@
MidiExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index e7c4f6d..c715939 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -36,7 +36,9 @@
virtual status_t listNodes(List<ComponentInfo> *list);
virtual status_t allocateNode(
- const char *name, const sp<IOMXObserver> &observer, node_id *node);
+ const char *name, const sp<IOMXObserver> &observer,
+ sp<IBinder> *nodeBinder,
+ node_id *node);
virtual status_t freeNode(node_id node);
@@ -62,8 +64,8 @@
virtual status_t getState(
node_id node, OMX_STATETYPE* state);
- virtual status_t enableGraphicBuffers(
- node_id node, OMX_U32 port_index, OMX_BOOL enable);
+ virtual status_t enableNativeBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL graphic, OMX_BOOL enable);
virtual status_t getGraphicBufferUsage(
node_id node, OMX_U32 port_index, OMX_U32* usage);
@@ -107,9 +109,9 @@
virtual status_t signalEndOfInputStream(node_id node);
- virtual status_t allocateBuffer(
+ virtual status_t allocateSecureBuffer(
node_id node, OMX_U32 port_index, size_t size,
- buffer_id *buffer, void **buffer_data);
+ buffer_id *buffer, void **buffer_data, native_handle_t **native_handle);
virtual status_t allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
@@ -166,13 +168,13 @@
Mutex mLock;
OMXMaster *mMaster;
- int32_t mNodeCounter;
+ size_t mNodeCounter;
KeyedVector<wp<IBinder>, OMXNodeInstance *> mLiveNodes;
KeyedVector<node_id, OMXNodeInstance *> mNodeIDToInstance;
KeyedVector<node_id, sp<CallbackDispatcher> > mDispatchers;
- node_id makeNodeID(OMXNodeInstance *instance);
+ node_id makeNodeID_l(OMXNodeInstance *instance);
OMXNodeInstance *findInstance(node_id node);
sp<CallbackDispatcher> findDispatcher(node_id node);
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index e5fb45b..732894c 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -54,7 +54,7 @@
status_t getState(OMX_STATETYPE* state);
- status_t enableGraphicBuffers(OMX_U32 portIndex, OMX_BOOL enable);
+ status_t enableNativeBuffers(OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable);
status_t getGraphicBufferUsage(OMX_U32 portIndex, OMX_U32* usage);
@@ -95,9 +95,9 @@
status_t signalEndOfInputStream();
- status_t allocateBuffer(
+ status_t allocateSecureBuffer(
OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
- void **buffer_data);
+ void **buffer_data, native_handle_t **native_handle);
status_t allocateBufferWithBackup(
OMX_U32 portIndex, const sp<IMemory> ¶ms,
@@ -165,7 +165,15 @@
uint32_t mBufferIDCount;
KeyedVector<OMX::buffer_id, OMX_BUFFERHEADERTYPE *> mBufferIDToBufferHeader;
KeyedVector<OMX_BUFFERHEADERTYPE *, OMX::buffer_id> mBufferHeaderToBufferID;
+
+ // metadata and secure buffer type tracking
MetadataBufferType mMetadataType[2];
+ enum SecureBufferType {
+ kSecureBufferTypeUnknown,
+ kSecureBufferTypeOpaque,
+ kSecureBufferTypeNativeHandle,
+ };
+ SecureBufferType mSecureBufferType[2];
// For debug support
char *mName;
diff --git a/media/libstagefright/include/OggExtractor.h b/media/libstagefright/include/OggExtractor.h
index c647cbb..592c264 100644
--- a/media/libstagefright/include/OggExtractor.h
+++ b/media/libstagefright/include/OggExtractor.h
@@ -34,10 +34,11 @@
OggExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
+ virtual const char * name() { return "OggExtractor"; }
protected:
virtual ~OggExtractor();
diff --git a/media/libstagefright/include/SampleIterator.h b/media/libstagefright/include/SampleIterator.h
index 7053247..2ef41ae 100644
--- a/media/libstagefright/include/SampleIterator.h
+++ b/media/libstagefright/include/SampleIterator.h
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#ifndef SAMPLE_ITERATOR_H_
+
+#define SAMPLE_ITERATOR_H_
+
#include <utils/Vector.h>
namespace android {
@@ -75,3 +79,4 @@
} // namespace android
+#endif // SAMPLE_ITERATOR_H_
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index fd739d0..b7ac718 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -18,9 +18,9 @@
#define STAGEFRIGHT_METADATA_RETRIEVER_H_
+#include <media/IMediaExtractor.h>
#include <media/MediaMetadataRetrieverInterface.h>
-#include <media/stagefright/OMXClient.h>
#include <utils/KeyedVector.h>
namespace android {
@@ -45,9 +45,8 @@
virtual const char *extractMetadata(int keyCode);
private:
- OMXClient mClient;
sp<DataSource> mSource;
- sp<MediaExtractor> mExtractor;
+ sp<IMediaExtractor> mExtractor;
bool mParsedMetaData;
KeyedVector<int, String8> mMetaData;
diff --git a/media/libstagefright/include/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h
deleted file mode 100644
index 890f7e8..0000000
--- a/media/libstagefright/include/TimedEventQueue.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TIMED_EVENT_QUEUE_H_
-
-#define TIMED_EVENT_QUEUE_H_
-
-#include <pthread.h>
-
-#include <utils/List.h>
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-#include <powermanager/IPowerManager.h>
-
-namespace android {
-
-struct TimedEventQueue {
-
- typedef int32_t event_id;
-
- struct Event : public RefBase {
- Event()
- : mEventID(0) {
- }
-
- virtual ~Event() {}
-
- event_id eventID() {
- return mEventID;
- }
-
- protected:
- virtual void fire(TimedEventQueue *queue, int64_t now_us) = 0;
-
- private:
- friend struct TimedEventQueue;
-
- event_id mEventID;
-
- void setEventID(event_id id) {
- mEventID = id;
- }
-
- Event(const Event &);
- Event &operator=(const Event &);
- };
-
- class PMDeathRecipient : public IBinder::DeathRecipient {
- public:
- PMDeathRecipient(TimedEventQueue *queue) : mQueue(queue) {}
- virtual ~PMDeathRecipient() {}
-
- // IBinder::DeathRecipient
- virtual void binderDied(const wp<IBinder>& who);
-
- private:
- PMDeathRecipient(const PMDeathRecipient&);
- PMDeathRecipient& operator = (const PMDeathRecipient&);
-
- TimedEventQueue *mQueue;
- };
-
- TimedEventQueue();
- ~TimedEventQueue();
-
- // Start executing the event loop.
- void start();
-
- // Stop executing the event loop, if flush is false, any pending
- // events are discarded, otherwise the queue will stop (and this call
- // return) once all pending events have been handled.
- void stop(bool flush = false);
-
- // Posts an event to the front of the queue (after all events that
- // have previously been posted to the front but before timed events).
- event_id postEvent(const sp<Event> &event);
-
- event_id postEventToBack(const sp<Event> &event);
-
- // It is an error to post an event with a negative delay.
- event_id postEventWithDelay(const sp<Event> &event, int64_t delay_us);
-
- // If the event is to be posted at a time that has already passed,
- // it will fire as soon as possible.
- event_id postTimedEvent(const sp<Event> &event, int64_t realtime_us);
-
- // Returns true iff event is currently in the queue and has been
- // successfully cancelled. In this case the event will have been
- // removed from the queue and won't fire.
- bool cancelEvent(event_id id);
-
- // Cancel any pending event that satisfies the predicate.
- // If stopAfterFirstMatch is true, only cancels the first event
- // satisfying the predicate (if any).
- void cancelEvents(
- bool (*predicate)(void *cookie, const sp<Event> &event),
- void *cookie,
- bool stopAfterFirstMatch = false);
-
- static int64_t getRealTimeUs();
-
- void clearPowerManager();
-
-private:
- struct QueueItem {
- sp<Event> event;
- int64_t realtime_us;
- bool has_wakelock;
- };
-
- struct StopEvent : public TimedEventQueue::Event {
- virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
- queue->mStopped = true;
- }
- };
-
- pthread_t mThread;
- List<QueueItem> mQueue;
- Mutex mLock;
- Condition mQueueNotEmptyCondition;
- Condition mQueueHeadChangedCondition;
- event_id mNextEventID;
-
- bool mRunning;
- bool mStopped;
-
- sp<IPowerManager> mPowerManager;
- sp<IBinder> mWakeLockToken;
- const sp<PMDeathRecipient> mDeathRecipient;
- uint32_t mWakeLockCount;
-
- static void *ThreadWrapper(void *me);
- void threadEntry();
-
- sp<Event> removeEventFromQueue_l(event_id id, bool *wakeLocked);
-
- void acquireWakeLock_l();
- void releaseWakeLock_l(bool force = false);
-
- TimedEventQueue(const TimedEventQueue &);
- TimedEventQueue &operator=(const TimedEventQueue &);
-};
-
-} // namespace android
-
-#endif // TIMED_EVENT_QUEUE_H_
diff --git a/media/libstagefright/include/WAVExtractor.h b/media/libstagefright/include/WAVExtractor.h
index c567ccd..91ee870 100644
--- a/media/libstagefright/include/WAVExtractor.h
+++ b/media/libstagefright/include/WAVExtractor.h
@@ -33,10 +33,11 @@
WAVExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
+ virtual const char * name() { return "WAVExtractor"; }
protected:
virtual ~WAVExtractor();
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
index ab7e8b8..5b91072 100644
--- a/media/libstagefright/include/WVMExtractor.h
+++ b/media/libstagefright/include/WVMExtractor.h
@@ -46,7 +46,7 @@
WVMExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
virtual void setUID(uid_t uid);
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index 1e8c2b2..b0cbf08 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -7,9 +7,11 @@
LOCAL_C_INCLUDES:= \
$(TOP)/external/libvpx/libwebm \
$(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/frameworks/av/media/libstagefright/include \
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_MODULE:= libstagefright_matroska
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index ecc2573..861bdc5 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -19,9 +19,11 @@
#include <utils/Log.h>
#include "MatroskaExtractor.h"
+#include "avc_utils.h"
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
@@ -144,12 +146,13 @@
Type mType;
bool mIsAudio;
BlockIterator mBlockIter;
- size_t mNALSizeLen; // for type AVC
+ ssize_t mNALSizeLen; // for type AVC
List<MediaBuffer *> mPendingFrames;
status_t advance();
+ status_t setWebmBlockCryptoInfo(MediaBuffer *mbuf);
status_t readBlock();
void clearPendingFrames();
@@ -213,7 +216,7 @@
mBlockIter(mExtractor.get(),
mExtractor->mTracks.itemAt(index).mTrackNum,
index),
- mNALSizeLen(0) {
+ mNALSizeLen(-1) {
sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta;
const char *mime;
@@ -227,13 +230,18 @@
uint32_t dummy;
const uint8_t *avcc;
size_t avccSize;
- CHECK(meta->findData(
- kKeyAVCC, &dummy, (const void **)&avcc, &avccSize));
-
- CHECK_GE(avccSize, 5u);
-
- mNALSizeLen = 1 + (avcc[4] & 3);
- ALOGV("mNALSizeLen = %zu", mNALSizeLen);
+ int32_t nalSizeLen = 0;
+ if (meta->findInt32(kKeyNalLengthSize, &nalSizeLen)) {
+ if (nalSizeLen >= 0 && nalSizeLen <= 4) {
+ mNALSizeLen = nalSizeLen;
+ }
+ } else if (meta->findData(kKeyAVCC, &dummy, (const void **)&avcc, &avccSize)
+ && avccSize >= 5u) {
+ mNALSizeLen = 1 + (avcc[4] & 3);
+ ALOGV("mNALSizeLen = %zd", mNALSizeLen);
+ } else {
+ ALOGE("No mNALSizeLen");
+ }
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
mType = AAC;
}
@@ -244,6 +252,10 @@
}
status_t MatroskaSource::start(MetaData * /* params */) {
+ if (mType == AVC && mNALSizeLen < 0) {
+ return ERROR_MALFORMED;
+ }
+
mBlockIter.reset();
return OK;
@@ -492,6 +504,9 @@
}
int64_t BlockIterator::blockTimeUs() const {
+ if (mCluster == NULL || mBlockEntry == NULL) {
+ return -1;
+ }
return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll;
}
@@ -511,6 +526,72 @@
}
}
+status_t MatroskaSource::setWebmBlockCryptoInfo(MediaBuffer *mbuf) {
+ if (mbuf->range_length() < 1 || mbuf->range_length() - 1 > INT32_MAX) {
+ // 1-byte signal
+ return ERROR_MALFORMED;
+ }
+
+ const uint8_t *data = (const uint8_t *)mbuf->data() + mbuf->range_offset();
+ bool blockEncrypted = data[0] & 0x1;
+ if (blockEncrypted && mbuf->range_length() < 9) {
+ // 1-byte signal + 8-byte IV
+ return ERROR_MALFORMED;
+ }
+
+ sp<MetaData> meta = mbuf->meta_data();
+ if (blockEncrypted) {
+ /*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Signal Byte | |
+ * +-+-+-+-+-+-+-+-+ IV |
+ * | |
+ * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | |
+ * |-+-+-+-+-+-+-+-+ |
+ * : Bytes 1..N of encrypted frame :
+ * | |
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ int32_t plainSizes[] = { 0 };
+ int32_t encryptedSizes[] = { static_cast<int32_t>(mbuf->range_length() - 9) };
+ uint8_t ctrCounter[16] = { 0 };
+ uint32_t type;
+ const uint8_t *keyId;
+ size_t keyIdSize;
+ sp<MetaData> trackMeta = mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
+ CHECK(trackMeta->findData(kKeyCryptoKey, &type, (const void **)&keyId, &keyIdSize));
+ meta->setData(kKeyCryptoKey, 0, keyId, keyIdSize);
+ memcpy(ctrCounter, data + 1, 8);
+ meta->setData(kKeyCryptoIV, 0, ctrCounter, 16);
+ meta->setData(kKeyPlainSizes, 0, plainSizes, sizeof(plainSizes));
+ meta->setData(kKeyEncryptedSizes, 0, encryptedSizes, sizeof(encryptedSizes));
+ mbuf->set_range(9, mbuf->range_length() - 9);
+ } else {
+ /*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Signal Byte | |
+ * +-+-+-+-+-+-+-+-+ |
+ * : Bytes 1..N of unencrypted frame :
+ * | |
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ int32_t plainSizes[] = { static_cast<int32_t>(mbuf->range_length() - 1) };
+ int32_t encryptedSizes[] = { 0 };
+ meta->setData(kKeyPlainSizes, 0, plainSizes, sizeof(plainSizes));
+ meta->setData(kKeyEncryptedSizes, 0, encryptedSizes, sizeof(encryptedSizes));
+ mbuf->set_range(1, mbuf->range_length() - 1);
+ }
+
+ return OK;
+}
+
status_t MatroskaSource::readBlock() {
CHECK(mPendingFrames.empty());
@@ -529,12 +610,19 @@
mbuf->meta_data()->setInt64(kKeyTime, timeUs);
mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey());
- long n = frame.Read(mExtractor->mReader, (unsigned char *)mbuf->data());
- if (n != 0) {
+ status_t err = frame.Read(mExtractor->mReader, static_cast<uint8_t *>(mbuf->data()));
+ if (err == OK
+ && mExtractor->mIsWebm
+ && mExtractor->mTracks.itemAt(mTrackIndex).mEncrypted) {
+ err = setWebmBlockCryptoInfo(mbuf);
+ }
+
+ if (err != OK) {
mPendingFrames.clear();
mBlockIter.advance();
- return ERROR_IO;
+ mbuf->release();
+ return err;
}
mPendingFrames.push_back(mbuf);
@@ -581,7 +669,7 @@
MediaBuffer *frame = *mPendingFrames.begin();
mPendingFrames.erase(mPendingFrames.begin());
- if (mType != AVC) {
+ if (mType != AVC || mNALSizeLen == 0) {
if (targetSampleTimeUs >= 0ll) {
frame->meta_data()->setInt64(
kKeyTargetTime, targetSampleTimeUs);
@@ -597,6 +685,9 @@
// followed by a corresponding number of bytes containing the fragment.
// We output all these fragments into a single large buffer separated
// by startcodes (0x00 0x00 0x00 0x01).
+ //
+ // When mNALSizeLen is 0, we assume the data is already in the format
+ // desired.
const uint8_t *srcPtr =
(const uint8_t *)frame->data() + frame->range_offset();
@@ -633,9 +724,11 @@
if (pass == 1) {
memcpy(&dstPtr[dstOffset], "\x00\x00\x00\x01", 4);
- memcpy(&dstPtr[dstOffset + 4],
- &srcPtr[srcOffset + mNALSizeLen],
- NALsize);
+ if (frame != buffer) {
+ memcpy(&dstPtr[dstOffset + 4],
+ &srcPtr[srcOffset + mNALSizeLen],
+ NALsize);
+ }
}
dstOffset += 4; // 0x00 00 00 01
@@ -657,7 +750,13 @@
if (pass == 0) {
dstSize = dstOffset;
- buffer = new MediaBuffer(dstSize);
+ if (dstSize == srcSize && mNALSizeLen == 4) {
+ // In this special case we can re-use the input buffer by substituting
+ // each 4-byte nal size with a 4-byte start code
+ buffer = frame;
+ } else {
+ buffer = new MediaBuffer(dstSize);
+ }
int64_t timeUs;
CHECK(frame->meta_data()->findInt64(kKeyTime, &timeUs));
@@ -671,8 +770,10 @@
}
}
- frame->release();
- frame = NULL;
+ if (frame != buffer) {
+ frame->release();
+ frame = NULL;
+ }
if (targetSampleTimeUs >= 0ll) {
buffer->meta_data()->setInt64(
@@ -761,7 +862,7 @@
return mTracks.size();
}
-sp<MediaSource> MatroskaExtractor::getTrack(size_t index) {
+sp<IMediaSource> MatroskaExtractor::getTrack(size_t index) {
if (index >= mTracks.size()) {
return NULL;
}
@@ -928,6 +1029,35 @@
return OK;
}
+status_t MatroskaExtractor::synthesizeAVCC(TrackInfo *trackInfo, size_t index) {
+ BlockIterator iter(this, trackInfo->mTrackNum, index);
+ if (iter.eos()) {
+ return ERROR_MALFORMED;
+ }
+
+ const mkvparser::Block *block = iter.block();
+ if (block->GetFrameCount() <= 0) {
+ return ERROR_MALFORMED;
+ }
+
+ const mkvparser::Block::Frame &frame = block->GetFrame(0);
+ sp<ABuffer> abuf = new ABuffer(frame.len);
+ long n = frame.Read(mReader, abuf->data());
+ if (n != 0) {
+ return ERROR_MALFORMED;
+ }
+
+ sp<MetaData> avcMeta = MakeAVCCodecSpecificData(abuf);
+ if (avcMeta == NULL) {
+ return ERROR_MALFORMED;
+ }
+
+ // Override the synthesized nal length size, which is arbitrary
+ avcMeta->setInt32(kKeyNalLengthSize, 0);
+ trackInfo->mMeta = avcMeta;
+ return OK;
+}
+
void MatroskaExtractor::addTracks() {
const mkvparser::Tracks *tracks = mSegment->GetTracks();
@@ -1040,10 +1170,31 @@
meta->setInt64(kKeyDuration, (durationNs + 500) / 1000);
mTracks.push();
- TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1);
+ size_t n = mTracks.size() - 1;
+ TrackInfo *trackInfo = &mTracks.editItemAt(n);
trackInfo->mTrackNum = track->GetNumber();
trackInfo->mMeta = meta;
trackInfo->mExtractor = this;
+
+ trackInfo->mEncrypted = false;
+ for(size_t i = 0; i < track->GetContentEncodingCount() && !trackInfo->mEncrypted; i++) {
+ const mkvparser::ContentEncoding *encoding = track->GetContentEncodingByIndex(i);
+ for(size_t j = 0; j < encoding->GetEncryptionCount(); j++) {
+ const mkvparser::ContentEncoding::ContentEncryption *encryption;
+ encryption = encoding->GetEncryptionByIndex(j);
+ meta->setData(kKeyCryptoKey, 0, encryption->key_id, encryption->key_id_len);
+ trackInfo->mEncrypted = true;
+ break;
+ }
+ }
+
+ if (!strcmp("V_MPEG4/ISO/AVC", codecID) && codecPrivateSize == 0) {
+ // Attempt to recover from AVC track without codec private data
+ err = synthesizeAVCC(trackInfo, n);
+ if (err != OK) {
+ mTracks.pop();
+ }
+ }
}
}
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
index db36bf8..a1d6b00 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -37,7 +37,7 @@
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(
size_t index, uint32_t flags);
@@ -55,6 +55,7 @@
struct TrackInfo {
unsigned long mTrackNum;
+ bool mEncrypted;
sp<MetaData> mMeta;
const MatroskaExtractor *mExtractor;
Vector<const mkvparser::CuePoint*> mCuePoints;
@@ -74,6 +75,7 @@
bool mIsWebm;
int64_t mSeekPreRollNs;
+ status_t synthesizeAVCC(TrackInfo *trackInfo, size_t index);
void addTracks();
void findThumbnails();
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index e3c3e80..2790a0e 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -509,7 +509,7 @@
mLastRecoveredPTS = static_cast<int64_t>(PTS_33bit);
} else {
mLastRecoveredPTS = static_cast<int64_t>(
- ((mLastRecoveredPTS - PTS_33bit + 0x100000000ll)
+ ((mLastRecoveredPTS - static_cast<int64_t>(PTS_33bit) + 0x100000000ll)
& 0xfffffffe00000000ull) | PTS_33bit);
// We start from 0, but recovered PTS could be slightly below 0.
// Clamp it to 0 as rest of the pipeline doesn't take negative pts.
@@ -524,15 +524,10 @@
}
sp<MediaSource> ATSParser::Program::getSource(SourceType type) {
- size_t index = (type == AUDIO) ? 0 : 0;
-
for (size_t i = 0; i < mStreams.size(); ++i) {
sp<MediaSource> source = mStreams.editValueAt(i)->getSource(type);
if (source != NULL) {
- if (index == 0) {
- return source;
- }
- --index;
+ return source;
}
}
@@ -546,6 +541,8 @@
return true;
} else if (type == VIDEO && stream->isVideo()) {
return true;
+ } else if (type == META && stream->isMeta()) {
+ return true;
}
}
@@ -1499,23 +1496,38 @@
}
sp<MediaSource> ATSParser::getSource(SourceType type) {
- int which = -1; // any
-
+ sp<MediaSource> firstSourceFound;
for (size_t i = 0; i < mPrograms.size(); ++i) {
const sp<Program> &program = mPrograms.editItemAt(i);
-
- if (which >= 0 && (int)program->number() != which) {
+ sp<MediaSource> source = program->getSource(type);
+ if (source == NULL) {
continue;
}
+ if (firstSourceFound == NULL) {
+ firstSourceFound = source;
+ }
+ // Prefer programs with both audio/video
+ switch (type) {
+ case VIDEO: {
+ if (program->hasSource(AUDIO)) {
+ return source;
+ }
+ break;
+ }
- sp<MediaSource> source = program->getSource(type);
+ case AUDIO: {
+ if (program->hasSource(VIDEO)) {
+ return source;
+ }
+ break;
+ }
- if (source != NULL) {
- return source;
+ default:
+ return source;
}
}
- return NULL;
+ return firstSourceFound;
}
bool ATSParser::hasSource(SourceType type) const {
@@ -1537,6 +1549,7 @@
return mPrograms.editItemAt(0)->PTSTimeDeltaEstablished();
}
+__attribute__((no_sanitize("integer")))
void ATSParser::updatePCR(
unsigned /* PID */, uint64_t PCR, size_t byteOffsetFromStart) {
ALOGV("PCR 0x%016" PRIx64 " @ %zu", PCR, byteOffsetFromStart);
@@ -1555,6 +1568,7 @@
++mNumPCRs;
if (mNumPCRs == 2) {
+ /* Unsigned overflow here */
double transportRate =
(mPCRBytes[1] - mPCRBytes[0]) * 27E6 / (mPCR[1] - mPCR[0]);
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index 16b0160..70afde9 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -15,6 +15,7 @@
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_MODULE:= libstagefright_mpeg2ts
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index cabde32..4fcf7b5 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -216,6 +216,12 @@
mediaBuffer->meta_data()->setData(kKeySEI, 0, sei->data(), sei->size());
}
+ sp<ABuffer> mpegUserData;
+ if (buffer->meta()->findBuffer("mpegUserData", &mpegUserData) && mpegUserData != NULL) {
+ mediaBuffer->meta_data()->setData(
+ kKeyMpegUserData, 0, mpegUserData->data(), mpegUserData->size());
+ }
+
*out = mediaBuffer;
return OK;
}
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 36ec367..daf6b3d 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -1047,6 +1047,8 @@
const uint8_t *data = mBuffer->data();
size_t size = mBuffer->size();
+ Vector<size_t> userDataPositions;
+
bool sawPictureStart = false;
int pprevStartCode = -1;
int prevStartCode = -1;
@@ -1121,11 +1123,19 @@
if (mFormat != NULL && currentStartCode == 0xb8) {
// GOP layer
+ if (offset + 7 >= size) {
+ ALOGE("Size too small");
+ return NULL;
+ }
gopFound = true;
isClosedGop = (data[offset + 7] & 0x40) != 0;
brokenLink = (data[offset + 7] & 0x20) != 0;
}
+ if (mFormat != NULL && currentStartCode == 0xb2) {
+ userDataPositions.add(offset);
+ }
+
if (mFormat != NULL && currentStartCode == 0x00) {
// Picture start
@@ -1159,6 +1169,19 @@
// hexdump(accessUnit->data(), accessUnit->size());
+ if (userDataPositions.size() > 0) {
+ sp<ABuffer> mpegUserData =
+ new ABuffer(userDataPositions.size() * sizeof(size_t));
+ if (mpegUserData != NULL && mpegUserData->data() != NULL) {
+ for (size_t i = 0; i < userDataPositions.size(); ++i) {
+ memcpy(
+ mpegUserData->data() + i * sizeof(size_t),
+ &userDataPositions[i], sizeof(size_t));
+ }
+ accessUnit->meta()->setBuffer("mpegUserData", mpegUserData);
+ }
+ }
+
return accessUnit;
}
}
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
index 6d9fe9d..078a5f0 100644
--- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
@@ -108,7 +108,8 @@
}
// Remove all tracks that were unable to determine their format.
- for (size_t i = mTracks.size(); i-- > 0;) {
+ for (size_t i = mTracks.size(); i > 0;) {
+ i--;
if (mTracks.valueAt(i)->getFormat() == NULL) {
mTracks.removeItemsAt(i);
}
@@ -124,7 +125,7 @@
return mTracks.size();
}
-sp<MediaSource> MPEG2PSExtractor::getTrack(size_t index) {
+sp<IMediaSource> MPEG2PSExtractor::getTrack(size_t index) {
if (index >= mTracks.size()) {
return NULL;
}
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index cbe9673..0b456c3 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -120,7 +120,7 @@
return mSourceImpls.size();
}
-sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) {
+sp<IMediaSource> MPEG2TSExtractor::getTrack(size_t index) {
if (index >= mSourceImpls.size()) {
return NULL;
}
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 5f0f567..804afe9 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -33,6 +33,7 @@
LOCAL_MODULE:= libstagefright_omx
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 1a7dc9d..acdc4b0 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -64,19 +64,19 @@
return;
}
- err = consumer->detachBuffer(bi.mBuf);
+ err = consumer->detachBuffer(bi.mSlot);
if (err != OK) {
ALOGE("PersistentProxyListener: detachBuffer failed (%d)", err);
return;
}
- err = consumer->attachBuffer(&bi.mBuf, bi.mGraphicBuffer);
+ err = consumer->attachBuffer(&bi.mSlot, bi.mGraphicBuffer);
if (err != OK) {
ALOGE("PersistentProxyListener: attachBuffer failed (%d)", err);
return;
}
- err = consumer->releaseBuffer(bi.mBuf, 0,
+ err = consumer->releaseBuffer(bi.mSlot, 0,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, bi.mFence);
if (err != OK) {
ALOGE("PersistentProxyListener: releaseBuffer failed (%d)", err);
@@ -382,7 +382,7 @@
// Find matching entry in our cached copy of the BufferQueue slots.
// If we find a match, release that slot. If we don't, the BufferQueue
// has dropped that GraphicBuffer, and there's nothing for us to release.
- int id = codecBuffer.mBuf;
+ int id = codecBuffer.mSlot;
sp<Fence> fence = new Fence(fenceFd);
if (mBufferSlot[id] != NULL &&
mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
@@ -476,7 +476,7 @@
++mNumBufferAcquired;
--mNumFramesAvailable;
- releaseBuffer(item.mBuf, item.mFrameNumber,
+ releaseBuffer(item.mSlot, item.mFrameNumber,
item.mGraphicBuffer, item.mFence);
}
return;
@@ -530,8 +530,8 @@
// If this is the first time we're seeing this buffer, add it to our
// slot table.
if (item.mGraphicBuffer != NULL) {
- ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf);
- mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+ ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mSlot);
+ mBufferSlot[item.mSlot] = item.mGraphicBuffer;
}
err = UNKNOWN_ERROR;
@@ -557,10 +557,10 @@
}
if (err != OK) {
- ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf);
- releaseBuffer(item.mBuf, item.mFrameNumber, item.mGraphicBuffer, item.mFence);
+ ALOGV("submitBuffer_l failed, releasing bq slot %d", item.mSlot);
+ releaseBuffer(item.mSlot, item.mFrameNumber, item.mGraphicBuffer, item.mFence);
} else {
- ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi);
+ ALOGV("buffer submitted (bq %d, cbi %d)", item.mSlot, cbi);
setLatestBuffer_l(item, dropped);
}
@@ -600,7 +600,7 @@
}
BufferItem item;
- item.mBuf = mLatestBufferId;
+ item.mSlot = mLatestBufferId;
item.mFrameNumber = mLatestBufferFrameNum;
item.mTimestamp = mRepeatLastFrameTimestamp;
item.mFence = mLatestBufferFence;
@@ -642,7 +642,7 @@
}
}
- mLatestBufferId = item.mBuf;
+ mLatestBufferId = item.mSlot;
mLatestBufferFrameNum = item.mFrameNumber;
mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
@@ -754,8 +754,8 @@
}
CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
- codecBuffer.mGraphicBuffer = mBufferSlot[item.mBuf];
- codecBuffer.mBuf = item.mBuf;
+ codecBuffer.mGraphicBuffer = mBufferSlot[item.mSlot];
+ codecBuffer.mSlot = item.mSlot;
codecBuffer.mFrameNumber = item.mFrameNumber;
OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader;
@@ -880,11 +880,11 @@
// If this is the first time we're seeing this buffer, add it to our
// slot table.
if (item.mGraphicBuffer != NULL) {
- ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mBuf);
- mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+ ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mSlot);
+ mBufferSlot[item.mSlot] = item.mGraphicBuffer;
}
- releaseBuffer(item.mBuf, item.mFrameNumber,
+ releaseBuffer(item.mSlot, item.mFrameNumber,
item.mGraphicBuffer, item.mFence);
}
return;
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 2f929d9..7150684 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -195,7 +195,7 @@
uint64_t mFrameNumber;
// buffer producer's buffer slot for buffer
- int mBuf;
+ int mSlot;
sp<GraphicBuffer> mGraphicBuffer;
};
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 7f357c9..6be289b 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -38,6 +38,9 @@
namespace android {
+// node ids are created by concatenating the pid with a 16-bit counter
+static size_t kMaxNodeInstances = (1 << 16);
+
////////////////////////////////////////////////////////////////////////////////
// This provides the underlying Thread used by CallbackDispatcher.
@@ -232,10 +235,19 @@
}
status_t OMX::allocateNode(
- const char *name, const sp<IOMXObserver> &observer, node_id *node) {
+ const char *name, const sp<IOMXObserver> &observer,
+ sp<IBinder> *nodeBinder, node_id *node) {
Mutex::Autolock autoLock(mLock);
*node = 0;
+ if (nodeBinder != NULL) {
+ *nodeBinder = NULL;
+ }
+
+ if (mNodeIDToInstance.size() == kMaxNodeInstances) {
+ // all possible node IDs are in use
+ return NO_MEMORY;
+ }
OMXNodeInstance *instance = new OMXNodeInstance(this, observer, name);
@@ -252,7 +264,7 @@
return StatusFromOMXError(err);
}
- *node = makeNodeID(instance);
+ *node = makeNodeID_l(instance);
mDispatchers.add(*node, new CallbackDispatcher(instance));
instance->setHandle(*node, handle);
@@ -266,6 +278,10 @@
status_t OMX::freeNode(node_id node) {
OMXNodeInstance *instance = findInstance(node);
+ if (instance == NULL) {
+ return OK;
+ }
+
{
Mutex::Autolock autoLock(mLock);
ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer()));
@@ -293,14 +309,26 @@
status_t OMX::sendCommand(
node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
- return findInstance(node)->sendCommand(cmd, param);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->sendCommand(cmd, param);
}
status_t OMX::getParameter(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size) {
ALOGV("getParameter(%u %#x %p %zd)", node, index, params, size);
- return findInstance(node)->getParameter(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getParameter(
index, params, size);
}
@@ -308,84 +336,162 @@
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) {
ALOGV("setParameter(%u %#x %p %zd)", node, index, params, size);
- return findInstance(node)->setParameter(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->setParameter(
index, params, size);
}
status_t OMX::getConfig(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size) {
- return findInstance(node)->getConfig(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getConfig(
index, params, size);
}
status_t OMX::setConfig(
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) {
- return findInstance(node)->setConfig(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->setConfig(
index, params, size);
}
status_t OMX::getState(
node_id node, OMX_STATETYPE* state) {
- return findInstance(node)->getState(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getState(
state);
}
-status_t OMX::enableGraphicBuffers(
- node_id node, OMX_U32 port_index, OMX_BOOL enable) {
- return findInstance(node)->enableGraphicBuffers(port_index, enable);
+status_t OMX::enableNativeBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL graphic, OMX_BOOL enable) {
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->enableNativeBuffers(port_index, graphic, enable);
}
status_t OMX::getGraphicBufferUsage(
node_id node, OMX_U32 port_index, OMX_U32* usage) {
- return findInstance(node)->getGraphicBufferUsage(port_index, usage);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getGraphicBufferUsage(port_index, usage);
}
status_t OMX::storeMetaDataInBuffers(
node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type) {
- return findInstance(node)->storeMetaDataInBuffers(port_index, enable, type);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->storeMetaDataInBuffers(port_index, enable, type);
}
status_t OMX::prepareForAdaptivePlayback(
node_id node, OMX_U32 portIndex, OMX_BOOL enable,
OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
- return findInstance(node)->prepareForAdaptivePlayback(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->prepareForAdaptivePlayback(
portIndex, enable, maxFrameWidth, maxFrameHeight);
}
status_t OMX::configureVideoTunnelMode(
node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
- return findInstance(node)->configureVideoTunnelMode(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->configureVideoTunnelMode(
portIndex, tunneled, audioHwSync, sidebandHandle);
}
status_t OMX::useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer, OMX_U32 allottedSize) {
- return findInstance(node)->useBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->useBuffer(
port_index, params, buffer, allottedSize);
}
status_t OMX::useGraphicBuffer(
node_id node, OMX_U32 port_index,
const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
- return findInstance(node)->useGraphicBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->useGraphicBuffer(
port_index, graphicBuffer, buffer);
}
status_t OMX::updateGraphicBufferInMeta(
node_id node, OMX_U32 port_index,
const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) {
- return findInstance(node)->updateGraphicBufferInMeta(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->updateGraphicBufferInMeta(
port_index, graphicBuffer, buffer);
}
status_t OMX::createInputSurface(
node_id node, OMX_U32 port_index,
sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
- return findInstance(node)->createInputSurface(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->createInputSurface(
port_index, bufferProducer, type);
}
@@ -399,35 +505,71 @@
status_t OMX::setInputSurface(
node_id node, OMX_U32 port_index,
const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) {
- return findInstance(node)->setInputSurface(port_index, bufferConsumer, type);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->setInputSurface(port_index, bufferConsumer, type);
}
status_t OMX::signalEndOfInputStream(node_id node) {
- return findInstance(node)->signalEndOfInputStream();
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->signalEndOfInputStream();
}
-status_t OMX::allocateBuffer(
+status_t OMX::allocateSecureBuffer(
node_id node, OMX_U32 port_index, size_t size,
- buffer_id *buffer, void **buffer_data) {
- return findInstance(node)->allocateBuffer(
- port_index, size, buffer, buffer_data);
+ buffer_id *buffer, void **buffer_data, native_handle_t **native_handle) {
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->allocateSecureBuffer(
+ port_index, size, buffer, buffer_data, native_handle);
}
status_t OMX::allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer, OMX_U32 allottedSize) {
- return findInstance(node)->allocateBufferWithBackup(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->allocateBufferWithBackup(
port_index, params, buffer, allottedSize);
}
status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
- return findInstance(node)->freeBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->freeBuffer(
port_index, buffer);
}
status_t OMX::fillBuffer(node_id node, buffer_id buffer, int fenceFd) {
- return findInstance(node)->fillBuffer(buffer, fenceFd);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->fillBuffer(buffer, fenceFd);
}
status_t OMX::emptyBuffer(
@@ -435,7 +577,13 @@
buffer_id buffer,
OMX_U32 range_offset, OMX_U32 range_length,
OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
- return findInstance(node)->emptyBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->emptyBuffer(
buffer, range_offset, range_length, flags, timestamp, fenceFd);
}
@@ -443,7 +591,13 @@
node_id node,
const char *parameter_name,
OMX_INDEXTYPE *index) {
- return findInstance(node)->getExtensionIndex(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getExtensionIndex(
parameter_name, index);
}
@@ -453,7 +607,13 @@
InternalOptionType type,
const void *data,
size_t size) {
- return findInstance(node)->setInternalOption(port_index, type, data, size);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->setInternalOption(port_index, type, data, size);
}
OMX_ERRORTYPE OMX::OnEvent(
@@ -463,9 +623,14 @@
OMX_IN OMX_U32 nData2,
OMX_IN OMX_PTR pEventData) {
ALOGV("OnEvent(%d, %" PRIu32", %" PRIu32 ")", eEvent, nData1, nData2);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return OMX_ErrorComponentNotFound;
+ }
// Forward to OMXNodeInstance.
- findInstance(node)->onEvent(eEvent, nData1, nData2);
+ instance->onEvent(eEvent, nData1, nData2);
sp<OMX::CallbackDispatcher> dispatcher = findDispatcher(node);
@@ -537,10 +702,17 @@
return OMX_ErrorNone;
}
-OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
+OMX::node_id OMX::makeNodeID_l(OMXNodeInstance *instance) {
// mLock is already held.
- node_id node = (node_id)++mNodeCounter;
+ node_id prefix = node_id(getpid() << 16);
+ node_id node = 0;
+ do {
+ if (++mNodeCounter >= kMaxNodeInstances) {
+ mNodeCounter = 0; // OK to use because we're combining with the pid
+ }
+ node = node_id(prefix | mNodeCounter);
+ } while (mNodeIDToInstance.indexOfKey(node) >= 0);
mNodeIDToInstance.add(node, instance);
return node;
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index ae3cb33..6132a2c 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -23,6 +23,7 @@
#include "SoftOMXPlugin.h"
#include <dlfcn.h>
+#include <fcntl.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -30,6 +31,29 @@
OMXMaster::OMXMaster()
: mVendorLibHandle(NULL) {
+
+ mProcessName[0] = 0;
+ if (mProcessName[0] == 0) {
+ pid_t pid = getpid();
+ char filename[20];
+ snprintf(filename, sizeof(filename), "/proc/%d/comm", pid);
+ int fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ ALOGW("couldn't determine process name");
+ sprintf(mProcessName, "<unknown>");
+ } else {
+ ssize_t len = read(fd, mProcessName, sizeof(mProcessName));
+ if (len < 2) {
+ ALOGW("couldn't determine process name");
+ sprintf(mProcessName, "<unknown>");
+ } else {
+ // the name is newline terminated, so erase the newline
+ mProcessName[len - 1] = 0;
+ }
+ close(fd);
+ }
+ }
+
addVendorPlugin();
addPlugin(new SoftOMXPlugin);
}
@@ -123,6 +147,7 @@
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component) {
+ ALOGI("makeComponentInstance(%s) in %s process", name, mProcessName);
Mutex::Autolock autoLock(mLock);
*component = NULL;
diff --git a/media/libstagefright/omx/OMXMaster.h b/media/libstagefright/omx/OMXMaster.h
index 6069741..3f9c0ca 100644
--- a/media/libstagefright/omx/OMXMaster.h
+++ b/media/libstagefright/omx/OMXMaster.h
@@ -50,6 +50,7 @@
Vector<String8> *roles);
private:
+ char mProcessName[16];
Mutex mLock;
List<OMXPluginBase *> mPlugins;
KeyedVector<String8, OMXPluginBase *> mPluginByComponentName;
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 94a213a..a8c55fa 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -29,6 +29,7 @@
#include <OMX_AsString.h>
#include <binder/IMemory.h>
+#include <cutils/properties.h>
#include <gui/BufferQueue.h>
#include <HardwareAPI.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -203,6 +204,8 @@
mDebugLevelBumpPendingBuffers[1] = 0;
mMetadataType[0] = kMetadataBufferTypeInvalid;
mMetadataType[1] = kMetadataBufferTypeInvalid;
+ mSecureBufferType[0] = kSecureBufferTypeUnknown;
+ mSecureBufferType[1] = kSecureBufferTypeUnknown;
mIsSecure = AString(name).endsWith(".secure");
}
@@ -453,12 +456,14 @@
return StatusFromOMXError(err);
}
-status_t OMXNodeInstance::enableGraphicBuffers(
- OMX_U32 portIndex, OMX_BOOL enable) {
+status_t OMXNodeInstance::enableNativeBuffers(
+ OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable) {
Mutex::Autolock autoLock(mLock);
- CLOG_CONFIG(enableGraphicBuffers, "%s:%u, %d", portString(portIndex), portIndex, enable);
+ CLOG_CONFIG(enableNativeBuffers, "%s:%u%s, %d", portString(portIndex), portIndex,
+ graphic ? ", graphic" : "", enable);
OMX_STRING name = const_cast<OMX_STRING>(
- "OMX.google.android.index.enableAndroidNativeBuffers");
+ graphic ? "OMX.google.android.index.enableAndroidNativeBuffers"
+ : "OMX.google.android.index.allocateNativeHandle");
OMX_INDEXTYPE index;
OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
@@ -476,6 +481,25 @@
err = OMX_SetParameter(mHandle, index, ¶ms);
CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d", name, index,
portString(portIndex), portIndex, enable);
+ if (!graphic) {
+ if (err == OK) {
+ mSecureBufferType[portIndex] =
+ enable ? kSecureBufferTypeNativeHandle : kSecureBufferTypeOpaque;
+ } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
+
+ // BEGIN ALTERNATE SIGNALING FOR USING NATIVE HANDLES
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("media.mediadrmservice.enable", value, NULL)
+ && (!strcmp("1", value) || !strcasecmp("true", value))) {
+ CLOG_CONFIG(enableNativeBuffers, "system property override: using native-handles");
+ mSecureBufferType[portIndex] = kSecureBufferTypeNativeHandle;
+ return OK;
+ }
+ // END ALTERNATE SIGNALING FOR USING NATIVE HANDLES
+
+ mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
+ }
+ }
return StatusFromOMXError(err);
}
@@ -655,6 +679,11 @@
status_t OMXNodeInstance::useBuffer(
OMX_U32 portIndex, const sp<IMemory> ¶ms,
OMX::buffer_id *buffer, OMX_U32 allottedSize) {
+ if (params == NULL || buffer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autoLock(mLock);
if (allottedSize > params->size()) {
return BAD_VALUE;
@@ -699,6 +728,10 @@
status_t OMXNodeInstance::useGraphicBuffer2_l(
OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
OMX::buffer_id *buffer) {
+ if (graphicBuffer == NULL || buffer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
// port definition
OMX_PARAM_PORTDEFINITIONTYPE def;
@@ -751,6 +784,10 @@
status_t OMXNodeInstance::useGraphicBuffer(
OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
OMX::buffer_id *buffer) {
+ if (graphicBuffer == NULL || buffer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
Mutex::Autolock autoLock(mLock);
// See if the newer version of the extension is present.
@@ -811,6 +848,12 @@
status_t OMXNodeInstance::updateGraphicBufferInMeta_l(
OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header) {
+ // No need to check |graphicBuffer| since NULL is valid for it as below.
+ if (header == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
+
if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
return BAD_VALUE;
}
@@ -911,6 +954,11 @@
status_t OMXNodeInstance::createInputSurface(
OMX_U32 portIndex, sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
+ if (bufferProducer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autolock(mLock);
status_t err = createGraphicBufferSource(portIndex, NULL /* bufferConsumer */, type);
@@ -926,6 +974,10 @@
status_t OMXNodeInstance::createPersistentInputSurface(
sp<IGraphicBufferProducer> *bufferProducer,
sp<IGraphicBufferConsumer> *bufferConsumer) {
+ if (bufferProducer == NULL || bufferConsumer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
String8 name("GraphicBufferSource");
sp<IGraphicBufferProducer> producer;
@@ -968,9 +1020,14 @@
return bufferSource->signalEndOfInputStream();
}
-status_t OMXNodeInstance::allocateBuffer(
+status_t OMXNodeInstance::allocateSecureBuffer(
OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
- void **buffer_data) {
+ void **buffer_data, native_handle_t **native_handle) {
+ if (buffer == NULL || buffer_data == NULL || native_handle == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autoLock(mLock);
BufferMeta *buffer_meta = new BufferMeta(size);
@@ -993,7 +1050,13 @@
CHECK_EQ(header->pAppPrivate, buffer_meta);
*buffer = makeBufferID(header);
- *buffer_data = header->pBuffer;
+ if (mSecureBufferType[portIndex] == kSecureBufferTypeNativeHandle) {
+ *buffer_data = NULL;
+ *native_handle = (native_handle_t *)header->pBuffer;
+ } else {
+ *buffer_data = header->pBuffer;
+ *native_handle = NULL;
+ }
addActiveBuffer(portIndex, *buffer);
@@ -1001,7 +1064,8 @@
if (bufferSource != NULL && portIndex == kPortIndexInput) {
bufferSource->addCodecBuffer(header);
}
- CLOG_BUFFER(allocateBuffer, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p", size, *buffer_data));
+ CLOG_BUFFER(allocateSecureBuffer, NEW_BUFFER_FMT(
+ *buffer, portIndex, "%zu@%p:%p", size, *buffer_data, *native_handle));
return OK;
}
@@ -1009,6 +1073,11 @@
status_t OMXNodeInstance::allocateBufferWithBackup(
OMX_U32 portIndex, const sp<IMemory> ¶ms,
OMX::buffer_id *buffer, OMX_U32 allottedSize) {
+ if (params == NULL || buffer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autoLock(mLock);
if (allottedSize > params->size()) {
return BAD_VALUE;
@@ -1056,6 +1125,10 @@
removeActiveBuffer(portIndex, buffer);
OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
+ if (header == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
@@ -1072,6 +1145,10 @@
Mutex::Autolock autoLock(mLock);
OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
+ if (header == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
header->nFilledLen = 0;
header->nOffset = 0;
header->nFlags = 0;
@@ -1105,6 +1182,10 @@
Mutex::Autolock autoLock(mLock);
OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
+ if (header == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
BufferMeta *buffer_meta =
static_cast<BufferMeta *>(header->pAppPrivate);
sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */);
@@ -1256,6 +1337,11 @@
status_t OMXNodeInstance::emptyGraphicBuffer(
OMX_BUFFERHEADERTYPE *header, const sp<GraphicBuffer> &graphicBuffer,
OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
+ if (header == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autoLock(mLock);
OMX::buffer_id buffer = findBufferID(header);
status_t err = updateGraphicBufferInMeta_l(kPortIndexInput, graphicBuffer, buffer, header);
@@ -1385,6 +1471,10 @@
if (msg.type == omx_message::FILL_BUFFER_DONE) {
OMX_BUFFERHEADERTYPE *buffer =
findBufferHeader(msg.u.extended_buffer_data.buffer);
+ if (buffer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
{
Mutex::Autolock _l(mDebugLock);
@@ -1523,6 +1613,10 @@
OMX_IN OMX_U32 nData1,
OMX_IN OMX_U32 nData2,
OMX_IN OMX_PTR pEventData) {
+ if (pAppData == NULL) {
+ ALOGE("b/25884056");
+ return OMX_ErrorBadParameter;
+ }
OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
if (instance->mDying) {
return OMX_ErrorNone;
@@ -1536,6 +1630,10 @@
OMX_IN OMX_HANDLETYPE /* hComponent */,
OMX_IN OMX_PTR pAppData,
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+ if (pAppData == NULL) {
+ ALOGE("b/25884056");
+ return OMX_ErrorBadParameter;
+ }
OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
if (instance->mDying) {
return OMX_ErrorNone;
@@ -1550,6 +1648,10 @@
OMX_IN OMX_HANDLETYPE /* hComponent */,
OMX_IN OMX_PTR pAppData,
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+ if (pAppData == NULL) {
+ ALOGE("b/25884056");
+ return OMX_ErrorBadParameter;
+ }
OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
if (instance->mDying) {
return OMX_ErrorNone;
@@ -1590,7 +1692,8 @@
void OMXNodeInstance::freeActiveBuffers() {
// Make sure to count down here, as freeBuffer will in turn remove
// the active buffer from the vector...
- for (size_t i = mActiveBuffers.size(); i--;) {
+ for (size_t i = mActiveBuffers.size(); i > 0;) {
+ i--;
freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
}
}
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 4ce165b..e1f4125 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -388,6 +388,14 @@
uint32_t oldHeight = def->format.video.nFrameHeight;
uint32_t newWidth = video_def->nFrameWidth;
uint32_t newHeight = video_def->nFrameHeight;
+ // We need width, height, stride and slice-height to be non-zero and sensible.
+ // These values were chosen to prevent integer overflows further down the line, and do
+ // not indicate support for 32kx32k video.
+ if (newWidth > 32768 || newHeight > 32768
+ || video_def->nStride > 32768 || video_def->nSliceHeight > 32768) {
+ ALOGE("b/22885421");
+ return OMX_ErrorBadParameter;
+ }
if (newWidth != oldWidth || newHeight != oldHeight) {
bool outputPort = (newParams->nPortIndex == kOutputPortIndex);
if (outputPort) {
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index 8ea7a6e..72823e2 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -23,7 +23,6 @@
#include "include/SoftVideoEncoderOMXComponent.h"
-#include <hardware/gralloc.h>
#include <media/hardware/HardwareAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
@@ -71,7 +70,6 @@
mBitrate(192000),
mFramerate(30 << 16), // Q16 format
mColorFormat(OMX_COLOR_FormatYUV420Planar),
- mGrallocModule(NULL),
mMinOutputBufferSize(384), // arbitrary, using one uncompressed macroblock
mMinCompressionRatio(1), // max output size is normally the input size
mComponentRole(componentRole),
@@ -358,6 +356,7 @@
}
// static
+__attribute__((no_sanitize("integer")))
void SoftVideoEncoderOMXComponent::ConvertFlexYUVToPlanar(
uint8_t *dst, size_t dstStride, size_t dstVStride,
struct android_ycbcr *ycbcr, int32_t width, int32_t height) {
@@ -400,6 +399,7 @@
}
// static
+__attribute__((no_sanitize("integer")))
void SoftVideoEncoderOMXComponent::ConvertYUV420SemiPlanarToYUV420Planar(
const uint8_t *inYVU, uint8_t* outYUV, int32_t width, int32_t height) {
// TODO: add support for stride
@@ -430,6 +430,7 @@
}
// static
+__attribute__((no_sanitize("integer")))
void SoftVideoEncoderOMXComponent::ConvertRGB32ToPlanar(
uint8_t *dstY, size_t dstStride, size_t dstVStride,
const uint8_t *src, size_t width, size_t height, size_t srcStride,
@@ -497,13 +498,6 @@
return NULL;
}
- if (mGrallocModule == NULL) {
- CHECK_EQ(0, hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule));
- }
-
- const gralloc_module_t *grmodule =
- (const gralloc_module_t *)mGrallocModule;
-
buffer_handle_t handle;
int format;
size_t srcStride;
@@ -561,19 +555,21 @@
return NULL;
}
+ auto& mapper = GraphicBufferMapper::get();
+
void *bits = NULL;
struct android_ycbcr ycbcr;
status_t res;
if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
- res = grmodule->lock_ycbcr(
- grmodule, handle,
+ res = mapper.lockYCbCr(
+ handle,
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
- 0, 0, width, height, &ycbcr);
+ Rect(width, height), &ycbcr);
} else {
- res = grmodule->lock(
- grmodule, handle,
+ res = mapper.lock(
+ handle,
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
- 0, 0, width, height, &bits);
+ Rect(width, height), &bits);
}
if (res != OK) {
ALOGE("Unable to lock image buffer %p for access", handle);
@@ -617,7 +613,7 @@
break;
}
- if (grmodule->unlock(grmodule, handle) != OK) {
+ if (mapper.unlock(handle) != OK) {
ALOGE("Unable to unlock image buffer %p for access", handle);
}
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 644b6ed..50bb0de 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -27,7 +27,7 @@
#include <binder/IServiceManager.h>
#include <binder/MemoryDealer.h>
#include <media/IMediaHTTPService.h>
-#include <media/IMediaPlayerService.h>
+#include <media/IMediaCodecService.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/DataSource.h>
@@ -37,7 +37,7 @@
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/SimpleDecodingSource.h>
#define DEFAULT_TIMEOUT 500000
@@ -57,8 +57,8 @@
status_t Harness::initOMX() {
sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.player"));
- sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+ sp<IBinder> binder = sm->getService(String16("media.codec"));
+ sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
mOMX = service->getOMX();
return mOMX != 0 ? OK : NO_INIT;
@@ -244,7 +244,7 @@
NodeReaper &operator=(const NodeReaper &);
};
-static sp<MediaExtractor> CreateExtractorFromURI(const char *uri) {
+static sp<IMediaExtractor> CreateExtractorFromURI(const char *uri) {
sp<DataSource> source =
DataSource::CreateFromURI(NULL /* httpService */, uri);
@@ -267,7 +267,7 @@
IOMX::node_id node;
status_t err =
- mOMX->allocateNode(componentName, this, &node);
+ mOMX->allocateNode(componentName, this, NULL, &node);
EXPECT_SUCCESS(err, "allocateNode");
NodeReaper reaper(this, node);
@@ -492,14 +492,14 @@
return NULL;
}
-static sp<MediaSource> CreateSourceForMime(const char *mime) {
+static sp<IMediaSource> CreateSourceForMime(const char *mime) {
const char *url = GetURLForMime(mime);
if (url == NULL) {
return NULL;
}
- sp<MediaExtractor> extractor = CreateExtractorFromURI(url);
+ sp<IMediaExtractor> extractor = CreateExtractorFromURI(url);
if (extractor == NULL) {
return NULL;
@@ -559,7 +559,7 @@
return OK;
}
- sp<MediaSource> source = CreateSourceForMime(mime);
+ sp<IMediaSource> source = CreateSourceForMime(mime);
if (source == NULL) {
printf(" * Unable to open test content for type '%s', "
@@ -569,16 +569,15 @@
return OK;
}
- sp<MediaSource> seekSource = CreateSourceForMime(mime);
+ sp<IMediaSource> seekSource = CreateSourceForMime(mime);
if (source == NULL || seekSource == NULL) {
return UNKNOWN_ERROR;
}
CHECK_EQ(seekSource->start(), (status_t)OK);
- sp<MediaSource> codec = OMXCodec::Create(
- mOMX, source->getFormat(), false /* createEncoder */,
- source, componentName);
+ sp<IMediaSource> codec = SimpleDecodingSource::Create(
+ source, 0 /* flags */, NULL /* nativeWindow */, componentName);
CHECK(codec != NULL);
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
index a1a6576..82a0631 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
@@ -379,7 +379,10 @@
unsigned muxSlotLengthBytes = 0;
unsigned tmp;
do {
- CHECK_LT(offset, buffer->size());
+ if (offset >= buffer->size()) {
+ ALOGW("Malformed buffer received");
+ return out;
+ }
tmp = ptr[offset++];
muxSlotLengthBytes += tmp;
} while (tmp == 0xff);
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index d7c3bd6..576a0a4 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -116,8 +116,15 @@
// to the highest sequence number (extended to 32 bits) received so far.
uint32_t seq1 = seqNum | (mHighestSeqNumber & 0xffff0000);
- uint32_t seq2 = seqNum | ((mHighestSeqNumber & 0xffff0000) + 0x10000);
- uint32_t seq3 = seqNum | ((mHighestSeqNumber & 0xffff0000) - 0x10000);
+
+ // non-overflowing version of:
+ // uint32_t seq2 = seqNum | ((mHighestSeqNumber & 0xffff0000) + 0x10000);
+ uint32_t seq2 = seqNum | (((mHighestSeqNumber >> 16) + 1) << 16);
+
+ // non-underflowing version of:
+ // uint32_t seq2 = seqNum | ((mHighestSeqNumber & 0xffff0000) - 0x10000);
+ uint32_t seq3 = seqNum | ((((mHighestSeqNumber >> 16) | 0x10000) - 1) << 16);
+
uint32_t diff1 = AbsDiff(seq1, mHighestSeqNumber);
uint32_t diff2 = AbsDiff(seq2, mHighestSeqNumber);
uint32_t diff3 = AbsDiff(seq3, mHighestSeqNumber);
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 56c4aa6..1f6b6f7 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -104,7 +104,7 @@
mFd = -1;
}
-status_t ARTPWriter::addSource(const sp<MediaSource> &source) {
+status_t ARTPWriter::addSource(const sp<IMediaSource> &source) {
mSource = source;
return OK;
}
diff --git a/media/libstagefright/rtsp/ARTPWriter.h b/media/libstagefright/rtsp/ARTPWriter.h
index be8bc13..62abd0a 100644
--- a/media/libstagefright/rtsp/ARTPWriter.h
+++ b/media/libstagefright/rtsp/ARTPWriter.h
@@ -37,7 +37,7 @@
struct ARTPWriter : public MediaWriter {
ARTPWriter(int fd);
- virtual status_t addSource(const sp<MediaSource> &source);
+ virtual status_t addSource(const sp<IMediaSource> &source);
virtual bool reachedEOS();
virtual status_t start(MetaData *params);
virtual status_t stop();
@@ -72,7 +72,7 @@
int mRTCPFd;
#endif
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
sp<ALooper> mLooper;
sp<AHandlerReflector<ARTPWriter> > mReflector;
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 855ffdc..5620cf8 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -898,11 +898,6 @@
if (!strncmp(value.c_str(), "Basic", 5)) {
mAuthType = BASIC;
} else {
-#if !defined(HAVE_ANDROID_OS)
- // We don't have access to the MD5 implementation on the simulator,
- // so we won't support digest authentication.
- return false;
-#endif
CHECK(!strncmp(value.c_str(), "Digest", 6));
mAuthType = DIGEST;
@@ -919,7 +914,6 @@
return true;
}
-#if defined(HAVE_ANDROID_OS)
static void H(const AString &s, AString *out) {
out->clear();
@@ -948,7 +942,6 @@
out->append(&nibble, 1);
}
}
-#endif
static void GetMethodAndURL(
const AString &request, AString *method, AString *url) {
@@ -990,7 +983,6 @@
return;
}
-#if defined(HAVE_ANDROID_OS)
CHECK_EQ((int)mAuthType, (int)DIGEST);
AString method, url;
@@ -1039,7 +1031,6 @@
fragment.append("\r\n");
request->insert(fragment, i + 2);
-#endif
}
void ARTSPConnection::addUserAgent(AString *request) const {
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index c5e8c35..bdda19c 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -33,6 +33,7 @@
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
@@ -42,21 +43,23 @@
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
- rtp_test.cpp
+LOCAL_SRC_FILES := \
+ rtp_test.cpp \
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder libstagefright_foundation
+ libstagefright liblog libutils libbinder libstagefright_foundation libmedia
LOCAL_STATIC_LIBRARIES := \
- libstagefright_rtsp
+ libstagefright_rtsp
-LOCAL_C_INCLUDES:= \
+LOCAL_C_INCLUDES := \
frameworks/av/media/libstagefright \
+ frameworks/av/cmds/stagefright \
$(TOP)/frameworks/native/include/media/openmax
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 0d0baf3..eedbb42 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -1131,10 +1131,11 @@
int32_t result;
CHECK(msg->findInt32("result", &result));
- ALOGI("PLAY completed with result %d (%s)",
+ ALOGI("PLAY (for resume) completed with result %d (%s)",
result, strerror(-result));
mCheckPending = false;
+ ++mCheckGeneration;
postAccessUnitTimeoutCheck();
if (result == OK) {
@@ -1282,10 +1283,11 @@
int32_t result;
CHECK(msg->findInt32("result", &result));
- ALOGI("PLAY completed with result %d (%s)",
+ ALOGI("PLAY (for seek) completed with result %d (%s)",
result, strerror(-result));
mCheckPending = false;
+ ++mCheckGeneration;
postAccessUnitTimeoutCheck();
if (result == OK) {
diff --git a/media/libstagefright/rtsp/MyTransmitter.h b/media/libstagefright/rtsp/MyTransmitter.h
index 369f276..bf44aff 100644
--- a/media/libstagefright/rtsp/MyTransmitter.h
+++ b/media/libstagefright/rtsp/MyTransmitter.h
@@ -31,9 +31,10 @@
#ifdef ANDROID
#include "VideoSource.h"
-
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaCodecSource.h>
#endif
namespace android {
@@ -109,17 +110,19 @@
sp<MediaSource> source = new VideoSource(width, height);
- sp<MetaData> encMeta = new MetaData;
- encMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
- encMeta->setInt32(kKeyWidth, width);
- encMeta->setInt32(kKeyHeight, height);
+ sp<AMessage> encMeta = new AMessage;
+ encMeta->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
+ encMeta->setInt32("width", width);
+ encMeta->setInt32("height", height);
+ encMeta->setInt32("frame-rate", 30);
+ encMeta->setInt32("bitrate", 256000);
+ encMeta->setInt32("i-frame-interval", 10);
- OMXClient client;
- client.connect();
+ sp<ALooper> encLooper = new ALooper;
+ encLooper->setName("rtsp_transmitter");
+ encLooper->start();
- mEncoder = OMXCodec::Create(
- client.interface(), encMeta,
- true /* createEncoder */, source);
+ mEncoder = MediaCodecSource::Create(encLooper, encMeta, source);
mEncoder->start();
diff --git a/media/libstagefright/rtsp/rtp_test.cpp b/media/libstagefright/rtsp/rtp_test.cpp
index d43cd2a..24f529b 100644
--- a/media/libstagefright/rtsp/rtp_test.cpp
+++ b/media/libstagefright/rtsp/rtp_test.cpp
@@ -20,13 +20,13 @@
#include <binder/ProcessState.h>
+#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/foundation/base64.h>
+#include <media/stagefright/SimpleDecodingSource.h>
#include "ARTPSession.h"
#include "ASessionDescription.h"
@@ -178,15 +178,8 @@
CHECK_EQ(session->countTracks(), 1u);
sp<MediaSource> source = session->trackAt(0);
- OMXClient client;
- CHECK_EQ(client.connect(), (status_t)OK);
-
- sp<MediaSource> decoder = OMXCodec::Create(
- client.interface(),
- source->getFormat(), false /* createEncoder */,
- source,
- NULL,
- 0); // OMXCodec::kPreferSoftwareCodecs);
+ sp<MediaSource> decoder = SimpleDecodingSource::Create(
+ source, 0 /* flags: ACodec::kPreferSoftwareCodecs */);
CHECK(decoder != NULL);
CHECK_EQ(decoder->start(), (status_t)OK);
@@ -213,7 +206,7 @@
int64_t timeUs;
CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
- printf("decoder returned frame of size %d at time %.2f secs\n",
+ printf("decoder returned frame of size %zu at time %.2f secs\n",
buffer->range_length(), timeUs / 1E6);
}
#endif
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index 3860e9b..ad1e684 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -38,11 +38,6 @@
#include <binder/ProcessState.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
#include <OMX_Component.h>
#include "DummyRecorder.h"
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index 58fb12f..f2c6365 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -3,14 +3,10 @@
LOCAL_SRC_FILES:= \
TextDescriptions.cpp \
- TimedTextDriver.cpp \
- TimedText3GPPSource.cpp \
- TimedTextSource.cpp \
- TimedTextSRTSource.cpp \
- TimedTextPlayer.cpp
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
LOCAL_C_INCLUDES:= \
$(TOP)/frameworks/av/include/media/stagefright/timedtext \
diff --git a/media/libstagefright/timedtext/TimedText3GPPSource.cpp b/media/libstagefright/timedtext/TimedText3GPPSource.cpp
deleted file mode 100644
index 4854121..0000000
--- a/media/libstagefright/timedtext/TimedText3GPPSource.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
- /*
- * Copyright (C) 2012 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 "TimedText3GPPSource"
-#include <utils/Log.h>
-
-#include <binder/Parcel.h>
-#include <media/stagefright/foundation/ADebug.h> // CHECK_XX macro
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h> // for MEDIA_MIMETYPE_xxx
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-
-#include "TimedText3GPPSource.h"
-#include "TextDescriptions.h"
-
-namespace android {
-
-TimedText3GPPSource::TimedText3GPPSource(const sp<MediaSource>& mediaSource)
- : mSource(mediaSource) {
-}
-
-TimedText3GPPSource::~TimedText3GPPSource() {
-}
-
-status_t TimedText3GPPSource::read(
- int64_t *startTimeUs, int64_t *endTimeUs, Parcel *parcel,
- const MediaSource::ReadOptions *options) {
- MediaBuffer *textBuffer = NULL;
- status_t err = mSource->read(&textBuffer, options);
- if (err != OK) {
- return err;
- }
- CHECK(textBuffer != NULL);
- textBuffer->meta_data()->findInt64(kKeyTime, startTimeUs);
- CHECK_GE(*startTimeUs, 0);
- extractAndAppendLocalDescriptions(*startTimeUs, textBuffer, parcel);
- textBuffer->release();
- // endTimeUs is a dummy parameter for 3gpp timed text format.
- // Set a negative value to it to mark it is unavailable.
- *endTimeUs = -1;
- return OK;
-}
-
-// Each text sample consists of a string of text, optionally with sample
-// modifier description. The modifier description could specify a new
-// text style for the string of text. These descriptions are present only
-// if they are needed. This method is used to extract the modifier
-// description and append it at the end of the text.
-status_t TimedText3GPPSource::extractAndAppendLocalDescriptions(
- int64_t timeUs, const MediaBuffer *textBuffer, Parcel *parcel) {
- const void *data;
- size_t size = 0;
- int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
-
- const char *mime;
- CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
- CHECK(strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0);
-
- data = textBuffer->data();
- size = textBuffer->size();
-
- if (size > 0) {
- parcel->freeData();
- flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
- return TextDescriptions::getParcelOfDescriptions(
- (const uint8_t *)data, size, flag, timeUs / 1000, parcel);
- }
- return OK;
-}
-
-// To extract and send the global text descriptions for all the text samples
-// in the text track or text file.
-// TODO: send error message to application via notifyListener()...?
-status_t TimedText3GPPSource::extractGlobalDescriptions(Parcel *parcel) {
- const void *data;
- size_t size = 0;
- int32_t flag = TextDescriptions::GLOBAL_DESCRIPTIONS;
-
- const char *mime;
- CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
- CHECK(strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0);
-
- uint32_t type;
- // get the 'tx3g' box content. This box contains the text descriptions
- // used to render the text track
- if (!mSource->getFormat()->findData(
- kKeyTextFormatData, &type, &data, &size)) {
- return ERROR_MALFORMED;
- }
-
- if (size > 0) {
- flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
- return TextDescriptions::getParcelOfDescriptions(
- (const uint8_t *)data, size, flag, 0, parcel);
- }
- return OK;
-}
-
-sp<MetaData> TimedText3GPPSource::getFormat() {
- return mSource->getFormat();
-}
-
-} // namespace android
diff --git a/media/libstagefright/timedtext/TimedText3GPPSource.h b/media/libstagefright/timedtext/TimedText3GPPSource.h
deleted file mode 100644
index 4170940..0000000
--- a/media/libstagefright/timedtext/TimedText3GPPSource.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2012 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 TIMED_TEXT_3GPP_SOURCE_H_
-#define TIMED_TEXT_3GPP_SOURCE_H_
-
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-
-#include "TimedTextSource.h"
-
-namespace android {
-
-class MediaBuffer;
-class Parcel;
-
-class TimedText3GPPSource : public TimedTextSource {
-public:
- TimedText3GPPSource(const sp<MediaSource>& mediaSource);
- virtual status_t start() { return mSource->start(); }
- virtual status_t stop() { return mSource->stop(); }
- virtual status_t read(
- int64_t *startTimeUs,
- int64_t *endTimeUs,
- Parcel *parcel,
- const MediaSource::ReadOptions *options = NULL);
- virtual status_t extractGlobalDescriptions(Parcel *parcel);
- virtual sp<MetaData> getFormat();
-
-protected:
- virtual ~TimedText3GPPSource();
-
-private:
- sp<MediaSource> mSource;
-
- status_t extractAndAppendLocalDescriptions(
- int64_t timeUs, const MediaBuffer *textBuffer, Parcel *parcel);
-
- DISALLOW_EVIL_CONSTRUCTORS(TimedText3GPPSource);
-};
-
-} // namespace android
-
-#endif // TIMED_TEXT_3GPP_SOURCE_H_
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
deleted file mode 100644
index 55a9803..0000000
--- a/media/libstagefright/timedtext/TimedTextDriver.cpp
+++ /dev/null
@@ -1,287 +0,0 @@
- /*
- * Copyright (C) 2012 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 "TimedTextDriver"
-#include <utils/Log.h>
-
-#include <binder/IPCThreadState.h>
-
-#include <media/IMediaHTTPService.h>
-#include <media/mediaplayer.h>
-#include <media/MediaPlayerInterface.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/timedtext/TimedTextDriver.h>
-
-#include "TextDescriptions.h"
-#include "TimedTextPlayer.h"
-#include "TimedTextSource.h"
-
-namespace android {
-
-TimedTextDriver::TimedTextDriver(
- const wp<MediaPlayerBase> &listener,
- const sp<IMediaHTTPService> &httpService)
- : mLooper(new ALooper),
- mListener(listener),
- mHTTPService(httpService),
- mState(UNINITIALIZED),
- mCurrentTrackIndex(UINT_MAX) {
- mLooper->setName("TimedTextDriver");
- mLooper->start();
- mPlayer = new TimedTextPlayer(listener);
- mLooper->registerHandler(mPlayer);
-}
-
-TimedTextDriver::~TimedTextDriver() {
- mTextSourceVector.clear();
- mTextSourceTypeVector.clear();
- mLooper->stop();
-}
-
-status_t TimedTextDriver::selectTrack_l(size_t index) {
- if (mCurrentTrackIndex == index) {
- return OK;
- }
- sp<TimedTextSource> source;
- source = mTextSourceVector.valueFor(index);
- mPlayer->setDataSource(source);
- if (mState == UNINITIALIZED) {
- mState = PREPARED;
- }
- mCurrentTrackIndex = index;
- return OK;
-}
-
-status_t TimedTextDriver::start() {
- Mutex::Autolock autoLock(mLock);
- switch (mState) {
- case UNINITIALIZED:
- return INVALID_OPERATION;
- case PLAYING:
- return OK;
- case PREPARED:
- mPlayer->start();
- mState = PLAYING;
- return OK;
- case PAUSED:
- mPlayer->resume();
- mState = PLAYING;
- return OK;
- default:
- TRESPASS();
- }
- return UNKNOWN_ERROR;
-}
-
-status_t TimedTextDriver::pause() {
- Mutex::Autolock autoLock(mLock);
- ALOGV("%s() is called", __FUNCTION__);
- switch (mState) {
- case UNINITIALIZED:
- return INVALID_OPERATION;
- case PLAYING:
- mPlayer->pause();
- mState = PAUSED;
- return OK;
- case PREPARED:
- return INVALID_OPERATION;
- case PAUSED:
- return OK;
- default:
- TRESPASS();
- }
- return UNKNOWN_ERROR;
-}
-
-status_t TimedTextDriver::selectTrack(size_t index) {
- status_t ret = OK;
- Mutex::Autolock autoLock(mLock);
- ALOGV("%s() is called", __FUNCTION__);
- switch (mState) {
- case UNINITIALIZED:
- case PREPARED:
- case PAUSED:
- ret = selectTrack_l(index);
- break;
- case PLAYING:
- mPlayer->pause();
- ret = selectTrack_l(index);
- if (ret != OK) {
- break;
- }
- mPlayer->start();
- break;
- default:
- TRESPASS();
- }
- return ret;
-}
-
-status_t TimedTextDriver::unselectTrack(size_t index) {
- Mutex::Autolock autoLock(mLock);
- ALOGV("%s() is called", __FUNCTION__);
- if (mCurrentTrackIndex != index) {
- return INVALID_OPERATION;
- }
- mCurrentTrackIndex = UINT_MAX;
- switch (mState) {
- case UNINITIALIZED:
- return INVALID_OPERATION;
- case PLAYING:
- mPlayer->setDataSource(NULL);
- mState = UNINITIALIZED;
- return OK;
- case PREPARED:
- case PAUSED:
- mState = UNINITIALIZED;
- return OK;
- default:
- TRESPASS();
- }
- return UNKNOWN_ERROR;
-}
-
-status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
- Mutex::Autolock autoLock(mLock);
- ALOGV("%s() is called", __FUNCTION__);
- switch (mState) {
- case UNINITIALIZED:
- return INVALID_OPERATION;
- case PREPARED:
- mPlayer->seekToAsync(timeUs);
- mPlayer->pause();
- mState = PAUSED;
- return OK;
- case PAUSED:
- mPlayer->seekToAsync(timeUs);
- mPlayer->pause();
- return OK;
- case PLAYING:
- mPlayer->seekToAsync(timeUs);
- return OK;
- default:
- TRESPASS();
- }
- return UNKNOWN_ERROR;
-}
-
-status_t TimedTextDriver::addInBandTextSource(
- size_t trackIndex, const sp<MediaSource>& mediaSource) {
- sp<TimedTextSource> source =
- TimedTextSource::CreateTimedTextSource(mediaSource);
- if (source == NULL) {
- return ERROR_UNSUPPORTED;
- }
- Mutex::Autolock autoLock(mLock);
- mTextSourceVector.add(trackIndex, source);
- mTextSourceTypeVector.add(TEXT_SOURCE_TYPE_IN_BAND);
- return OK;
-}
-
-status_t TimedTextDriver::addOutOfBandTextSource(
- size_t trackIndex, const char *uri, const char *mimeType) {
-
- // To support local subtitle file only for now
- if (strncasecmp("file://", uri, 7)) {
- ALOGE("uri('%s') is not a file", uri);
- return ERROR_UNSUPPORTED;
- }
-
- sp<DataSource> dataSource =
- DataSource::CreateFromURI(mHTTPService, uri);
- return createOutOfBandTextSource(trackIndex, mimeType, dataSource);
-}
-
-status_t TimedTextDriver::addOutOfBandTextSource(
- size_t trackIndex, int fd, off64_t offset, off64_t length, const char *mimeType) {
-
- if (fd < 0) {
- ALOGE("Invalid file descriptor: %d", fd);
- return ERROR_UNSUPPORTED;
- }
-
- sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
- return createOutOfBandTextSource(trackIndex, mimeType, dataSource);
-}
-
-status_t TimedTextDriver::createOutOfBandTextSource(
- size_t trackIndex,
- const char *mimeType,
- const sp<DataSource>& dataSource) {
-
- if (dataSource == NULL) {
- return ERROR_UNSUPPORTED;
- }
-
- sp<TimedTextSource> source;
- if (strcasecmp(mimeType, MEDIA_MIMETYPE_TEXT_SUBRIP) == 0) {
- source = TimedTextSource::CreateTimedTextSource(
- dataSource, TimedTextSource::OUT_OF_BAND_FILE_SRT);
- }
-
- if (source == NULL) {
- ALOGE("Failed to create timed text source");
- return ERROR_UNSUPPORTED;
- }
-
- Mutex::Autolock autoLock(mLock);
- mTextSourceVector.add(trackIndex, source);
- mTextSourceTypeVector.add(TEXT_SOURCE_TYPE_OUT_OF_BAND);
- return OK;
-}
-
-size_t TimedTextDriver::countExternalTracks() const {
- size_t nTracks = 0;
- for (size_t i = 0, n = mTextSourceTypeVector.size(); i < n; ++i) {
- if (mTextSourceTypeVector[i] == TEXT_SOURCE_TYPE_OUT_OF_BAND) {
- ++nTracks;
- }
- }
- return nTracks;
-}
-
-void TimedTextDriver::getExternalTrackInfo(Parcel *parcel) {
- Mutex::Autolock autoLock(mLock);
- for (size_t i = 0, n = mTextSourceTypeVector.size(); i < n; ++i) {
- if (mTextSourceTypeVector[i] == TEXT_SOURCE_TYPE_IN_BAND) {
- continue;
- }
-
- sp<MetaData> meta = mTextSourceVector.valueAt(i)->getFormat();
-
- // There are two fields.
- parcel->writeInt32(2);
-
- // track type.
- parcel->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
- const char *lang = "und";
- if (meta != NULL) {
- meta->findCString(kKeyMediaLanguage, &lang);
- }
- parcel->writeString16(String16(lang));
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
deleted file mode 100644
index aecf666..0000000
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ /dev/null
@@ -1,316 +0,0 @@
- /*
- * Copyright (C) 2012 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 "TimedTextPlayer"
-#include <utils/Log.h>
-
-#include <inttypes.h>
-#include <limits.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/timedtext/TimedTextDriver.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/MediaPlayerInterface.h>
-
-#include "TimedTextPlayer.h"
-
-#include "TimedTextSource.h"
-
-namespace android {
-
-// Event should be fired a bit earlier considering the processing time till
-// application actually gets the notification message.
-static const int64_t kAdjustmentProcessingTimeUs = 100000ll;
-static const int64_t kMaxDelayUs = 5000000ll;
-static const int64_t kWaitTimeUsToRetryRead = 100000ll;
-static const int64_t kInvalidTimeUs = INT_MIN;
-
-TimedTextPlayer::TimedTextPlayer(const wp<MediaPlayerBase> &listener)
- : mListener(listener),
- mSource(NULL),
- mPendingSeekTimeUs(kInvalidTimeUs),
- mPaused(false),
- mSendSubtitleGeneration(0) {
-}
-
-TimedTextPlayer::~TimedTextPlayer() {
- if (mSource != NULL) {
- mSource->stop();
- mSource.clear();
- mSource = NULL;
- }
-}
-
-void TimedTextPlayer::start() {
- (new AMessage(kWhatStart, this))->post();
-}
-
-void TimedTextPlayer::pause() {
- (new AMessage(kWhatPause, this))->post();
-}
-
-void TimedTextPlayer::resume() {
- (new AMessage(kWhatResume, this))->post();
-}
-
-void TimedTextPlayer::seekToAsync(int64_t timeUs) {
- sp<AMessage> msg = new AMessage(kWhatSeek, this);
- msg->setInt64("seekTimeUs", timeUs);
- msg->post();
-}
-
-void TimedTextPlayer::setDataSource(sp<TimedTextSource> source) {
- sp<AMessage> msg = new AMessage(kWhatSetSource, this);
- msg->setObject("source", source);
- msg->post();
-}
-
-void TimedTextPlayer::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatPause: {
- mPaused = true;
- break;
- }
- case kWhatResume: {
- mPaused = false;
- if (mPendingSeekTimeUs != kInvalidTimeUs) {
- seekToAsync(mPendingSeekTimeUs);
- mPendingSeekTimeUs = kInvalidTimeUs;
- } else {
- doRead();
- }
- break;
- }
- case kWhatStart: {
- sp<MediaPlayerBase> listener = mListener.promote();
- if (listener == NULL) {
- ALOGE("Listener is NULL when kWhatStart is received.");
- break;
- }
- mPaused = false;
- mPendingSeekTimeUs = kInvalidTimeUs;
- int32_t positionMs = 0;
- listener->getCurrentPosition(&positionMs);
- int64_t seekTimeUs = positionMs * 1000ll;
-
- notifyListener();
- mSendSubtitleGeneration++;
- doSeekAndRead(seekTimeUs);
- break;
- }
- case kWhatRetryRead: {
- int32_t generation = -1;
- CHECK(msg->findInt32("generation", &generation));
- if (generation != mSendSubtitleGeneration) {
- // Drop obsolete msg.
- break;
- }
- int64_t seekTimeUs;
- int seekMode;
- if (msg->findInt64("seekTimeUs", &seekTimeUs) &&
- msg->findInt32("seekMode", &seekMode)) {
- MediaSource::ReadOptions options;
- options.setSeekTo(
- seekTimeUs,
- static_cast<MediaSource::ReadOptions::SeekMode>(seekMode));
- doRead(&options);
- } else {
- doRead();
- }
- break;
- }
- case kWhatSeek: {
- int64_t seekTimeUs = kInvalidTimeUs;
- // Clear a displayed timed text before seeking.
- notifyListener();
- msg->findInt64("seekTimeUs", &seekTimeUs);
- if (seekTimeUs == kInvalidTimeUs) {
- sp<MediaPlayerBase> listener = mListener.promote();
- if (listener != NULL) {
- int32_t positionMs = 0;
- listener->getCurrentPosition(&positionMs);
- seekTimeUs = positionMs * 1000ll;
- }
- }
- if (mPaused) {
- mPendingSeekTimeUs = seekTimeUs;
- break;
- }
- mSendSubtitleGeneration++;
- doSeekAndRead(seekTimeUs);
- break;
- }
- case kWhatSendSubtitle: {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- if (generation != mSendSubtitleGeneration) {
- // Drop obsolete msg.
- break;
- }
- // If current time doesn't reach to the fire time,
- // re-post the message with the adjusted delay time.
- int64_t fireTimeUs = kInvalidTimeUs;
- if (msg->findInt64("fireTimeUs", &fireTimeUs)) {
- // TODO: check if fireTimeUs is not kInvalidTimeUs.
- int64_t delayUs = delayUsFromCurrentTime(fireTimeUs);
- if (delayUs > 0) {
- msg->post(delayUs);
- break;
- }
- }
- sp<RefBase> obj;
- if (msg->findObject("subtitle", &obj)) {
- sp<ParcelEvent> parcelEvent;
- parcelEvent = static_cast<ParcelEvent*>(obj.get());
- notifyListener(&(parcelEvent->parcel));
- doRead();
- } else {
- notifyListener();
- }
- break;
- }
- case kWhatSetSource: {
- mSendSubtitleGeneration++;
- sp<RefBase> obj;
- msg->findObject("source", &obj);
- if (mSource != NULL) {
- mSource->stop();
- mSource.clear();
- mSource = NULL;
- }
- // null source means deselect track.
- if (obj == NULL) {
- mPendingSeekTimeUs = kInvalidTimeUs;
- mPaused = false;
- notifyListener();
- break;
- }
- mSource = static_cast<TimedTextSource*>(obj.get());
- status_t err = mSource->start();
- if (err != OK) {
- notifyError(err);
- break;
- }
- Parcel parcel;
- err = mSource->extractGlobalDescriptions(&parcel);
- if (err != OK) {
- notifyError(err);
- break;
- }
- notifyListener(&parcel);
- break;
- }
- }
-}
-
-void TimedTextPlayer::doSeekAndRead(int64_t seekTimeUs) {
- MediaSource::ReadOptions options;
- options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
- doRead(&options);
-}
-
-void TimedTextPlayer::doRead(MediaSource::ReadOptions* options) {
- int64_t startTimeUs = 0;
- int64_t endTimeUs = 0;
- sp<ParcelEvent> parcelEvent = new ParcelEvent();
- CHECK(mSource != NULL);
- status_t err = mSource->read(&startTimeUs, &endTimeUs,
- &(parcelEvent->parcel), options);
- if (err == WOULD_BLOCK) {
- sp<AMessage> msg = new AMessage(kWhatRetryRead, this);
- if (options != NULL) {
- int64_t seekTimeUs = kInvalidTimeUs;
- MediaSource::ReadOptions::SeekMode seekMode =
- MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC;
- CHECK(options->getSeekTo(&seekTimeUs, &seekMode));
- msg->setInt64("seekTimeUs", seekTimeUs);
- msg->setInt32("seekMode", seekMode);
- }
- msg->setInt32("generation", mSendSubtitleGeneration);
- msg->post(kWaitTimeUsToRetryRead);
- return;
- } else if (err != OK) {
- notifyError(err);
- return;
- }
-
- postTextEvent(parcelEvent, startTimeUs);
- if (endTimeUs > 0) {
- CHECK_GE(endTimeUs, startTimeUs);
- // send an empty timed text to clear the subtitle when it reaches to the
- // end time.
- postTextEvent(NULL, endTimeUs);
- }
-}
-
-void TimedTextPlayer::postTextEvent(const sp<ParcelEvent>& parcel, int64_t timeUs) {
- int64_t delayUs = delayUsFromCurrentTime(timeUs);
- sp<AMessage> msg = new AMessage(kWhatSendSubtitle, this);
- msg->setInt32("generation", mSendSubtitleGeneration);
- if (parcel != NULL) {
- msg->setObject("subtitle", parcel);
- }
- msg->setInt64("fireTimeUs", timeUs);
- msg->post(delayUs);
-}
-
-int64_t TimedTextPlayer::delayUsFromCurrentTime(int64_t fireTimeUs) {
- sp<MediaPlayerBase> listener = mListener.promote();
- if (listener == NULL) {
- // TODO: it may be better to return kInvalidTimeUs
- ALOGE("%s: Listener is NULL. (fireTimeUs = %" PRId64" )",
- __FUNCTION__, fireTimeUs);
- return 0;
- }
- int32_t positionMs = 0;
- listener->getCurrentPosition(&positionMs);
- int64_t positionUs = positionMs * 1000ll;
-
- if (fireTimeUs <= positionUs + kAdjustmentProcessingTimeUs) {
- return 0;
- } else {
- int64_t delayUs = fireTimeUs - positionUs - kAdjustmentProcessingTimeUs;
- if (delayUs > kMaxDelayUs) {
- return kMaxDelayUs;
- }
- return delayUs;
- }
-}
-
-void TimedTextPlayer::notifyError(int error) {
- sp<MediaPlayerBase> listener = mListener.promote();
- if (listener == NULL) {
- ALOGE("%s(error=%d): Listener is NULL.", __FUNCTION__, error);
- return;
- }
- listener->sendEvent(MEDIA_INFO, MEDIA_INFO_TIMED_TEXT_ERROR, error);
-}
-
-void TimedTextPlayer::notifyListener(const Parcel *parcel) {
- sp<MediaPlayerBase> listener = mListener.promote();
- if (listener == NULL) {
- ALOGE("%s: Listener is NULL.", __FUNCTION__);
- return;
- }
- if (parcel != NULL && (parcel->dataSize() > 0)) {
- listener->sendEvent(MEDIA_TIMED_TEXT, 0, 0, parcel);
- } else { // send an empty timed text to clear the screen
- listener->sendEvent(MEDIA_TIMED_TEXT);
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.h b/media/libstagefright/timedtext/TimedTextPlayer.h
deleted file mode 100644
index 9cb49ec..0000000
--- a/media/libstagefright/timedtext/TimedTextPlayer.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2012 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 TIMEDTEXT_PLAYER_H_
-#define TIMEDTEXT_PLAYER_H_
-
-#include <binder/Parcel.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AHandler.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/RefBase.h>
-
-#include "TimedTextSource.h"
-
-namespace android {
-
-struct AMessage;
-class MediaPlayerBase;
-class TimedTextDriver;
-class TimedTextSource;
-
-class TimedTextPlayer : public AHandler {
-public:
- TimedTextPlayer(const wp<MediaPlayerBase> &listener);
-
- virtual ~TimedTextPlayer();
-
- void start();
- void pause();
- void resume();
- void seekToAsync(int64_t timeUs);
- void setDataSource(sp<TimedTextSource> source);
-
-protected:
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
-private:
- enum {
- kWhatPause = 'paus',
- kWhatResume = 'resm',
- kWhatStart = 'strt',
- kWhatSeek = 'seek',
- kWhatRetryRead = 'read',
- kWhatSendSubtitle = 'send',
- kWhatSetSource = 'ssrc',
- };
-
- // To add Parcel into an AMessage as an object, it should be 'RefBase'.
- struct ParcelEvent : public RefBase {
- Parcel parcel;
- };
-
- wp<MediaPlayerBase> mListener;
- sp<TimedTextSource> mSource;
- int64_t mPendingSeekTimeUs;
- bool mPaused;
- int32_t mSendSubtitleGeneration;
-
- void doSeekAndRead(int64_t seekTimeUs);
- void doRead(MediaSource::ReadOptions* options = NULL);
- void onTextEvent();
- void postTextEvent(const sp<ParcelEvent>& parcel = NULL, int64_t timeUs = -1);
- int64_t delayUsFromCurrentTime(int64_t fireTimeUs);
- void notifyError(int error = 0);
- void notifyListener(const Parcel *parcel = NULL);
-
- DISALLOW_EVIL_CONSTRUCTORS(TimedTextPlayer);
-};
-
-} // namespace android
-
-#endif // TIMEDTEXT_PLAYER_H_
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.cpp b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
deleted file mode 100644
index 2ac1e72..0000000
--- a/media/libstagefright/timedtext/TimedTextSRTSource.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
- /*
- * Copyright (C) 2012 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 "TimedTextSRTSource"
-#include <utils/Log.h>
-
-#include <binder/Parcel.h>
-#include <media/stagefright/foundation/ADebug.h> // for CHECK_xx
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDefs.h> // for MEDIA_MIMETYPE_xxx
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-
-#include "TimedTextSRTSource.h"
-#include "TextDescriptions.h"
-
-namespace android {
-
-TimedTextSRTSource::TimedTextSRTSource(const sp<DataSource>& dataSource)
- : mSource(dataSource),
- mMetaData(new MetaData),
- mIndex(0) {
- // TODO: Need to detect the language, because SRT doesn't give language
- // information explicitly.
- mMetaData->setCString(kKeyMediaLanguage, "und");
-}
-
-TimedTextSRTSource::~TimedTextSRTSource() {
-}
-
-status_t TimedTextSRTSource::start() {
- status_t err = scanFile();
- if (err != OK) {
- reset();
- }
- return err;
-}
-
-void TimedTextSRTSource::reset() {
- mTextVector.clear();
- mIndex = 0;
-}
-
-status_t TimedTextSRTSource::stop() {
- reset();
- return OK;
-}
-
-status_t TimedTextSRTSource::read(
- int64_t *startTimeUs,
- int64_t *endTimeUs,
- Parcel *parcel,
- const MediaSource::ReadOptions *options) {
- AString text;
- status_t err = getText(options, &text, startTimeUs, endTimeUs);
- if (err != OK) {
- return err;
- }
-
- CHECK_GE(*startTimeUs, 0);
- extractAndAppendLocalDescriptions(*startTimeUs, text, parcel);
- return OK;
-}
-
-sp<MetaData> TimedTextSRTSource::getFormat() {
- return mMetaData;
-}
-
-status_t TimedTextSRTSource::scanFile() {
- off64_t offset = 0;
- int64_t startTimeUs;
- bool endOfFile = false;
-
- while (!endOfFile) {
- TextInfo info;
- status_t err = getNextSubtitleInfo(&offset, &startTimeUs, &info);
- switch (err) {
- case OK:
- mTextVector.add(startTimeUs, info);
- break;
- case ERROR_END_OF_STREAM:
- endOfFile = true;
- break;
- default:
- return err;
- }
- }
- if (mTextVector.isEmpty()) {
- return ERROR_MALFORMED;
- }
- return OK;
-}
-
-/* SRT format:
- * Subtitle number
- * Start time --> End time
- * Text of subtitle (one or more lines)
- * Blank lines
- *
- * .srt file example:
- * 1
- * 00:00:20,000 --> 00:00:24,400
- * Altocumulus clouds occr between six thousand
- *
- * 2
- * 00:00:24,600 --> 00:00:27,800
- * and twenty thousand feet above ground level.
- */
-status_t TimedTextSRTSource::getNextSubtitleInfo(
- off64_t *offset, int64_t *startTimeUs, TextInfo *info) {
- AString data;
- status_t err;
-
- // To skip blank lines.
- do {
- if ((err = readNextLine(offset, &data)) != OK) {
- return err;
- }
- data.trim();
- } while (data.empty());
-
- // Just ignore the first non-blank line which is subtitle sequence number.
- if ((err = readNextLine(offset, &data)) != OK) {
- return err;
- }
- int hour1, hour2, min1, min2, sec1, sec2, msec1, msec2;
- // the start time format is: hours:minutes:seconds,milliseconds
- // 00:00:24,600 --> 00:00:27,800
- if (sscanf(data.c_str(), "%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d",
- &hour1, &min1, &sec1, &msec1, &hour2, &min2, &sec2, &msec2) != 8) {
- return ERROR_MALFORMED;
- }
-
- *startTimeUs = ((hour1 * 3600 + min1 * 60 + sec1) * 1000 + msec1) * 1000ll;
- info->endTimeUs = ((hour2 * 3600 + min2 * 60 + sec2) * 1000 + msec2) * 1000ll;
- if (info->endTimeUs <= *startTimeUs) {
- return ERROR_MALFORMED;
- }
-
- info->offset = *offset;
- bool needMoreData = true;
- while (needMoreData) {
- if ((err = readNextLine(offset, &data)) != OK) {
- if (err == ERROR_END_OF_STREAM) {
- break;
- } else {
- return err;
- }
- }
-
- data.trim();
- if (data.empty()) {
- // it's an empty line used to separate two subtitles
- needMoreData = false;
- }
- }
- info->textLen = *offset - info->offset;
- return OK;
-}
-
-status_t TimedTextSRTSource::readNextLine(off64_t *offset, AString *data) {
- data->clear();
- while (true) {
- ssize_t readSize;
- char character;
- if ((readSize = mSource->readAt(*offset, &character, 1)) < 1) {
- if (readSize == 0) {
- return ERROR_END_OF_STREAM;
- }
- return ERROR_IO;
- }
-
- (*offset)++;
-
- // a line could end with CR, LF or CR + LF
- if (character == 10) {
- break;
- } else if (character == 13) {
- if ((readSize = mSource->readAt(*offset, &character, 1)) < 1) {
- if (readSize == 0) { // end of the stream
- return OK;
- }
- return ERROR_IO;
- }
-
- (*offset)++;
- if (character != 10) {
- (*offset)--;
- }
- break;
- }
- data->append(character);
- }
- return OK;
-}
-
-status_t TimedTextSRTSource::getText(
- const MediaSource::ReadOptions *options,
- AString *text, int64_t *startTimeUs, int64_t *endTimeUs) {
- if (mTextVector.size() == 0) {
- return ERROR_END_OF_STREAM;
- }
- text->clear();
- int64_t seekTimeUs;
- MediaSource::ReadOptions::SeekMode mode;
- if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
- int64_t lastEndTimeUs =
- mTextVector.valueAt(mTextVector.size() - 1).endTimeUs;
- if (seekTimeUs < 0) {
- return ERROR_OUT_OF_RANGE;
- } else if (seekTimeUs >= lastEndTimeUs) {
- return ERROR_END_OF_STREAM;
- } else {
- // binary search
- size_t low = 0;
- size_t high = mTextVector.size() - 1;
- size_t mid = 0;
-
- while (low <= high) {
- mid = low + (high - low)/2;
- int diff = compareExtendedRangeAndTime(mid, seekTimeUs);
- if (diff == 0) {
- break;
- } else if (diff < 0) {
- low = mid + 1;
- } else {
- high = mid - 1;
- }
- }
- mIndex = mid;
- }
- }
-
- if (mIndex >= mTextVector.size()) {
- return ERROR_END_OF_STREAM;
- }
-
- const TextInfo &info = mTextVector.valueAt(mIndex);
- *startTimeUs = mTextVector.keyAt(mIndex);
- *endTimeUs = info.endTimeUs;
- mIndex++;
-
- char *str = new char[info.textLen];
- if (mSource->readAt(info.offset, str, info.textLen) < info.textLen) {
- delete[] str;
- return ERROR_IO;
- }
- text->append(str, info.textLen);
- delete[] str;
- return OK;
-}
-
-status_t TimedTextSRTSource::extractAndAppendLocalDescriptions(
- int64_t timeUs, const AString &text, Parcel *parcel) {
- const void *data = text.c_str();
- size_t size = text.size();
- int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS |
- TextDescriptions::OUT_OF_BAND_TEXT_SRT;
-
- if (size > 0) {
- return TextDescriptions::getParcelOfDescriptions(
- (const uint8_t *)data, size, flag, timeUs / 1000, parcel);
- }
- return OK;
-}
-
-int TimedTextSRTSource::compareExtendedRangeAndTime(size_t index, int64_t timeUs) {
- CHECK_LT(index, mTextVector.size());
- int64_t endTimeUs = mTextVector.valueAt(index).endTimeUs;
- int64_t startTimeUs = (index > 0) ?
- mTextVector.valueAt(index - 1).endTimeUs : 0;
- if (timeUs >= startTimeUs && timeUs < endTimeUs) {
- return 0;
- } else if (endTimeUs <= timeUs) {
- return -1;
- } else {
- return 1;
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.h b/media/libstagefright/timedtext/TimedTextSRTSource.h
deleted file mode 100644
index 232675e..0000000
--- a/media/libstagefright/timedtext/TimedTextSRTSource.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2012 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 TIMED_TEXT_SRT_SOURCE_H_
-#define TIMED_TEXT_SRT_SOURCE_H_
-
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/Compat.h> // off64_t
-
-#include "TimedTextSource.h"
-
-namespace android {
-
-struct AString;
-class DataSource;
-class MediaBuffer;
-class Parcel;
-
-class TimedTextSRTSource : public TimedTextSource {
-public:
- TimedTextSRTSource(const sp<DataSource>& dataSource);
- virtual status_t start();
- virtual status_t stop();
- virtual status_t read(
- int64_t *startTimeUs,
- int64_t *endTimeUs,
- Parcel *parcel,
- const MediaSource::ReadOptions *options = NULL);
- virtual sp<MetaData> getFormat();
-
-protected:
- virtual ~TimedTextSRTSource();
-
-private:
- sp<DataSource> mSource;
- sp<MetaData> mMetaData;
-
- struct TextInfo {
- int64_t endTimeUs;
- // The offset of the text in the original file.
- off64_t offset;
- int textLen;
- };
-
- size_t mIndex;
- KeyedVector<int64_t, TextInfo> mTextVector;
-
- void reset();
- status_t scanFile();
- status_t getNextSubtitleInfo(
- off64_t *offset, int64_t *startTimeUs, TextInfo *info);
- status_t readNextLine(off64_t *offset, AString *data);
- status_t getText(
- const MediaSource::ReadOptions *options,
- AString *text, int64_t *startTimeUs, int64_t *endTimeUs);
- status_t extractAndAppendLocalDescriptions(
- int64_t timeUs, const AString &text, Parcel *parcel);
-
- // Compares the time range of the subtitle at index to the given timeUs.
- // The time range of the subtitle to match with given timeUs is extended to
- // [endTimeUs of the previous subtitle, endTimeUs of current subtitle).
- //
- // This compare function is used to find a next subtitle when read() is
- // called with seek options. Note that timeUs within gap ranges, such as
- // [200, 300) in the below example, will be matched to the closest future
- // subtitle, [300, 400).
- //
- // For instance, assuming there are 3 subtitles in mTextVector,
- // 0: [100, 200) ----> [0, 200)
- // 1: [300, 400) ----> [200, 400)
- // 2: [500, 600) ----> [400, 600)
- // If the 'index' parameter contains 1, this function
- // returns 0, if timeUs is in [200, 400)
- // returns -1, if timeUs >= 400,
- // returns 1, if timeUs < 200.
- int compareExtendedRangeAndTime(size_t index, int64_t timeUs);
-
- DISALLOW_EVIL_CONSTRUCTORS(TimedTextSRTSource);
-};
-
-} // namespace android
-
-#endif // TIMED_TEXT_SRT_SOURCE_H_
diff --git a/media/libstagefright/timedtext/TimedTextSource.cpp b/media/libstagefright/timedtext/TimedTextSource.cpp
deleted file mode 100644
index 953f7b5..0000000
--- a/media/libstagefright/timedtext/TimedTextSource.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
- /*
- * Copyright (C) 2012 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 "TimedTextSource"
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/ADebug.h> // CHECK_XX macro
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDefs.h> // for MEDIA_MIMETYPE_xxx
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-
-#include "TimedTextSource.h"
-
-#include "TimedText3GPPSource.h"
-#include "TimedTextSRTSource.h"
-
-namespace android {
-
-// static
-sp<TimedTextSource> TimedTextSource::CreateTimedTextSource(
- const sp<MediaSource>& mediaSource) {
- const char *mime;
- CHECK(mediaSource->getFormat()->findCString(kKeyMIMEType, &mime));
- if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0) {
- return new TimedText3GPPSource(mediaSource);
- }
- ALOGE("Unsupported mime type for subtitle. : %s", mime);
- return NULL;
-}
-
-// static
-sp<TimedTextSource> TimedTextSource::CreateTimedTextSource(
- const sp<DataSource>& dataSource, FileType filetype) {
- switch(filetype) {
- case OUT_OF_BAND_FILE_SRT:
- return new TimedTextSRTSource(dataSource);
- case OUT_OF_BAND_FILE_SMI:
- // TODO: Implement for SMI.
- ALOGE("Supporting SMI is not implemented yet");
- break;
- default:
- ALOGE("Undefined subtitle format. : %d", filetype);
- }
- return NULL;
-}
-
-sp<MetaData> TimedTextSource::getFormat() {
- return NULL;
-}
-
-} // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextSource.h b/media/libstagefright/timedtext/TimedTextSource.h
deleted file mode 100644
index 8c1c1cd..0000000
--- a/media/libstagefright/timedtext/TimedTextSource.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2012 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 TIMED_TEXT_SOURCE_H_
-#define TIMED_TEXT_SOURCE_H_
-
-#include <media/stagefright/foundation/ABase.h> // for DISALLOW_XXX macro.
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h> // for MediaSource::ReadOptions
-#include <utils/RefBase.h>
-
-namespace android {
-
-class DataSource;
-class MetaData;
-class Parcel;
-
-class TimedTextSource : public RefBase {
- public:
- enum FileType {
- OUT_OF_BAND_FILE_SRT = 1,
- OUT_OF_BAND_FILE_SMI = 2,
- };
- static sp<TimedTextSource> CreateTimedTextSource(
- const sp<MediaSource>& source);
- static sp<TimedTextSource> CreateTimedTextSource(
- const sp<DataSource>& source, FileType filetype);
- TimedTextSource() {}
- virtual status_t start() = 0;
- virtual status_t stop() = 0;
- // Returns subtitle parcel and its start time.
- virtual status_t read(
- int64_t *startTimeUs,
- int64_t *endTimeUs,
- Parcel *parcel,
- const MediaSource::ReadOptions *options = NULL) = 0;
- virtual status_t extractGlobalDescriptions(Parcel * /* parcel */) {
- return INVALID_OPERATION;
- }
- virtual sp<MetaData> getFormat();
-
- protected:
- virtual ~TimedTextSource() { }
-
- private:
- DISALLOW_EVIL_CONSTRUCTORS(TimedTextSource);
-};
-
-} // namespace android
-
-#endif // TIMED_TEXT_SOURCE_H_
diff --git a/media/libstagefright/timedtext/test/Android.mk b/media/libstagefright/timedtext/test/Android.mk
deleted file mode 100644
index e0e0e0d..0000000
--- a/media/libstagefright/timedtext/test/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# ================================================================
-# Unit tests for libstagefright_timedtext
-# ================================================================
-
-# ================================================================
-# A test for TimedTextSRTSource
-# ================================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := TimedTextSRTSource_test
-
-LOCAL_MODULE_TAGS := eng tests
-
-LOCAL_SRC_FILES := TimedTextSRTSource_test.cpp
-
-LOCAL_C_INCLUDES := \
- $(TOP)/external/expat/lib \
- $(TOP)/frameworks/av/media/libstagefright/timedtext
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libexpat \
- libstagefright \
- libstagefright_foundation \
- libutils
-
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CLANG := true
-
-include $(BUILD_NATIVE_TEST)
diff --git a/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp b/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp
deleted file mode 100644
index 211e732..0000000
--- a/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2012 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 "TimedTextSRTSource_test"
-#include <utils/Log.h>
-
-#include <gtest/gtest.h>
-
-#include <binder/Parcel.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaErrors.h>
-#include <utils/misc.h>
-
-#include <TimedTextSource.h>
-#include <TimedTextSRTSource.h>
-
-namespace android {
-namespace test {
-
-static const int kSecToUsec = 1000000;
-static const int kSecToMsec = 1000;
-static const int kMsecToUsec = 1000;
-
-/* SRT format (http://en.wikipedia.org/wiki/SubRip)
- * Subtitle number
- * Start time --> End time
- * Text of subtitle (one or more lines)
- * Blank lines
- */
-static const char *kSRTString =
- "1\n00:00:1,000 --> 00:00:1,500\n1\n\n"
- "2\n00:00:2,000 --> 00:00:2,500\n2\n\n"
- "3\n00:00:3,000 --> 00:00:3,500\n3\n\n"
- "4\n00:00:4,000 --> 00:00:4,500\n4\n\n"
- "5\n00:00:5,000 --> 00:00:5,500\n5\n\n"
- // edge case : previos end time = next start time
- "6\n00:00:5,500 --> 00:00:5,800\n6\n\n"
- "7\n00:00:5,800 --> 00:00:6,000\n7\n\n"
- "8\n00:00:6,000 --> 00:00:7,000\n8\n\n";
-
-class SRTDataSourceStub : public DataSource {
-public:
- SRTDataSourceStub(const char *data, size_t size) :
- mData(data), mSize(size) {}
- virtual ~SRTDataSourceStub() {}
-
- virtual status_t initCheck() const {
- return OK;
- }
-
- virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
- if ((size_t)offset >= mSize) return 0;
-
- ssize_t avail = mSize - offset;
- if ((size_t)avail > size) {
- avail = size;
- }
- memcpy(data, mData + offset, avail);
- return avail;
- }
-
-private:
- const char *mData;
- size_t mSize;
-};
-
-class TimedTextSRTSourceTest : public testing::Test {
-protected:
- void SetUp() {
- sp<DataSource> stub= new SRTDataSourceStub(
- kSRTString,
- strlen(kSRTString));
- mSource = new TimedTextSRTSource(stub);
- mSource->start();
- }
-
- void CheckStartTimeMs(const Parcel& parcel, int32_t timeMs) {
- int32_t intval;
- parcel.setDataPosition(8);
- parcel.readInt32(&intval);
- EXPECT_EQ(timeMs, intval);
- }
-
- void CheckDataEquals(const Parcel& parcel, const char* content) {
- int32_t intval;
- parcel.setDataPosition(16);
- parcel.readInt32(&intval);
- parcel.setDataPosition(24);
- const char* data = (const char*) parcel.readInplace(intval);
-
- int32_t content_len = strlen(content);
- EXPECT_EQ(content_len, intval);
- EXPECT_TRUE(strncmp(data, content, content_len) == 0);
- }
-
- sp<TimedTextSource> mSource;
- int64_t startTimeUs;
- int64_t endTimeUs;
- Parcel parcel;
- AString subtitle;
- status_t err;
-};
-
-TEST_F(TimedTextSRTSourceTest, readAll) {
- for (int i = 1; i <= 5; i++) {
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
- EXPECT_EQ(OK, err);
- CheckStartTimeMs(parcel, i * kSecToMsec);
- subtitle = AStringPrintf("%d\n\n", i);
- CheckDataEquals(parcel, subtitle.c_str());
- }
- // read edge cases
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
- EXPECT_EQ(OK, err);
- CheckStartTimeMs(parcel, 5500);
- subtitle = AStringPrintf("6\n\n");
- CheckDataEquals(parcel, subtitle.c_str());
-
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
- EXPECT_EQ(OK, err);
- CheckStartTimeMs(parcel, 5800);
- subtitle = AStringPrintf("7\n\n");
- CheckDataEquals(parcel, subtitle.c_str());
-
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
- EXPECT_EQ(OK, err);
- CheckStartTimeMs(parcel, 6000);
- subtitle = AStringPrintf("8\n\n");
- CheckDataEquals(parcel, subtitle.c_str());
-
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
- EXPECT_EQ(ERROR_END_OF_STREAM, err);
-}
-
-TEST_F(TimedTextSRTSourceTest, seekTimeIsEarlierThanFirst) {
- MediaSource::ReadOptions options;
- options.setSeekTo(500, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
- EXPECT_EQ(OK, err);
- EXPECT_EQ(1 * kSecToUsec, startTimeUs);
- CheckStartTimeMs(parcel, 1 * kSecToMsec);
-}
-
-TEST_F(TimedTextSRTSourceTest, seekTimeIsLaterThanLast) {
- MediaSource::ReadOptions options;
- options.setSeekTo(7 * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
- EXPECT_EQ(ERROR_END_OF_STREAM, err);
-
- options.setSeekTo(8 * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
- EXPECT_EQ(ERROR_END_OF_STREAM, err);
-}
-
-TEST_F(TimedTextSRTSourceTest, seekTimeIsMatched) {
- for (int i = 1; i <= 5; i++) {
- MediaSource::ReadOptions options;
- options.setSeekTo(i * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
- EXPECT_EQ(OK, err);
- EXPECT_EQ(i * kSecToUsec, startTimeUs);
-
- options.setSeekTo(i * kSecToUsec + 100, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
- EXPECT_EQ(OK, err);
- EXPECT_EQ(i * kSecToUsec, startTimeUs);
- }
-}
-
-TEST_F(TimedTextSRTSourceTest, seekTimeInBetweenTwo) {
- for (int i = 1; i <= 4; i++) {
- MediaSource::ReadOptions options;
- options.setSeekTo(i * kSecToUsec + 500000, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
- EXPECT_EQ(OK, err);
- EXPECT_EQ((i + 1) * kSecToUsec, startTimeUs);
-
- options.setSeekTo(i * kSecToUsec + 600000, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
- EXPECT_EQ(OK, err);
- EXPECT_EQ((i + 1) * kSecToUsec, startTimeUs);
- }
-}
-
-TEST_F(TimedTextSRTSourceTest, checkEdgeCase) {
- MediaSource::ReadOptions options;
- options.setSeekTo(5500 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
- EXPECT_EQ(OK, err);
- EXPECT_EQ(5500 * kMsecToUsec, startTimeUs);
- subtitle = AStringPrintf("6\n\n");
- CheckDataEquals(parcel, subtitle.c_str());
-
- options.setSeekTo(5800 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
- EXPECT_EQ(OK, err);
- EXPECT_EQ(5800 * kMsecToUsec, startTimeUs);
- subtitle = AStringPrintf("7\n\n");
- CheckDataEquals(parcel, subtitle.c_str());
-
- options.setSeekTo(6000 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
- err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
- EXPECT_EQ(OK, err);
- EXPECT_EQ(6000 * kMsecToUsec, startTimeUs);
- subtitle = AStringPrintf("8\n\n");
- CheckDataEquals(parcel, subtitle.c_str());
-}
-
-} // namespace test
-} // namespace android
diff --git a/media/libstagefright/webm/Android.mk b/media/libstagefright/webm/Android.mk
index bc53c56..ce580ae 100644
--- a/media/libstagefright/webm/Android.mk
+++ b/media/libstagefright/webm/Android.mk
@@ -5,6 +5,7 @@
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_SRC_FILES:= EbmlUtil.cpp \
WebmElement.cpp \
diff --git a/media/libstagefright/webm/WebmElement.cpp b/media/libstagefright/webm/WebmElement.cpp
index a008cab..f454bf6 100644
--- a/media/libstagefright/webm/WebmElement.cpp
+++ b/media/libstagefright/webm/WebmElement.cpp
@@ -338,6 +338,7 @@
}
sp<WebmElement> WebmElement::VideoTrackEntry(
+ const char *codec,
uint64_t width,
uint64_t height,
uint64_t uid,
@@ -353,7 +354,7 @@
uid,
lacing,
lang,
- "V_VP8",
+ codec,
kVideoType,
trackEntryFields);
diff --git a/media/libstagefright/webm/WebmElement.h b/media/libstagefright/webm/WebmElement.h
index f19933e..456c3c7 100644
--- a/media/libstagefright/webm/WebmElement.h
+++ b/media/libstagefright/webm/WebmElement.h
@@ -57,6 +57,7 @@
const char *lang = "und");
static sp<WebmElement> VideoTrackEntry(
+ const char *codec,
uint64_t width,
uint64_t height,
uint64_t uid = 0,
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
index a4b8a42..7eb4745 100644
--- a/media/libstagefright/webm/WebmFrameThread.cpp
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -246,7 +246,7 @@
}
WebmFrameMediaSourceThread::WebmFrameMediaSourceThread(
- const sp<MediaSource>& source,
+ const sp<IMediaSource>& source,
int type,
LinkedBlockingQueue<const sp<WebmFrame> >& sink,
uint64_t timeCodeScale,
diff --git a/media/libstagefright/webm/WebmFrameThread.h b/media/libstagefright/webm/WebmFrameThread.h
index d65d9b7..528984f 100644
--- a/media/libstagefright/webm/WebmFrameThread.h
+++ b/media/libstagefright/webm/WebmFrameThread.h
@@ -123,7 +123,7 @@
class WebmFrameMediaSourceThread: public WebmFrameSourceThread {
public:
WebmFrameMediaSourceThread(
- const sp<MediaSource>& source,
+ const sp<IMediaSource>& source,
int type,
LinkedBlockingQueue<const sp<WebmFrame> >& sink,
uint64_t timeCodeScale,
@@ -142,7 +142,7 @@
}
private:
- const sp<MediaSource> mSource;
+ const sp<IMediaSource> mSource;
const uint64_t mTimeCodeScale;
uint64_t mStartTimeUs;
diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp
index 737f144..511260a 100644
--- a/media/libstagefright/webm/WebmWriter.cpp
+++ b/media/libstagefright/webm/WebmWriter.cpp
@@ -83,9 +83,25 @@
// static
sp<WebmElement> WebmWriter::videoTrack(const sp<MetaData>& md) {
int32_t width, height;
+ const char *mimeType;
CHECK(md->findInt32(kKeyWidth, &width));
CHECK(md->findInt32(kKeyHeight, &height));
- return WebmElement::VideoTrackEntry(width, height);
+ CHECK(md->findCString(kKeyMIMEType, &mimeType));
+ const char *codec;
+ if (!strncasecmp(
+ mimeType,
+ MEDIA_MIMETYPE_VIDEO_VP8,
+ strlen(MEDIA_MIMETYPE_VIDEO_VP8))) {
+ codec = "V_VP8";
+ } else if (!strncasecmp(
+ mimeType,
+ MEDIA_MIMETYPE_VIDEO_VP9,
+ strlen(MEDIA_MIMETYPE_VIDEO_VP9))) {
+ codec = "V_VP9";
+ } else {
+ CHECK(!"Unsupported codec");
+ }
+ return WebmElement::VideoTrackEntry(codec, width, height);
}
// static
@@ -328,7 +344,7 @@
return err;
}
-status_t WebmWriter::addSource(const sp<MediaSource> &source) {
+status_t WebmWriter::addSource(const sp<IMediaSource> &source) {
Mutex::Autolock l(mLock);
if (mStarted) {
ALOGE("Attempt to add source AFTER recording is started");
@@ -348,15 +364,18 @@
const char *mime;
source->getFormat()->findCString(kKeyMIMEType, &mime);
const char *vp8 = MEDIA_MIMETYPE_VIDEO_VP8;
+ const char *vp9 = MEDIA_MIMETYPE_VIDEO_VP9;
const char *vorbis = MEDIA_MIMETYPE_AUDIO_VORBIS;
size_t streamIndex;
- if (!strncasecmp(mime, vp8, strlen(vp8))) {
+ if (!strncasecmp(mime, vp8, strlen(vp8)) ||
+ !strncasecmp(mime, vp9, strlen(vp9))) {
streamIndex = kVideoIndex;
} else if (!strncasecmp(mime, vorbis, strlen(vorbis))) {
streamIndex = kAudioIndex;
} else {
- ALOGE("Track (%s) other than %s or %s is not supported", mime, vp8, vorbis);
+ ALOGE("Track (%s) other than %s, %s or %s is not supported",
+ mime, vp8, vp9, vorbis);
return ERROR_UNSUPPORTED;
}
diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/WebmWriter.h
index 4ad770e..4a7f506 100644
--- a/media/libstagefright/webm/WebmWriter.h
+++ b/media/libstagefright/webm/WebmWriter.h
@@ -40,7 +40,7 @@
~WebmWriter() { reset(); }
- virtual status_t addSource(const sp<MediaSource> &source);
+ virtual status_t addSource(const sp<IMediaSource> &source);
virtual status_t start(MetaData *param = NULL);
virtual status_t stop();
virtual status_t pause();
@@ -85,7 +85,7 @@
const char *mName;
sp<WebmElement> (*mMakeTrack)(const sp<MetaData>&);
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
sp<WebmElement> mTrackEntry;
sp<WebmFrameSourceThread> mThread;
LinkedBlockingQueue<const sp<WebmFrame> > mSink;
diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk
index fb28624..5bd6e5c 100644
--- a/media/libstagefright/wifi-display/Android.mk
+++ b/media/libstagefright/wifi-display/Android.mk
@@ -32,6 +32,7 @@
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
LOCAL_MODULE:= libstagefright_wfd
diff --git a/media/libstagefright/yuv/Android.mk b/media/libstagefright/yuv/Android.mk
index dc67288..f2fd3be 100644
--- a/media/libstagefright/yuv/Android.mk
+++ b/media/libstagefright/yuv/Android.mk
@@ -14,5 +14,6 @@
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index b6de0d9..979143c 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -14,22 +14,16 @@
main_mediaserver.cpp
LOCAL_SHARED_LIBRARIES := \
- libaudioflinger \
- libaudiopolicyservice \
libcamera_metadata\
libcameraservice \
- libicuuc \
libmedialogservice \
libresourcemanagerservice \
libcutils \
- libnbaio \
libmedia \
libmediaplayerservice \
libutils \
- liblog \
libbinder \
- libsoundtriggerservice \
- libradioservice
+ libicuuc \
LOCAL_STATIC_LIBRARIES := \
libicuandroid_utils \
@@ -37,20 +31,12 @@
LOCAL_C_INCLUDES := \
frameworks/av/media/libmediaplayerservice \
- frameworks/av/services/medialog \
- frameworks/av/services/audioflinger \
- frameworks/av/services/audiopolicy \
- frameworks/av/services/audiopolicy/common/managerdefinitions/include \
- frameworks/av/services/audiopolicy/common/include \
- frameworks/av/services/audiopolicy/engine/interface \
frameworks/av/services/camera/libcameraservice \
frameworks/av/services/mediaresourcemanager \
- $(call include-path-for, audio-utils) \
- frameworks/av/services/soundtrigger \
- frameworks/av/services/radio \
- external/sonic
LOCAL_MODULE:= mediaserver
LOCAL_32_BIT_ONLY := true
+LOCAL_INIT_RC := mediaserver.rc
+
include $(BUILD_EXECUTABLE)
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 4a485ed..e9dede9 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -18,126 +18,31 @@
#define LOG_TAG "mediaserver"
//#define LOG_NDEBUG 0
-#include <fcntl.h>
-#include <sys/prctl.h>
-#include <sys/wait.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
-#include <cutils/properties.h>
#include <utils/Log.h>
#include "RegisterExtensions.h"
// from LOCAL_C_INCLUDES
-#include "AudioFlinger.h"
#include "CameraService.h"
#include "IcuUtils.h"
-#include "MediaLogService.h"
#include "MediaPlayerService.h"
#include "ResourceManagerService.h"
-#include "service/AudioPolicyService.h"
-#include "SoundTriggerHwService.h"
-#include "RadioService.h"
using namespace android;
-int main(int argc __unused, char** argv)
+int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
- char value[PROPERTY_VALUE_MAX];
- bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
- pid_t childPid;
- // FIXME The advantage of making the process containing media.log service the parent process of
- // the process that contains all the other real services, is that it allows us to collect more
- // detailed information such as signal numbers, stop and continue, resource usage, etc.
- // But it is also more complex. Consider replacing this by independent processes, and using
- // binder on death notification instead.
- if (doLog && (childPid = fork()) != 0) {
- // media.log service
- //prctl(PR_SET_NAME, (unsigned long) "media.log", 0, 0, 0);
- // unfortunately ps ignores PR_SET_NAME for the main thread, so use this ugly hack
- strcpy(argv[0], "media.log");
- sp<ProcessState> proc(ProcessState::self());
- MediaLogService::instantiate();
- ProcessState::self()->startThreadPool();
- for (;;) {
- siginfo_t info;
- int ret = waitid(P_PID, childPid, &info, WEXITED | WSTOPPED | WCONTINUED);
- if (ret == EINTR) {
- continue;
- }
- if (ret < 0) {
- break;
- }
- char buffer[32];
- const char *code;
- switch (info.si_code) {
- case CLD_EXITED:
- code = "CLD_EXITED";
- break;
- case CLD_KILLED:
- code = "CLD_KILLED";
- break;
- case CLD_DUMPED:
- code = "CLD_DUMPED";
- break;
- case CLD_STOPPED:
- code = "CLD_STOPPED";
- break;
- case CLD_TRAPPED:
- code = "CLD_TRAPPED";
- break;
- case CLD_CONTINUED:
- code = "CLD_CONTINUED";
- break;
- default:
- snprintf(buffer, sizeof(buffer), "unknown (%d)", info.si_code);
- code = buffer;
- break;
- }
- struct rusage usage;
- getrusage(RUSAGE_CHILDREN, &usage);
- ALOG(LOG_ERROR, "media.log", "pid %d status %d code %s user %ld.%03lds sys %ld.%03lds",
- info.si_pid, info.si_status, code,
- usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000,
- usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000);
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.log"));
- if (binder != 0) {
- Vector<String16> args;
- binder->dump(-1, args);
- }
- switch (info.si_code) {
- case CLD_EXITED:
- case CLD_KILLED:
- case CLD_DUMPED: {
- ALOG(LOG_INFO, "media.log", "exiting");
- _exit(0);
- // not reached
- }
- default:
- break;
- }
- }
- } else {
- // all other services
- if (doLog) {
- prctl(PR_SET_PDEATHSIG, SIGKILL); // if parent media.log dies before me, kill me also
- setpgid(0, 0); // but if I die first, don't kill my parent
- }
- InitializeIcuOrDie();
- sp<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> sm = defaultServiceManager();
- ALOGI("ServiceManager: %p", sm.get());
- AudioFlinger::instantiate();
- MediaPlayerService::instantiate();
- ResourceManagerService::instantiate();
- CameraService::instantiate();
- AudioPolicyService::instantiate();
- SoundTriggerHwService::instantiate();
- RadioService::instantiate();
- registerExtensions();
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
- }
+
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm(defaultServiceManager());
+ ALOGI("ServiceManager: %p", sm.get());
+ InitializeIcuOrDie();
+ MediaPlayerService::instantiate();
+ ResourceManagerService::instantiate();
+ registerExtensions();
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
}
diff --git a/media/mediaserver/mediaserver.rc b/media/mediaserver/mediaserver.rc
new file mode 100644
index 0000000..89c3896
--- /dev/null
+++ b/media/mediaserver/mediaserver.rc
@@ -0,0 +1,5 @@
+service media /system/bin/mediaserver
+ class main
+ user media
+ group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
+ ioprio rt 4
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 052b700..d0ec2a6 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -25,8 +25,6 @@
#include "MtpDataPacket.h"
#include "MtpStringBuffer.h"
-#define MTP_BUFFER_SIZE 16384
-
namespace android {
MtpDataPacket::MtpDataPacket()
@@ -525,16 +523,9 @@
int MtpDataPacket::write(struct usb_request *request) {
MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
-
- // send header separately from data
request->buffer = mBuffer;
- request->buffer_length = MTP_CONTAINER_HEADER_SIZE;
+ request->buffer_length = mPacketSize;
int ret = transfer(request);
- if (ret == MTP_CONTAINER_HEADER_SIZE) {
- request->buffer = mBuffer + MTP_CONTAINER_HEADER_SIZE;
- request->buffer_length = mPacketSize - MTP_CONTAINER_HEADER_SIZE;
- ret = transfer(request);
- }
return (ret < 0 ? ret : 0);
}
@@ -547,17 +538,17 @@
#endif // MTP_HOST
-void* MtpDataPacket::getData(int& outLength) const {
+void* MtpDataPacket::getData(int* outLength) const {
int length = mPacketSize - MTP_CONTAINER_HEADER_SIZE;
if (length > 0) {
void* result = malloc(length);
if (result) {
memcpy(result, mBuffer + MTP_CONTAINER_HEADER_SIZE, length);
- outLength = length;
+ *outLength = length;
return result;
}
}
- outLength = 0;
+ *outLength = 0;
return NULL;
}
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index 13d3bd9..6240f28 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -117,7 +117,7 @@
inline bool hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; }
inline uint32_t getContainerLength() const { return MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET); }
- void* getData(int& outLength) const;
+ void* getData(int* outLength) const;
};
}; // namespace android
diff --git a/media/mtp/MtpDebug.cpp b/media/mtp/MtpDebug.cpp
index 9f3037d..1c04bcf 100644
--- a/media/mtp/MtpDebug.cpp
+++ b/media/mtp/MtpDebug.cpp
@@ -101,6 +101,7 @@
{ "MTP_FORMAT_TIFF_IT", 0x380E },
{ "MTP_FORMAT_JP2", 0x380F },
{ "MTP_FORMAT_JPX", 0x3810 },
+ { "MTP_FORMAT_DNG", 0x3811 },
{ "MTP_FORMAT_UNDEFINED_FIRMWARE", 0xB802 },
{ "MTP_FORMAT_WINDOWS_IMAGE_FORMAT", 0xB881 },
{ "MTP_FORMAT_UNDEFINED_AUDIO", 0xB900 },
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 3eafd6f..7d7ea13 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -19,6 +19,7 @@
#include "MtpDebug.h"
#include "MtpDevice.h"
#include "MtpDeviceInfo.h"
+#include "MtpEventPacket.h"
#include "MtpObjectInfo.h"
#include "MtpProperty.h"
#include "MtpStorageInfo.h"
@@ -50,6 +51,19 @@
}
#endif
+namespace {
+
+bool writeToFd(void* data, uint32_t /* unused_offset */, uint32_t length, void* clientData) {
+ const int fd = *static_cast<int*>(clientData);
+ const ssize_t result = write(fd, data, length);
+ if (result < 0) {
+ return false;
+ }
+ return static_cast<uint32_t>(result) == length;
+}
+
+} // namespace
+
MtpDevice* MtpDevice::open(const char* deviceName, int fd) {
struct usb_device *device = usb_device_new(deviceName, fd);
if (!device) {
@@ -123,6 +137,10 @@
printf("no MTP string\n");
}
}
+#else
+ else {
+ continue;
+ }
#endif
// if we got here, then we have a likely MTP or PTP device
@@ -163,7 +181,13 @@
return NULL;
}
- if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
+ int ret = usb_device_claim_interface(device, interface->bInterfaceNumber);
+ if (ret && errno == EBUSY) {
+ // disconnect kernel driver and try again
+ usb_device_connect_kernel_driver(device, interface->bInterfaceNumber, false);
+ ret = usb_device_claim_interface(device, interface->bInterfaceNumber);
+ }
+ if (ret) {
ALOGE("usb_device_claim_interface failed errno: %d\n", errno);
usb_device_close(device);
return NULL;
@@ -194,7 +218,9 @@
mDeviceInfo(NULL),
mSessionID(0),
mTransactionID(0),
- mReceivedResponse(false)
+ mReceivedResponse(false),
+ mProcessingEvent(false),
+ mCurrentEventHandle(0)
{
mRequestIn1 = usb_request_new(device, ep_in);
mRequestIn2 = usb_request_new(device, ep_in);
@@ -414,7 +440,7 @@
if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
MtpResponseCode ret = readResponse();
if (ret == MTP_RESPONSE_OK) {
- return mData.getData(outLength);
+ return mData.getData(&outLength);
}
}
outLength = 0;
@@ -430,8 +456,9 @@
parent = MTP_PARENT_ROOT;
mRequest.setParameter(1, info->mStorageID);
- mRequest.setParameter(2, info->mParent);
+ mRequest.setParameter(2, parent);
+ mData.reset();
mData.putUInt32(info->mStorageID);
mData.putUInt16(info->mFormat);
mData.putUInt16(info->mProtectionStatus);
@@ -472,17 +499,18 @@
return (MtpObjectHandle)-1;
}
-bool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
+bool MtpDevice::sendObject(MtpObjectHandle handle, int size, int srcFD) {
Mutex::Autolock autoLock(mMutex);
- int remaining = info->mCompressedSize;
+ int remaining = size;
mRequest.reset();
- mRequest.setParameter(1, info->mHandle);
+ mRequest.setParameter(1, handle);
if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
// send data header
writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
- char buffer[65536];
+ // USB writes greater than 16K don't work
+ char buffer[MTP_BUFFER_SIZE];
while (remaining > 0) {
int count = read(srcFD, buffer, sizeof(buffer));
if (count > 0) {
@@ -592,97 +620,12 @@
}
bool MtpDevice::readObject(MtpObjectHandle handle,
- bool (* callback)(void* data, int offset, int length, void* clientData),
- size_t objectSize, void* clientData) {
- Mutex::Autolock autoLock(mMutex);
- bool result = false;
-
- mRequest.reset();
- mRequest.setParameter(1, handle);
- if (sendRequest(MTP_OPERATION_GET_OBJECT)
- && mData.readDataHeader(mRequestIn1)) {
- uint32_t length = mData.getContainerLength();
- if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) {
- ALOGE("readObject error objectSize: %d, length: %d",
- objectSize, length);
- goto fail;
- }
- length -= MTP_CONTAINER_HEADER_SIZE;
- uint32_t remaining = length;
- int offset = 0;
-
- int initialDataLength = 0;
- void* initialData = mData.getData(initialDataLength);
- if (initialData) {
- if (initialDataLength > 0) {
- if (!callback(initialData, 0, initialDataLength, clientData))
- goto fail;
- remaining -= initialDataLength;
- offset += initialDataLength;
- }
- free(initialData);
- }
-
- // USB reads greater than 16K don't work
- char buffer1[16384], buffer2[16384];
- mRequestIn1->buffer = buffer1;
- mRequestIn2->buffer = buffer2;
- struct usb_request* req = mRequestIn1;
- void* writeBuffer = NULL;
- int writeLength = 0;
-
- while (remaining > 0 || writeBuffer) {
- if (remaining > 0) {
- // queue up a read request
- req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
- if (mData.readDataAsync(req)) {
- ALOGE("readDataAsync failed");
- goto fail;
- }
- } else {
- req = NULL;
- }
-
- if (writeBuffer) {
- // write previous buffer
- if (!callback(writeBuffer, offset, writeLength, clientData)) {
- ALOGE("write failed");
- // wait for pending read before failing
- if (req)
- mData.readDataWait(mDevice);
- goto fail;
- }
- offset += writeLength;
- writeBuffer = NULL;
- }
-
- // wait for read to complete
- if (req) {
- int read = mData.readDataWait(mDevice);
- if (read < 0)
- goto fail;
-
- if (read > 0) {
- writeBuffer = req->buffer;
- writeLength = read;
- remaining -= read;
- req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
- } else {
- writeBuffer = NULL;
- }
- }
- }
-
- MtpResponseCode response = readResponse();
- if (response == MTP_RESPONSE_OK)
- result = true;
- }
-
-fail:
- return result;
+ ReadObjectCallback callback,
+ uint32_t expectedLength,
+ void* clientData) {
+ return readObjectInternal(handle, callback, &expectedLength, clientData);
}
-
// reads the object's data and writes it to the specified file path
bool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
ALOGD("readObject: %s", destPath);
@@ -698,89 +641,176 @@
fchmod(fd, perm);
umask(mask);
+ bool result = readObject(handle, fd);
+ ::close(fd);
+ return result;
+}
+
+bool MtpDevice::readObject(MtpObjectHandle handle, int fd) {
+ ALOGD("readObject: %d", fd);
+ return readObjectInternal(handle, writeToFd, NULL /* expected size */, &fd);
+}
+
+bool MtpDevice::readObjectInternal(MtpObjectHandle handle,
+ ReadObjectCallback callback,
+ const uint32_t* expectedLength,
+ void* clientData) {
Mutex::Autolock autoLock(mMutex);
- bool result = false;
mRequest.reset();
mRequest.setParameter(1, handle);
- if (sendRequest(MTP_OPERATION_GET_OBJECT)
- && mData.readDataHeader(mRequestIn1)) {
- uint32_t length = mData.getContainerLength();
- if (length < MTP_CONTAINER_HEADER_SIZE)
- goto fail;
- length -= MTP_CONTAINER_HEADER_SIZE;
- uint32_t remaining = length;
+ if (!sendRequest(MTP_OPERATION_GET_OBJECT)) {
+ ALOGE("Failed to send a read request.");
+ return false;
+ }
+ return readData(callback, expectedLength, nullptr, clientData);
+}
+
+bool MtpDevice::readData(ReadObjectCallback callback,
+ const uint32_t* expectedLength,
+ uint32_t* writtenSize,
+ void* clientData) {
+ if (!mData.readDataHeader(mRequestIn1)) {
+ ALOGE("Failed to read header.");
+ return false;
+ }
+
+ if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
+ mResponse.copyFrom(mData);
+ return mResponse.getResponseCode() == MTP_RESPONSE_OK ? 0 : -1;
+ }
+
+ // If object size 0 byte, the remote device can reply response packet
+ // without sending any data packets.
+ if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
+ mResponse.copyFrom(mData);
+ return mResponse.getResponseCode() == MTP_RESPONSE_OK;
+ }
+
+ const uint32_t fullLength = mData.getContainerLength();
+ if (fullLength < MTP_CONTAINER_HEADER_SIZE) {
+ ALOGE("fullLength is too short: %d", fullLength);
+ return false;
+ }
+ const uint32_t length = fullLength - MTP_CONTAINER_HEADER_SIZE;
+ if (expectedLength && length != *expectedLength) {
+ ALOGE("readObject error length: %d", fullLength);
+ return false;
+ }
+
+ uint32_t offset = 0;
+ bool writingError = false;
+
+ {
int initialDataLength = 0;
- void* initialData = mData.getData(initialDataLength);
+ void* const initialData = mData.getData(&initialDataLength);
if (initialData) {
if (initialDataLength > 0) {
- if (write(fd, initialData, initialDataLength) != initialDataLength) {
- free(initialData);
- goto fail;
+ if (!callback(initialData, offset, initialDataLength, clientData)) {
+ ALOGE("Failed to write initial data.");
+ writingError = true;
}
- remaining -= initialDataLength;
+ offset += initialDataLength;
}
free(initialData);
}
+ }
- // USB reads greater than 16K don't work
- char buffer1[16384], buffer2[16384];
- mRequestIn1->buffer = buffer1;
- mRequestIn2->buffer = buffer2;
- struct usb_request* req = mRequestIn1;
+ // USB reads greater than 16K don't work.
+ char buffer1[MTP_BUFFER_SIZE], buffer2[MTP_BUFFER_SIZE];
+ mRequestIn1->buffer = buffer1;
+ mRequestIn2->buffer = buffer2;
+ struct usb_request* req = NULL;
+
+ while (offset < length) {
+ // Wait for previous read to complete.
void* writeBuffer = NULL;
int writeLength = 0;
-
- while (remaining > 0 || writeBuffer) {
- if (remaining > 0) {
- // queue up a read request
- req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
- if (mData.readDataAsync(req)) {
- ALOGE("readDataAsync failed");
- goto fail;
- }
- } else {
- req = NULL;
+ if (req) {
+ const int read = mData.readDataWait(mDevice);
+ if (read < 0) {
+ ALOGE("readDataWait failed.");
+ return false;
}
+ writeBuffer = req->buffer;
+ writeLength = read;
+ }
- if (writeBuffer) {
- // write previous buffer
- if (write(fd, writeBuffer, writeLength) != writeLength) {
- ALOGE("write failed");
- // wait for pending read before failing
- if (req)
- mData.readDataWait(mDevice);
- goto fail;
- }
- writeBuffer = NULL;
- }
-
- // wait for read to complete
- if (req) {
- int read = mData.readDataWait(mDevice);
- if (read < 0)
- goto fail;
-
- if (read > 0) {
- writeBuffer = req->buffer;
- writeLength = read;
- remaining -= read;
- req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
- } else {
- writeBuffer = NULL;
- }
+ // Request to read next chunk.
+ const uint32_t nextOffset = offset + writeLength;
+ if (nextOffset < length) {
+ // Queue up a read request.
+ const size_t remaining = length - nextOffset;
+ req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
+ req->buffer_length = remaining > MTP_BUFFER_SIZE ?
+ static_cast<size_t>(MTP_BUFFER_SIZE) : remaining;
+ if (mData.readDataAsync(req) != 0) {
+ ALOGE("readDataAsync failed");
+ return false;
}
}
- MtpResponseCode response = readResponse();
- if (response == MTP_RESPONSE_OK)
- result = true;
+ // Write previous buffer.
+ if (writeBuffer && !writingError) {
+ if (!callback(writeBuffer, offset, writeLength, clientData)) {
+ ALOGE("write failed");
+ writingError = true;
+ }
+ }
+ offset = nextOffset;
}
-fail:
- ::close(fd);
- return result;
+ if (writtenSize) {
+ *writtenSize = length;
+ }
+
+ return readResponse() == MTP_RESPONSE_OK;
+}
+
+bool MtpDevice::readPartialObject(MtpObjectHandle handle,
+ uint32_t offset,
+ uint32_t size,
+ uint32_t *writtenSize,
+ ReadObjectCallback callback,
+ void* clientData) {
+ Mutex::Autolock autoLock(mMutex);
+
+ mRequest.reset();
+ mRequest.setParameter(1, handle);
+ mRequest.setParameter(2, offset);
+ mRequest.setParameter(3, size);
+ if (!sendRequest(MTP_OPERATION_GET_PARTIAL_OBJECT)) {
+ ALOGE("Failed to send a read request.");
+ return false;
+ }
+ // The expected size is null because it requires the exact number of bytes to read though
+ // MTP_OPERATION_GET_PARTIAL_OBJECT allows devices to return shorter length of bytes than
+ // requested. Destination's buffer length should be checked in |callback|.
+ return readData(callback, nullptr /* expected size */, writtenSize, clientData);
+}
+
+bool MtpDevice::readPartialObject64(MtpObjectHandle handle,
+ uint64_t offset,
+ uint32_t size,
+ uint32_t *writtenSize,
+ ReadObjectCallback callback,
+ void* clientData) {
+ Mutex::Autolock autoLock(mMutex);
+
+ mRequest.reset();
+ mRequest.setParameter(1, handle);
+ mRequest.setParameter(2, 0xffffffff & offset);
+ mRequest.setParameter(3, 0xffffffff & (offset >> 32));
+ mRequest.setParameter(4, size);
+ if (!sendRequest(MTP_OPERATION_GET_PARTIAL_OBJECT_64)) {
+ ALOGE("Failed to send a read request.");
+ return false;
+ }
+ // The expected size is null because it requires the exact number of bytes to read though
+ // MTP_OPERATION_GET_PARTIAL_OBJECT_64 allows devices to return shorter length of bytes than
+ // requested. Destination's buffer length should be checked in |callback|.
+ return readData(callback, nullptr /* expected size */, writtenSize, clientData);
}
bool MtpDevice::sendRequest(MtpOperationCode operation) {
@@ -800,7 +830,7 @@
mData.setTransactionID(mRequest.getTransactionID());
int ret = mData.write(mRequestOut);
mData.dump();
- return (ret > 0);
+ return (ret >= 0);
}
bool MtpDevice::readData() {
@@ -851,4 +881,44 @@
}
}
+int MtpDevice::submitEventRequest() {
+ if (mEventMutex.tryLock()) {
+ // An event is being reaped on another thread.
+ return -1;
+ }
+ if (mProcessingEvent) {
+ // An event request was submitted, but no reapEventRequest called so far.
+ return -1;
+ }
+ Mutex::Autolock autoLock(mEventMutexForInterrupt);
+ mEventPacket.sendRequest(mRequestIntr);
+ const int currentHandle = ++mCurrentEventHandle;
+ mProcessingEvent = true;
+ mEventMutex.unlock();
+ return currentHandle;
+}
+
+int MtpDevice::reapEventRequest(int handle, uint32_t (*parameters)[3]) {
+ Mutex::Autolock autoLock(mEventMutex);
+ if (!mProcessingEvent || mCurrentEventHandle != handle || !parameters) {
+ return -1;
+ }
+ mProcessingEvent = false;
+ const int readSize = mEventPacket.readResponse(mRequestIntr->dev);
+ const int result = mEventPacket.getEventCode();
+ // MTP event has three parameters.
+ (*parameters)[0] = mEventPacket.getParameter(1);
+ (*parameters)[1] = mEventPacket.getParameter(2);
+ (*parameters)[2] = mEventPacket.getParameter(3);
+ return readSize != 0 ? result : 0;
+}
+
+void MtpDevice::discardEventRequest(int handle) {
+ Mutex::Autolock autoLock(mEventMutexForInterrupt);
+ if (mCurrentEventHandle != handle) {
+ return;
+ }
+ usb_request_cancel(mRequestIntr);
+}
+
} // namespace android
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index 9b0acbf..ce60811 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -17,8 +17,9 @@
#ifndef _MTP_DEVICE_H
#define _MTP_DEVICE_H
-#include "MtpRequestPacket.h"
+#include "MtpEventPacket.h"
#include "MtpDataPacket.h"
+#include "MtpRequestPacket.h"
#include "MtpResponsePacket.h"
#include "MtpTypes.h"
@@ -31,6 +32,7 @@
namespace android {
class MtpDeviceInfo;
+class MtpEventPacket;
class MtpObjectInfo;
class MtpStorageInfo;
@@ -53,17 +55,27 @@
MtpRequestPacket mRequest;
MtpDataPacket mData;
MtpResponsePacket mResponse;
+ MtpEventPacket mEventPacket;
+
// set to true if we received a response packet instead of a data packet
bool mReceivedResponse;
+ bool mProcessingEvent;
+ int mCurrentEventHandle;
// to ensure only one MTP transaction at a time
Mutex mMutex;
+ Mutex mEventMutex;
+ Mutex mEventMutexForInterrupt;
public:
- MtpDevice(struct usb_device* device, int interface,
- const struct usb_endpoint_descriptor *ep_in,
- const struct usb_endpoint_descriptor *ep_out,
- const struct usb_endpoint_descriptor *ep_intr);
+ typedef bool (*ReadObjectCallback)
+ (void* data, uint32_t offset, uint32_t length, void* clientData);
+
+ MtpDevice(struct usb_device* device,
+ int interface,
+ const struct usb_endpoint_descriptor *ep_in,
+ const struct usb_endpoint_descriptor *ep_out,
+ const struct usb_endpoint_descriptor *ep_intr);
static MtpDevice* open(const char* deviceName, int fd);
@@ -85,7 +97,7 @@
MtpObjectInfo* getObjectInfo(MtpObjectHandle handle);
void* getThumbnail(MtpObjectHandle handle, int& outLength);
MtpObjectHandle sendObjectInfo(MtpObjectInfo* info);
- bool sendObject(MtpObjectInfo* info, int srcFD);
+ bool sendObject(MtpObjectHandle handle, int size, int srcFD);
bool deleteObject(MtpObjectHandle handle);
MtpObjectHandle getParent(MtpObjectHandle handle);
MtpObjectHandle getStorageID(MtpObjectHandle handle);
@@ -95,20 +107,53 @@
MtpProperty* getDevicePropDesc(MtpDeviceProperty code);
MtpProperty* getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format);
- bool readObject(MtpObjectHandle handle,
- bool (* callback)(void* data, int offset,
- int length, void* clientData),
- size_t objectSize, void* clientData);
+ bool readObject(MtpObjectHandle handle, ReadObjectCallback callback,
+ uint32_t objectSize, void* clientData);
bool readObject(MtpObjectHandle handle, const char* destPath, int group,
int perm);
+ bool readObject(MtpObjectHandle handle, int fd);
+ bool readPartialObject(MtpObjectHandle handle,
+ uint32_t offset,
+ uint32_t size,
+ uint32_t *writtenSize,
+ ReadObjectCallback callback,
+ void* clientData);
+ bool readPartialObject64(MtpObjectHandle handle,
+ uint64_t offset,
+ uint32_t size,
+ uint32_t *writtenSize,
+ ReadObjectCallback callback,
+ void* clientData);
+ // Starts a request to read MTP event from MTP device. It returns a request handle that
+ // can be used for blocking read or cancel. If other thread has already been processing an
+ // event returns -1.
+ int submitEventRequest();
+ // Waits for MTP event from the device and returns MTP event code. It blocks the current thread
+ // until it receives an event from the device. |handle| should be a request handle returned
+ // by |submitEventRequest|. The function writes event parameters to |parameters|. Returns 0 for
+ // cancellations. Returns -1 for errors.
+ int reapEventRequest(int handle, uint32_t (*parameters)[3]);
+ // Cancels an event request. |handle| should be request handle returned by
+ // |submitEventRequest|. If there is a thread blocked by |reapEventRequest| with the same
+ // |handle|, the thread will resume.
+ void discardEventRequest(int handle);
private:
+ // If |objectSize| is not NULL, it checks object size before reading data bytes.
+ bool readObjectInternal(MtpObjectHandle handle,
+ ReadObjectCallback callback,
+ const uint32_t* objectSize,
+ void* clientData);
+ // If |objectSize| is not NULL, it checks object size before reading data bytes.
+ bool readData(ReadObjectCallback callback,
+ const uint32_t* objectSize,
+ uint32_t* writtenData,
+ void* clientData);
bool sendRequest(MtpOperationCode operation);
bool sendData();
bool readData();
bool writeDataHeader(MtpOperationCode operation, int dataLength);
MtpResponseCode readResponse();
-
};
}; // namespace android
diff --git a/media/mtp/MtpEventPacket.cpp b/media/mtp/MtpEventPacket.cpp
index d2fca42..8e13ea9 100644
--- a/media/mtp/MtpEventPacket.cpp
+++ b/media/mtp/MtpEventPacket.cpp
@@ -54,17 +54,26 @@
#endif
#ifdef MTP_HOST
-int MtpEventPacket::read(struct usb_request *request) {
+int MtpEventPacket::sendRequest(struct usb_request *request) {
request->buffer = mBuffer;
request->buffer_length = mBufferSize;
- int ret = transfer(request);
- if (ret >= 0)
- mPacketSize = ret;
- else
- mPacketSize = 0;
- return ret;
+ mPacketSize = 0;
+ if (usb_request_queue(request)) {
+ ALOGE("usb_endpoint_queue failed, errno: %d", errno);
+ return -1;
+ }
+ return 0;
+}
+
+int MtpEventPacket::readResponse(struct usb_device *device) {
+ struct usb_request* const req = usb_request_wait(device);
+ if (req) {
+ mPacketSize = req->actual_length;
+ return req->actual_length;
+ } else {
+ return -1;
+ }
}
#endif
} // namespace android
-
diff --git a/media/mtp/MtpEventPacket.h b/media/mtp/MtpEventPacket.h
index 660baad..a8779fd 100644
--- a/media/mtp/MtpEventPacket.h
+++ b/media/mtp/MtpEventPacket.h
@@ -35,7 +35,8 @@
#ifdef MTP_HOST
// read our buffer with the given request
- int read(struct usb_request *request);
+ int sendRequest(struct usb_request *request);
+ int readResponse(struct usb_device *device);
#endif
inline MtpEventCode getEventCode() const { return getContainerCode(); }
diff --git a/media/mtp/MtpPacket.h b/media/mtp/MtpPacket.h
index 037722a..0e96309 100644
--- a/media/mtp/MtpPacket.h
+++ b/media/mtp/MtpPacket.h
@@ -19,6 +19,7 @@
#include "MtpTypes.h"
+struct usb_device;
struct usb_request;
namespace android {
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 07199e3..3e0f239 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -214,10 +214,11 @@
mResponse.setTransactionID(transaction);
ALOGV("sending response %04X", mResponse.getResponseCode());
ret = mResponse.write(fd);
+ const int savedErrno = errno;
mResponse.dump();
if (ret < 0) {
ALOGE("request write returned %d, errno: %d", ret, errno);
- if (errno == ECANCELED) {
+ if (savedErrno == ECANCELED) {
// return to top of loop and wait for next command
continue;
}
@@ -787,15 +788,19 @@
// then transfer the file
int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
+ if (ret < 0) {
+ if (errno == ECANCELED) {
+ result = MTP_RESPONSE_TRANSACTION_CANCELLED;
+ } else {
+ result = MTP_RESPONSE_GENERAL_ERROR;
+ }
+ } else {
+ result = MTP_RESPONSE_OK;
+ }
+
ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
close(mfr.fd);
- if (ret < 0) {
- if (errno == ECANCELED)
- return MTP_RESPONSE_TRANSACTION_CANCELLED;
- else
- return MTP_RESPONSE_GENERAL_ERROR;
- }
- return MTP_RESPONSE_OK;
+ return result;
}
MtpResponseCode MtpServer::doGetThumb() {
@@ -864,14 +869,15 @@
// transfer the file
int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
- close(mfr.fd);
+ result = MTP_RESPONSE_OK;
if (ret < 0) {
if (errno == ECANCELED)
- return MTP_RESPONSE_TRANSACTION_CANCELLED;
+ result = MTP_RESPONSE_TRANSACTION_CANCELLED;
else
- return MTP_RESPONSE_GENERAL_ERROR;
+ result = MTP_RESPONSE_GENERAL_ERROR;
}
- return MTP_RESPONSE_OK;
+ close(mfr.fd);
+ return result;
}
MtpResponseCode MtpServer::doSendObjectInfo() {
@@ -985,6 +991,7 @@
MtpResponseCode result = MTP_RESPONSE_OK;
mode_t mask;
int ret, initialData;
+ bool isCanceled = false;
if (mSendObjectHandle == kInvalidObjectHandle) {
ALOGE("Expected SendObjectInfo before SendObject");
@@ -1032,6 +1039,10 @@
ALOGV("receiving %s\n", (const char *)mSendObjectFilePath);
// transfer the file
ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+ if ((ret < 0) && (errno == ECANCELED)) {
+ isCanceled = true;
+ }
+
ALOGV("MTP_RECEIVE_FILE returned %d\n", ret);
}
}
@@ -1039,7 +1050,7 @@
if (ret < 0) {
unlink(mSendObjectFilePath);
- if (errno == ECANCELED)
+ if (isCanceled)
result = MTP_RESPONSE_TRANSACTION_CANCELLED;
else
result = MTP_RESPONSE_GENERAL_ERROR;
@@ -1208,6 +1219,7 @@
length -= initialData;
}
+ bool isCanceled = false;
if (ret < 0) {
ALOGE("failed to write initial data");
} else {
@@ -1219,12 +1231,15 @@
// transfer the file
ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+ if ((ret < 0) && (errno == ECANCELED)) {
+ isCanceled = true;
+ }
ALOGV("MTP_RECEIVE_FILE returned %d", ret);
}
}
if (ret < 0) {
mResponse.setParameter(1, 0);
- if (errno == ECANCELED)
+ if (isCanceled)
return MTP_RESPONSE_TRANSACTION_CANCELLED;
else
return MTP_RESPONSE_GENERAL_ERROR;
diff --git a/media/mtp/MtpUtils.cpp b/media/mtp/MtpUtils.cpp
index 0667bdd..ebf3601 100644
--- a/media/mtp/MtpUtils.cpp
+++ b/media/mtp/MtpUtils.cpp
@@ -19,8 +19,6 @@
#include <stdio.h>
#include <time.h>
-#include <../private/bionic_time.h> /* TODO: switch this code to icu4c! */
-
#include "MtpUtils.h"
namespace android {
@@ -32,38 +30,40 @@
DD replaced by the day (01-31), T is a constant character 'T' delimiting time from date,
hh is replaced by the hour (00-23), mm is replaced by the minute (00-59), and ss by the
second (00-59). The ".s" is optional, and represents tenths of a second.
+This is followed by a UTC offset given as "[+-]zzzz" or the literal "Z", meaning UTC.
*/
bool parseDateTime(const char* dateTime, time_t& outSeconds) {
int year, month, day, hour, minute, second;
- struct tm tm;
-
if (sscanf(dateTime, "%04d%02d%02dT%02d%02d%02d",
- &year, &month, &day, &hour, &minute, &second) != 6)
+ &year, &month, &day, &hour, &minute, &second) != 6)
return false;
- const char* tail = dateTime + 15;
+
// skip optional tenth of second
- if (tail[0] == '.' && tail[1])
- tail += 2;
- //FIXME - support +/-hhmm
+ const char* tail = dateTime + 15;
+ if (tail[0] == '.' && tail[1]) tail += 2;
+
+ // FIXME: "Z" means UTC, but non-"Z" doesn't mean local time.
+ // It might be that you're in Asia/Seoul on vacation and your Android
+ // device has noticed this via the network, but your camera was set to
+ // America/Los_Angeles once when you bought it and doesn't know where
+ // it is right now, so the camera says "20160106T081700-0800" but we
+ // just ignore the "-0800" and assume local time which is actually "+0900".
+ // I think to support this (without switching to Java or using icu4c)
+ // you'd want to always use timegm(3) and then manually add/subtract
+ // the UTC offset parsed from the string (taking care of wrapping).
+ // mktime(3) ignores the tm_gmtoff field, so you can't let it do the work.
bool useUTC = (tail[0] == 'Z');
- // hack to compute timezone
- time_t dummy;
- localtime_r(&dummy, &tm);
-
+ struct tm tm = {};
tm.tm_sec = second;
tm.tm_min = minute;
tm.tm_hour = hour;
tm.tm_mday = day;
tm.tm_mon = month - 1; // mktime uses months in 0 - 11 range
tm.tm_year = year - 1900;
- tm.tm_wday = 0;
tm.tm_isdst = -1;
- if (useUTC)
- outSeconds = mktime(&tm);
- else
- outSeconds = mktime_tz(&tm, tm.tm_zone);
+ outSeconds = useUTC ? timegm(&tm) : mktime(&tm);
return true;
}
@@ -73,7 +73,7 @@
localtime_r(&seconds, &tm);
snprintf(buffer, bufferLength, "%04d%02d%02dT%02d%02d%02d",
- tm.tm_year + 1900,
+ tm.tm_year + 1900,
tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range
tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
diff --git a/media/mtp/mtp.h b/media/mtp/mtp.h
index d270df5..adfb102 100644
--- a/media/mtp/mtp.h
+++ b/media/mtp/mtp.h
@@ -37,6 +37,9 @@
#define MTP_CONTAINER_PARAMETER_OFFSET 12
#define MTP_CONTAINER_HEADER_SIZE 12
+// Maximum buffer size for a MTP packet.
+#define MTP_BUFFER_SIZE 16384
+
// MTP Data Types
#define MTP_TYPE_UNDEFINED 0x0000 // Undefined
#define MTP_TYPE_INT8 0x0001 // Signed 8-bit integer
@@ -90,6 +93,7 @@
#define MTP_FORMAT_TIFF_IT 0x380E // Tag Image File Format for Information Technology (graphic arts)
#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_UNDEFINED_FIRMWARE 0xB802
#define MTP_FORMAT_WINDOWS_IMAGE_FORMAT 0xB881
#define MTP_FORMAT_UNDEFINED_AUDIO 0xB900
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index 8f795cd..8dbb291 100644
--- a/media/ndk/Android.mk
+++ b/media/ndk/Android.mk
@@ -27,13 +27,16 @@
NdkMediaFormat.cpp \
NdkMediaMuxer.cpp \
NdkMediaDrm.cpp \
+ NdkImage.cpp \
+ NdkImageReader.cpp \
LOCAL_MODULE:= libmediandk
LOCAL_C_INCLUDES := \
bionic/libc/private \
frameworks/base/core/jni \
- frameworks/av/include/ndk
+ frameworks/av/include/ndk \
+ system/media/camera/include
LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
@@ -44,8 +47,11 @@
libstagefright_foundation \
liblog \
libutils \
+ libcutils \
libandroid_runtime \
libbinder \
+ libgui \
+ libui \
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
new file mode 100644
index 0000000..40900ad
--- /dev/null
+++ b/media/ndk/NdkImage.cpp
@@ -0,0 +1,631 @@
+/*
+ * 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.
+ */
+
+#include <inttypes.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NdkImage"
+
+#include "NdkImagePriv.h"
+#include "NdkImageReaderPriv.h"
+
+#include <utils/Log.h>
+#include "hardware/camera3.h"
+
+using namespace android;
+
+#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
+
+AImage::AImage(AImageReader* reader, int32_t format,
+ CpuConsumer::LockedBuffer* buffer, int64_t timestamp,
+ int32_t width, int32_t height, int32_t numPlanes) :
+ mReader(reader), mFormat(format),
+ mBuffer(buffer), mTimestamp(timestamp),
+ mWidth(width), mHeight(height), mNumPlanes(numPlanes) {
+}
+
+// Can only be called by free() with mLock hold
+AImage::~AImage() {
+ if (!mIsClosed) {
+ LOG_ALWAYS_FATAL(
+ "Error: AImage %p is deleted before returning buffer to AImageReader!", this);
+ }
+}
+
+bool
+AImage::isClosed() const {
+ Mutex::Autolock _l(mLock);
+ return mIsClosed;
+}
+
+void
+AImage::close() {
+ Mutex::Autolock _l(mLock);
+ if (mIsClosed) {
+ return;
+ }
+ sp<AImageReader> reader = mReader.promote();
+ if (reader == nullptr) {
+ LOG_ALWAYS_FATAL("Error: AImage not closed before AImageReader close!");
+ return;
+ }
+ reader->releaseImageLocked(this);
+ // Should have been set to nullptr in releaseImageLocked
+ // Set to nullptr here for extra safety only
+ mBuffer = nullptr;
+ mIsClosed = true;
+}
+
+void
+AImage::free() {
+ if (!isClosed()) {
+ ALOGE("Cannot free AImage before close!");
+ return;
+ }
+ Mutex::Autolock _l(mLock);
+ delete this;
+}
+
+void
+AImage::lockReader() const {
+ sp<AImageReader> reader = mReader.promote();
+ if (reader == nullptr) {
+ // Reader has been closed
+ return;
+ }
+ reader->mLock.lock();
+}
+
+void
+AImage::unlockReader() const {
+ sp<AImageReader> reader = mReader.promote();
+ if (reader == nullptr) {
+ // Reader has been closed
+ return;
+ }
+ reader->mLock.unlock();
+}
+
+media_status_t
+AImage::getWidth(int32_t* width) const {
+ if (width == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ *width = -1;
+ if (isClosed()) {
+ ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+ *width = mWidth;
+ return AMEDIA_OK;
+}
+
+media_status_t
+AImage::getHeight(int32_t* height) const {
+ if (height == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ *height = -1;
+ if (isClosed()) {
+ ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+ *height = mHeight;
+ return AMEDIA_OK;
+}
+
+media_status_t
+AImage::getFormat(int32_t* format) const {
+ if (format == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ *format = -1;
+ if (isClosed()) {
+ ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+ *format = mFormat;
+ return AMEDIA_OK;
+}
+
+media_status_t
+AImage::getNumPlanes(int32_t* numPlanes) const {
+ if (numPlanes == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ *numPlanes = -1;
+ if (isClosed()) {
+ ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+ *numPlanes = mNumPlanes;
+ return AMEDIA_OK;
+}
+
+media_status_t
+AImage::getTimestamp(int64_t* timestamp) const {
+ if (timestamp == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ *timestamp = -1;
+ if (isClosed()) {
+ ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+ *timestamp = mTimestamp;
+ return AMEDIA_OK;
+}
+
+media_status_t
+AImage::getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const {
+ if (planeIdx < 0 || planeIdx >= mNumPlanes) {
+ ALOGE("Error: planeIdx %d out of bound [0,%d]",
+ planeIdx, mNumPlanes - 1);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ if (pixelStride == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ if (isClosed()) {
+ ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+ int32_t fmt = mBuffer->flexFormat;
+ switch (fmt) {
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ *pixelStride = (planeIdx == 0) ? 1 : mBuffer->chromaStep;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ *pixelStride = (planeIdx == 0) ? 1 : 2;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_Y8:
+ *pixelStride = 1;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_YV12:
+ *pixelStride = 1;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_Y16:
+ case HAL_PIXEL_FORMAT_RAW16:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ // Single plane 16bpp data.
+ *pixelStride = 2;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ *pixelStride = 4;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ // Single plane, 24bpp.
+ *pixelStride = 3;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_BLOB:
+ case HAL_PIXEL_FORMAT_RAW10:
+ case HAL_PIXEL_FORMAT_RAW12:
+ case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+ // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
+ // those are single plane data without pixel stride defined
+ return AMEDIA_ERROR_UNSUPPORTED;
+ default:
+ ALOGE("Pixel format: 0x%x is unsupported", fmt);
+ return AMEDIA_ERROR_UNSUPPORTED;
+ }
+}
+
+media_status_t
+AImage::getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const {
+ if (planeIdx < 0 || planeIdx >= mNumPlanes) {
+ ALOGE("Error: planeIdx %d out of bound [0,%d]",
+ planeIdx, mNumPlanes - 1);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ if (rowStride == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ if (isClosed()) {
+ ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+ int32_t fmt = mBuffer->flexFormat;
+ switch (fmt) {
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ *rowStride = (planeIdx == 0) ? mBuffer->stride : mBuffer->chromaStride;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ *rowStride = mBuffer->width;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_YV12:
+ if (mBuffer->stride % 16) {
+ ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ *rowStride = (planeIdx == 0) ? mBuffer->stride : ALIGN(mBuffer->stride / 2, 16);
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_RAW10:
+ case HAL_PIXEL_FORMAT_RAW12:
+ // RAW10 and RAW12 are used for 10-bit and 12-bit raw data, they are single plane
+ *rowStride = mBuffer->stride;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_Y8:
+ if (mBuffer->stride % 16) {
+ ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ *rowStride = mBuffer->stride;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_Y16:
+ case HAL_PIXEL_FORMAT_RAW16:
+ // In native side, strides are specified in pixels, not in bytes.
+ // Single plane 16bpp bayer data. even width/height,
+ // row stride multiple of 16 pixels (32 bytes)
+ if (mBuffer->stride % 16) {
+ ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ *rowStride = mBuffer->stride * 2;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ *rowStride = mBuffer->stride * 2;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ *rowStride = mBuffer->stride * 4;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ // Single plane, 24bpp.
+ *rowStride = mBuffer->stride * 3;
+ return AMEDIA_OK;
+ case HAL_PIXEL_FORMAT_BLOB:
+ case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+ // Blob is used for JPEG/Raw opaque data. It is single plane and has 0 row stride and
+ // no row stride defined
+ return AMEDIA_ERROR_UNSUPPORTED;
+ default:
+ ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
+ return AMEDIA_ERROR_UNSUPPORTED;
+ }
+}
+
+uint32_t
+AImage::getJpegSize() const {
+ if (mBuffer == nullptr) {
+ LOG_ALWAYS_FATAL("Error: buffer is null");
+ }
+
+ uint32_t size = 0;
+ uint32_t width = mBuffer->width;
+ uint8_t* jpegBuffer = mBuffer->data;
+
+ // First check for JPEG transport header at the end of the buffer
+ uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
+ struct camera3_jpeg_blob* blob = (struct camera3_jpeg_blob*)(header);
+ if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
+ size = blob->jpeg_size;
+ ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
+ }
+
+ // failed to find size, default to whole buffer
+ if (size == 0) {
+ /*
+ * This is a problem because not including the JPEG header
+ * means that in certain rare situations a regular JPEG blob
+ * will be misidentified as having a header, in which case
+ * we will get a garbage size value.
+ */
+ ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
+ __FUNCTION__, width);
+ size = width;
+ }
+
+ return size;
+}
+
+media_status_t
+AImage::getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const {
+ if (planeIdx < 0 || planeIdx >= mNumPlanes) {
+ ALOGE("Error: planeIdx %d out of bound [0,%d]",
+ planeIdx, mNumPlanes - 1);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ if (data == nullptr || dataLength == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ if (isClosed()) {
+ ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+
+ uint32_t dataSize, ySize, cSize, cStride;
+ uint8_t* cb = nullptr;
+ uint8_t* cr = nullptr;
+ uint8_t* pData = nullptr;
+ int bytesPerPixel = 0;
+ int32_t fmt = mBuffer->flexFormat;
+
+ switch (fmt) {
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ pData = (planeIdx == 0) ? mBuffer->data :
+ (planeIdx == 1) ? mBuffer->dataCb : mBuffer->dataCr;
+ // only map until last pixel
+ if (planeIdx == 0) {
+ dataSize = mBuffer->stride * (mBuffer->height - 1) + mBuffer->width;
+ } else {
+ dataSize = mBuffer->chromaStride * (mBuffer->height / 2 - 1) +
+ mBuffer->chromaStep * (mBuffer->width / 2 - 1) + 1;
+ }
+ break;
+ // NV21
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ cr = mBuffer->data + (mBuffer->stride * mBuffer->height);
+ cb = cr + 1;
+ // only map until last pixel
+ ySize = mBuffer->width * (mBuffer->height - 1) + mBuffer->width;
+ cSize = mBuffer->width * (mBuffer->height / 2 - 1) + mBuffer->width - 1;
+
+ pData = (planeIdx == 0) ? mBuffer->data :
+ (planeIdx == 1) ? cb : cr;
+ dataSize = (planeIdx == 0) ? ySize : cSize;
+ break;
+ case HAL_PIXEL_FORMAT_YV12:
+ // Y and C stride need to be 16 pixel aligned.
+ if (mBuffer->stride % 16) {
+ ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+
+ ySize = mBuffer->stride * mBuffer->height;
+ cStride = ALIGN(mBuffer->stride / 2, 16);
+ cr = mBuffer->data + ySize;
+ cSize = cStride * mBuffer->height / 2;
+ cb = cr + cSize;
+
+ pData = (planeIdx == 0) ? mBuffer->data :
+ (planeIdx == 1) ? cb : cr;
+ dataSize = (planeIdx == 0) ? ySize : cSize;
+ break;
+ case HAL_PIXEL_FORMAT_Y8:
+ // Single plane, 8bpp.
+
+ pData = mBuffer->data;
+ dataSize = mBuffer->stride * mBuffer->height;
+ break;
+ case HAL_PIXEL_FORMAT_Y16:
+ bytesPerPixel = 2;
+
+ pData = mBuffer->data;
+ dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+ break;
+ case HAL_PIXEL_FORMAT_BLOB:
+ // Used for JPEG data, height must be 1, width == size, single plane.
+ if (mBuffer->height != 1) {
+ ALOGE("Jpeg should have height value one but got %d", mBuffer->height);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+
+ pData = mBuffer->data;
+ dataSize = getJpegSize();
+ break;
+ case HAL_PIXEL_FORMAT_RAW16:
+ // Single plane 16bpp bayer data.
+ bytesPerPixel = 2;
+ pData = mBuffer->data;
+ dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+ break;
+ case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+ // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
+ if (mBuffer->height != 1) {
+ ALOGE("RAW_OPAQUE should have height value one but got %d", mBuffer->height);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ pData = mBuffer->data;
+ dataSize = mBuffer->width;
+ break;
+ case HAL_PIXEL_FORMAT_RAW10:
+ // Single plane 10bpp bayer data.
+ if (mBuffer->width % 4) {
+ ALOGE("Width is not multiple of 4 %d", mBuffer->width);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ if (mBuffer->height % 2) {
+ ALOGE("Height is not multiple of 2 %d", mBuffer->height);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ if (mBuffer->stride < (mBuffer->width * 10 / 8)) {
+ ALOGE("stride (%d) should be at least %d",
+ mBuffer->stride, mBuffer->width * 10 / 8);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ pData = mBuffer->data;
+ dataSize = mBuffer->stride * mBuffer->height;
+ break;
+ case HAL_PIXEL_FORMAT_RAW12:
+ // Single plane 10bpp bayer data.
+ if (mBuffer->width % 4) {
+ ALOGE("Width is not multiple of 4 %d", mBuffer->width);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ if (mBuffer->height % 2) {
+ ALOGE("Height is not multiple of 2 %d", mBuffer->height);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ if (mBuffer->stride < (mBuffer->width * 12 / 8)) {
+ ALOGE("stride (%d) should be at least %d",
+ mBuffer->stride, mBuffer->width * 12 / 8);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ pData = mBuffer->data;
+ dataSize = mBuffer->stride * mBuffer->height;
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ // Single plane, 32bpp.
+ bytesPerPixel = 4;
+ pData = mBuffer->data;
+ dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ // Single plane, 16bpp.
+ bytesPerPixel = 2;
+ pData = mBuffer->data;
+ dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ // Single plane, 24bpp.
+ bytesPerPixel = 3;
+ pData = mBuffer->data;
+ dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+ break;
+ default:
+ ALOGE("Pixel format: 0x%x is unsupported", fmt);
+ return AMEDIA_ERROR_UNSUPPORTED;
+ }
+
+ *data = pData;
+ *dataLength = dataSize;
+ return AMEDIA_OK;
+}
+
+EXPORT
+void AImage_delete(AImage* image) {
+ ALOGV("%s", __FUNCTION__);
+ if (image != nullptr) {
+ image->lockReader();
+ image->close();
+ image->unlockReader();
+ if (!image->isClosed()) {
+ LOG_ALWAYS_FATAL("Image close failed!");
+ }
+ image->free();
+ }
+ return;
+}
+
+EXPORT
+media_status_t AImage_getWidth(const AImage* image, /*out*/int32_t* width) {
+ ALOGV("%s", __FUNCTION__);
+ if (image == nullptr || width == nullptr) {
+ ALOGE("%s: bad argument. image %p width %p",
+ __FUNCTION__, image, width);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return image->getWidth(width);
+}
+
+EXPORT
+media_status_t AImage_getHeight(const AImage* image, /*out*/int32_t* height) {
+ ALOGV("%s", __FUNCTION__);
+ if (image == nullptr || height == nullptr) {
+ ALOGE("%s: bad argument. image %p height %p",
+ __FUNCTION__, image, height);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return image->getHeight(height);
+}
+
+EXPORT
+media_status_t AImage_getFormat(const AImage* image, /*out*/int32_t* format) {
+ ALOGV("%s", __FUNCTION__);
+ if (image == nullptr || format == nullptr) {
+ ALOGE("%s: bad argument. image %p format %p",
+ __FUNCTION__, image, format);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return image->getFormat(format);
+}
+
+EXPORT
+media_status_t AImage_getCropRect(const AImage* image, /*out*/AImageCropRect* rect) {
+ ALOGV("%s", __FUNCTION__);
+ if (image == nullptr || rect == nullptr) {
+ ALOGE("%s: bad argument. image %p rect %p",
+ __FUNCTION__, image, rect);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ // For now AImage only supports camera outputs where cropRect is always full window
+ int32_t width = -1;
+ media_status_t ret = image->getWidth(&width);
+ if (ret != AMEDIA_OK) {
+ return ret;
+ }
+ int32_t height = -1;
+ ret = image->getHeight(&height);
+ if (ret != AMEDIA_OK) {
+ return ret;
+ }
+ rect->left = 0;
+ rect->top = 0;
+ rect->right = width;
+ rect->bottom = height;
+ return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AImage_getTimestamp(const AImage* image, /*out*/int64_t* timestampNs) {
+ ALOGV("%s", __FUNCTION__);
+ if (image == nullptr || timestampNs == nullptr) {
+ ALOGE("%s: bad argument. image %p timestampNs %p",
+ __FUNCTION__, image, timestampNs);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return image->getTimestamp(timestampNs);
+}
+
+EXPORT
+media_status_t AImage_getNumberOfPlanes(const AImage* image, /*out*/int32_t* numPlanes) {
+ ALOGV("%s", __FUNCTION__);
+ if (image == nullptr || numPlanes == nullptr) {
+ ALOGE("%s: bad argument. image %p numPlanes %p",
+ __FUNCTION__, image, numPlanes);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return image->getNumPlanes(numPlanes);
+}
+
+EXPORT
+media_status_t AImage_getPlanePixelStride(
+ const AImage* image, int planeIdx, /*out*/int32_t* pixelStride) {
+ ALOGV("%s", __FUNCTION__);
+ if (image == nullptr || pixelStride == nullptr) {
+ ALOGE("%s: bad argument. image %p pixelStride %p",
+ __FUNCTION__, image, pixelStride);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return image->getPlanePixelStride(planeIdx, pixelStride);
+}
+
+EXPORT
+media_status_t AImage_getPlaneRowStride(
+ const AImage* image, int planeIdx, /*out*/int32_t* rowStride) {
+ ALOGV("%s", __FUNCTION__);
+ if (image == nullptr || rowStride == nullptr) {
+ ALOGE("%s: bad argument. image %p rowStride %p",
+ __FUNCTION__, image, rowStride);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return image->getPlaneRowStride(planeIdx, rowStride);
+}
+
+EXPORT
+media_status_t AImage_getPlaneData(
+ const AImage* image, int planeIdx,
+ /*out*/uint8_t** data, /*out*/int* dataLength) {
+ ALOGV("%s", __FUNCTION__);
+ if (image == nullptr || data == nullptr || dataLength == nullptr) {
+ ALOGE("%s: bad argument. image %p data %p dataLength %p",
+ __FUNCTION__, image, data, dataLength);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return image->getPlaneData(planeIdx, data, dataLength);
+}
diff --git a/media/ndk/NdkImagePriv.h b/media/ndk/NdkImagePriv.h
new file mode 100644
index 0000000..89d2b7c
--- /dev/null
+++ b/media/ndk/NdkImagePriv.h
@@ -0,0 +1,81 @@
+/*
+ * 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 _NDK_IMAGE_PRIV_H
+#define _NDK_IMAGE_PRIV_H
+
+#include <inttypes.h>
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+
+#include <gui/CpuConsumer.h>
+
+#include "NdkImageReaderPriv.h"
+#include "NdkImage.h"
+
+
+using namespace android;
+
+// TODO: this only supports ImageReader
+struct AImage {
+ AImage(AImageReader* reader, int32_t format,
+ CpuConsumer::LockedBuffer* buffer, int64_t timestamp,
+ int32_t width, int32_t height, int32_t numPlanes);
+
+ // free all resources while keeping object alive. Caller must obtain reader lock
+ void close();
+
+ // Remove from object memory. Must be called after close
+ void free();
+
+ bool isClosed() const ;
+
+ // only For AImage to grab reader lock
+ // Always grab reader lock before grabbing image lock
+ void lockReader() const;
+ void unlockReader() const;
+
+ media_status_t getWidth(/*out*/int32_t* width) const;
+ media_status_t getHeight(/*out*/int32_t* height) const;
+ media_status_t getFormat(/*out*/int32_t* format) const;
+ media_status_t getNumPlanes(/*out*/int32_t* numPlanes) const;
+ media_status_t getTimestamp(/*out*/int64_t* timestamp) const;
+
+ media_status_t getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const;
+ media_status_t getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const;
+ media_status_t getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const;
+
+ private:
+ // AImage should be deleted through free() API.
+ ~AImage();
+
+ friend struct AImageReader; // for reader to access mBuffer
+
+ uint32_t getJpegSize() const;
+
+ // When reader is close, AImage will only accept close API call
+ wp<AImageReader> mReader;
+ const int32_t mFormat;
+ CpuConsumer::LockedBuffer* mBuffer;
+ const int64_t mTimestamp;
+ const int32_t mWidth;
+ const int32_t mHeight;
+ const int32_t mNumPlanes;
+ bool mIsClosed = false;
+ mutable Mutex mLock;
+};
+
+#endif // _NDK_IMAGE_PRIV_H
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
new file mode 100644
index 0000000..d57a86e
--- /dev/null
+++ b/media/ndk/NdkImageReader.cpp
@@ -0,0 +1,581 @@
+/*
+ * 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.
+ */
+
+#include <inttypes.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NdkImageReader"
+
+#include "NdkImagePriv.h"
+#include "NdkImageReaderPriv.h"
+
+#include <utils/Log.h>
+#include <android_runtime/android_view_Surface.h>
+
+using namespace android;
+
+namespace {
+ // Get an ID that's unique within this process.
+ static int32_t createProcessUniqueId() {
+ static volatile int32_t globalCounter = 0;
+ return android_atomic_inc(&globalCounter);
+ }
+}
+
+const char* AImageReader::kCallbackFpKey = "Callback";
+const char* AImageReader::kContextKey = "Context";
+
+bool
+AImageReader::isSupportedFormat(int32_t format) {
+ switch (format) {
+ case AIMAGE_FORMAT_YUV_420_888:
+ case AIMAGE_FORMAT_JPEG:
+ case AIMAGE_FORMAT_RAW16:
+ case AIMAGE_FORMAT_RAW_PRIVATE:
+ case AIMAGE_FORMAT_RAW10:
+ case AIMAGE_FORMAT_RAW12:
+ case AIMAGE_FORMAT_DEPTH16:
+ case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+int
+AImageReader::getNumPlanesForFormat(int32_t format) {
+ switch (format) {
+ case AIMAGE_FORMAT_YUV_420_888:
+ return 3;
+ case AIMAGE_FORMAT_JPEG:
+ case AIMAGE_FORMAT_RAW16:
+ case AIMAGE_FORMAT_RAW_PRIVATE:
+ case AIMAGE_FORMAT_RAW10:
+ case AIMAGE_FORMAT_RAW12:
+ case AIMAGE_FORMAT_DEPTH16:
+ case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
+ return 1;
+ default:
+ return -1;
+ }
+}
+
+void
+AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
+ Mutex::Autolock _l(mLock);
+ sp<AImageReader> reader = mReader.promote();
+ if (reader == nullptr) {
+ ALOGW("A frame is available after AImageReader closed!");
+ return; // reader has been closed
+ }
+ if (mListener.onImageAvailable == nullptr) {
+ return; // No callback registered
+ }
+
+ sp<AMessage> msg = new AMessage(AImageReader::kWhatImageAvailable, reader->mHandler);
+ msg->setPointer(AImageReader::kCallbackFpKey, (void *) mListener.onImageAvailable);
+ msg->setPointer(AImageReader::kContextKey, mListener.context);
+ msg->post();
+}
+
+media_status_t
+AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listener) {
+ Mutex::Autolock _l(mLock);
+ if (listener == nullptr) {
+ ALOGE("AImageReader: listener is null!");
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ mListener = *listener;
+ return AMEDIA_OK;
+}
+
+media_status_t
+AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
+ return mFrameListener->setImageListener(listener);
+}
+
+media_status_t
+AImageReader::setImageListener(AImageReader_ImageListener* listener) {
+ Mutex::Autolock _l(mLock);
+ return setImageListenerLocked(listener);
+}
+
+void AImageReader::CallbackHandler::onMessageReceived(
+ const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatImageAvailable:
+ {
+ AImageReader_ImageCallback onImageAvailable;
+ void* context;
+ bool found = msg->findPointer(kCallbackFpKey, (void**) &onImageAvailable);
+ if (!found || onImageAvailable == nullptr) {
+ ALOGE("%s: Cannot find onImageAvailable callback fp!", __FUNCTION__);
+ return;
+ }
+ found = msg->findPointer(kContextKey, &context);
+ if (!found) {
+ ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+ return;
+ }
+ (*onImageAvailable)(context, mReader);
+ break;
+ }
+ default:
+ ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
+ break;
+ }
+}
+
+AImageReader::AImageReader(int32_t width, int32_t height, int32_t format, int32_t maxImages) :
+ mWidth(width), mHeight(height), mFormat(format), mMaxImages(maxImages),
+ mNumPlanes(getNumPlanesForFormat(format)),
+ mFrameListener(new FrameListener(this)) {}
+
+media_status_t
+AImageReader::init() {
+ PublicFormat publicFormat = static_cast<PublicFormat>(mFormat);
+ mHalFormat = android_view_Surface_mapPublicFormatToHalFormat(publicFormat);
+ mHalDataSpace = android_view_Surface_mapPublicFormatToHalDataspace(publicFormat);
+
+ sp<IGraphicBufferProducer> gbProducer;
+ sp<IGraphicBufferConsumer> gbConsumer;
+ BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
+
+ sp<CpuConsumer> cpuConsumer;
+ String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
+ mWidth, mHeight, mFormat, mMaxImages, getpid(),
+ createProcessUniqueId());
+
+ cpuConsumer = new CpuConsumer(gbConsumer, mMaxImages, /*controlledByApp*/true);
+ if (cpuConsumer == nullptr) {
+ ALOGE("Failed to allocate CpuConsumer");
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+
+ mCpuConsumer = cpuConsumer;
+ mCpuConsumer->setName(consumerName);
+ mProducer = gbProducer;
+
+ sp<ConsumerBase> consumer = cpuConsumer;
+ consumer->setFrameAvailableListener(mFrameListener);
+
+ status_t res;
+ res = cpuConsumer->setDefaultBufferSize(mWidth, mHeight);
+ if (res != OK) {
+ ALOGE("Failed to set CpuConsumer buffer size");
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ res = cpuConsumer->setDefaultBufferFormat(mHalFormat);
+ if (res != OK) {
+ ALOGE("Failed to set CpuConsumer buffer format");
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ res = cpuConsumer->setDefaultBufferDataSpace(mHalDataSpace);
+ if (res != OK) {
+ ALOGE("Failed to set CpuConsumer buffer dataSpace");
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+
+ mSurface = new Surface(mProducer, /*controlledByApp*/true);
+ if (mSurface == nullptr) {
+ ALOGE("Failed to create surface");
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ mWindow = static_cast<ANativeWindow*>(mSurface.get());
+
+ for (int i = 0; i < mMaxImages; i++) {
+ CpuConsumer::LockedBuffer* buffer = new CpuConsumer::LockedBuffer;
+ mBuffers.push_back(buffer);
+ }
+
+ mCbLooper = new ALooper;
+ mCbLooper->setName(consumerName.string());
+ status_t ret = mCbLooper->start(
+ /*runOnCallingThread*/false,
+ /*canCallJava*/ true,
+ PRIORITY_DEFAULT);
+ mHandler = new CallbackHandler(this);
+ mCbLooper->registerHandler(mHandler);
+
+ return AMEDIA_OK;
+}
+
+AImageReader::~AImageReader() {
+ Mutex::Autolock _l(mLock);
+ AImageReader_ImageListener nullListener = {nullptr, nullptr};
+ setImageListenerLocked(&nullListener);
+
+ if (mCbLooper != nullptr) {
+ mCbLooper->unregisterHandler(mHandler->id());
+ mCbLooper->stop();
+ }
+ mCbLooper.clear();
+ mHandler.clear();
+
+ // Close all previously acquired images
+ for (auto it = mAcquiredImages.begin();
+ it != mAcquiredImages.end(); it++) {
+ AImage* image = *it;
+ image->close();
+ }
+
+ // Delete LockedBuffers
+ for (auto it = mBuffers.begin();
+ it != mBuffers.end(); it++) {
+ delete *it;
+ }
+
+ if (mCpuConsumer != nullptr) {
+ mCpuConsumer->abandon();
+ mCpuConsumer->setFrameAvailableListener(nullptr);
+ }
+}
+
+media_status_t
+AImageReader::acquireCpuConsumerImageLocked(/*out*/AImage** image) {
+ *image = nullptr;
+ CpuConsumer::LockedBuffer* buffer = getLockedBufferLocked();
+ if (buffer == nullptr) {
+ ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
+ " maxImages buffers");
+ return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
+ }
+
+ status_t res = mCpuConsumer->lockNextBuffer(buffer);
+ if (res != NO_ERROR) {
+ returnLockedBufferLocked(buffer);
+ if (res != BAD_VALUE /*no buffers*/) {
+ if (res == NOT_ENOUGH_DATA) {
+ return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
+ } else {
+ ALOGE("%s Fail to lockNextBuffer with error: %d ",
+ __FUNCTION__, res);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ }
+ return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
+ }
+
+ if (buffer->flexFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+ ALOGE("NV21 format is not supported by AImageReader");
+ return AMEDIA_ERROR_UNSUPPORTED;
+ }
+
+ // Check if the left-top corner of the crop rect is origin, we currently assume this point is
+ // zero, will revist this once this assumption turns out problematic.
+ Point lt = buffer->crop.leftTop();
+ if (lt.x != 0 || lt.y != 0) {
+ ALOGE("crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+
+ // Check if the producer buffer configurations match what ImageReader configured.
+ int outputWidth = getBufferWidth(buffer);
+ int outputHeight = getBufferHeight(buffer);
+
+ int readerFmt = mHalFormat;
+ int readerWidth = mWidth;
+ int readerHeight = mHeight;
+
+ if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && (readerFmt != HAL_PIXEL_FORMAT_BLOB) &&
+ (readerWidth != outputWidth || readerHeight != outputHeight)) {
+ ALOGW("%s: Producer buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
+ __FUNCTION__, outputWidth, outputHeight, readerWidth, readerHeight);
+ }
+
+ int bufFmt = buffer->format;
+ if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ bufFmt = buffer->flexFormat;
+ }
+
+ if (readerFmt != bufFmt) {
+ if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt ==
+ HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) {
+ // Special casing for when producer switches to a format compatible with flexible YUV
+ // (HAL_PIXEL_FORMAT_YCbCr_420_888).
+ mHalFormat = bufFmt;
+ ALOGD("%s: Overriding buffer format YUV_420_888 to %x.", __FUNCTION__, bufFmt);
+ } else {
+ // Return the buffer to the queue.
+ mCpuConsumer->unlockBuffer(*buffer);
+ returnLockedBufferLocked(buffer);
+
+ ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
+ buffer->format, readerFmt);
+
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ }
+
+ if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
+ *image = new AImage(this, mFormat, buffer, buffer->timestamp,
+ readerWidth, readerHeight, mNumPlanes);
+ } else {
+ *image = new AImage(this, mFormat, buffer, buffer->timestamp,
+ outputWidth, outputHeight, mNumPlanes);
+ }
+ mAcquiredImages.push_back(*image);
+ return AMEDIA_OK;
+}
+
+CpuConsumer::LockedBuffer*
+AImageReader::getLockedBufferLocked() {
+ if (mBuffers.empty()) {
+ return nullptr;
+ }
+ // Return a LockedBuffer pointer and remove it from the list
+ auto it = mBuffers.begin();
+ CpuConsumer::LockedBuffer* buffer = *it;
+ mBuffers.erase(it);
+ return buffer;
+}
+
+void
+AImageReader::returnLockedBufferLocked(CpuConsumer::LockedBuffer* buffer) {
+ mBuffers.push_back(buffer);
+}
+
+void
+AImageReader::releaseImageLocked(AImage* image) {
+ CpuConsumer::LockedBuffer* buffer = image->mBuffer;
+ if (buffer == nullptr) {
+ // This should not happen, but is not fatal
+ ALOGW("AImage %p has no buffer!", image);
+ return;
+ }
+
+ mCpuConsumer->unlockBuffer(*buffer);
+ returnLockedBufferLocked(buffer);
+ image->mBuffer = nullptr;
+
+ bool found = false;
+ // cleanup acquired image list
+ for (auto it = mAcquiredImages.begin();
+ it != mAcquiredImages.end(); it++) {
+ AImage* readerCopy = *it;
+ if (readerCopy == image) {
+ found = true;
+ mAcquiredImages.erase(it);
+ break;
+ }
+ }
+ if (!found) {
+ ALOGE("Error: AImage %p is not generated by AImageReader %p",
+ image, this);
+ }
+}
+
+int
+AImageReader::getBufferWidth(CpuConsumer::LockedBuffer* buffer) {
+ if (buffer == nullptr) return -1;
+
+ if (!buffer->crop.isEmpty()) {
+ return buffer->crop.getWidth();
+ }
+ return buffer->width;
+}
+
+int
+AImageReader::getBufferHeight(CpuConsumer::LockedBuffer* buffer) {
+ if (buffer == nullptr) return -1;
+
+ if (!buffer->crop.isEmpty()) {
+ return buffer->crop.getHeight();
+ }
+ return buffer->height;
+}
+
+media_status_t
+AImageReader::acquireNextImage(/*out*/AImage** image) {
+ Mutex::Autolock _l(mLock);
+ return acquireCpuConsumerImageLocked(image);
+}
+
+media_status_t
+AImageReader::acquireLatestImage(/*out*/AImage** image) {
+ if (image == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ Mutex::Autolock _l(mLock);
+ *image = nullptr;
+ AImage* prevImage = nullptr;
+ AImage* nextImage = nullptr;
+ media_status_t ret = acquireCpuConsumerImageLocked(&prevImage);
+ if (prevImage == nullptr) {
+ return ret;
+ }
+ for (;;) {
+ ret = acquireCpuConsumerImageLocked(&nextImage);
+ if (nextImage == nullptr) {
+ *image = prevImage;
+ return AMEDIA_OK;
+ }
+ prevImage->close();
+ prevImage->free();
+ prevImage = nextImage;
+ nextImage = nullptr;
+ }
+}
+
+EXPORT
+media_status_t AImageReader_new(
+ int32_t width, int32_t height, int32_t format, int32_t maxImages,
+ /*out*/AImageReader** reader) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (width < 1 || height < 1) {
+ ALOGE("%s: image dimension must be positive: w:%d h:%d",
+ __FUNCTION__, width, height);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (maxImages < 1) {
+ ALOGE("%s: max outstanding image count must be at least 1 (%d)",
+ __FUNCTION__, maxImages);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!AImageReader::isSupportedFormat(format)) {
+ ALOGE("%s: format %d is not supported by AImageReader",
+ __FUNCTION__, format);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (reader == nullptr) {
+ ALOGE("%s: reader argument is null", __FUNCTION__);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+
+ //*reader = new AImageReader(width, height, format, maxImages);
+ AImageReader* tmpReader = new AImageReader(width, height, format, maxImages);
+ if (tmpReader == nullptr) {
+ ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ media_status_t ret = tmpReader->init();
+ if (ret != AMEDIA_OK) {
+ ALOGE("%s: AImageReader initialization failed!", __FUNCTION__);
+ delete tmpReader;
+ return ret;
+ }
+ *reader = tmpReader;
+ (*reader)->incStrong((void*) AImageReader_new);
+ return AMEDIA_OK;
+}
+
+EXPORT
+void AImageReader_delete(AImageReader* reader) {
+ ALOGV("%s", __FUNCTION__);
+ if (reader != nullptr) {
+ reader->decStrong((void*) AImageReader_delete);
+ }
+ return;
+}
+
+EXPORT
+media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
+ ALOGE("%s", __FUNCTION__);
+ if (reader == nullptr || window == nullptr) {
+ ALOGE("%s: invalid argument. reader %p, window %p",
+ __FUNCTION__, reader, window);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ *window = reader->getWindow();
+ return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width) {
+ ALOGV("%s", __FUNCTION__);
+ if (reader == nullptr || width == nullptr) {
+ ALOGE("%s: invalid argument. reader %p, width %p",
+ __FUNCTION__, reader, width);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ *width = reader->getWidth();
+ return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height) {
+ ALOGV("%s", __FUNCTION__);
+ if (reader == nullptr || height == nullptr) {
+ ALOGE("%s: invalid argument. reader %p, height %p",
+ __FUNCTION__, reader, height);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ *height = reader->getHeight();
+ return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format) {
+ ALOGV("%s", __FUNCTION__);
+ if (reader == nullptr || format == nullptr) {
+ ALOGE("%s: invalid argument. reader %p, format %p",
+ __FUNCTION__, reader, format);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ *format = reader->getFormat();
+ return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages) {
+ ALOGV("%s", __FUNCTION__);
+ if (reader == nullptr || maxImages == nullptr) {
+ ALOGE("%s: invalid argument. reader %p, maxImages %p",
+ __FUNCTION__, reader, maxImages);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ *maxImages = reader->getMaxImages();
+ return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
+ ALOGV("%s", __FUNCTION__);
+ if (reader == nullptr || image == nullptr) {
+ ALOGE("%s: invalid argument. reader %p, maxImages %p",
+ __FUNCTION__, reader, image);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return reader->acquireNextImage(image);
+}
+
+EXPORT
+media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
+ ALOGV("%s", __FUNCTION__);
+ if (reader == nullptr || image == nullptr) {
+ ALOGE("%s: invalid argument. reader %p, maxImages %p",
+ __FUNCTION__, reader, image);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return reader->acquireLatestImage(image);
+}
+
+EXPORT
+media_status_t AImageReader_setImageListener(
+ AImageReader* reader, AImageReader_ImageListener* listener) {
+ ALOGV("%s", __FUNCTION__);
+ if (reader == nullptr || listener == nullptr) {
+ ALOGE("%s: invalid argument! read %p listener %p", __FUNCTION__, reader, listener);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+
+ reader->setImageListener(listener);
+ return AMEDIA_OK;
+}
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
new file mode 100644
index 0000000..48f0953
--- /dev/null
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -0,0 +1,141 @@
+/*
+ * 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 _NDK_IMAGE_READER_PRIV_H
+#define _NDK_IMAGE_READER_PRIV_H
+
+#include <inttypes.h>
+
+#include "NdkImageReader.h"
+
+#include <utils/List.h>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
+
+#include <gui/CpuConsumer.h>
+#include <gui/Surface.h>
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+using namespace android;
+
+namespace {
+ enum {
+ IMAGE_READER_MAX_NUM_PLANES = 3,
+ };
+
+ enum {
+ ACQUIRE_SUCCESS = 0,
+ ACQUIRE_NO_BUFFERS = 1,
+ ACQUIRE_MAX_IMAGES = 2,
+ };
+}
+
+struct AImageReader : public RefBase {
+ public:
+
+ static bool isSupportedFormat(int32_t format);
+ static int getNumPlanesForFormat(int32_t format);
+
+ AImageReader(int32_t width, int32_t height, int32_t format, int32_t maxImages);
+ ~AImageReader();
+
+ // Inintialize AImageReader, uninitialized or failed to initialize AImageReader
+ // should never be passed to application
+ media_status_t init();
+
+ media_status_t setImageListener(AImageReader_ImageListener* listener);
+
+ media_status_t acquireNextImage(/*out*/AImage** image);
+ media_status_t acquireLatestImage(/*out*/AImage** image);
+
+ ANativeWindow* getWindow() const { return mWindow.get(); };
+ int32_t getWidth() const { return mWidth; };
+ int32_t getHeight() const { return mHeight; };
+ int32_t getFormat() const { return mFormat; };
+ int32_t getMaxImages() const { return mMaxImages; };
+
+
+ private:
+
+ friend struct AImage; // for grabing reader lock
+
+ media_status_t acquireCpuConsumerImageLocked(/*out*/AImage** image);
+ CpuConsumer::LockedBuffer* getLockedBufferLocked();
+ void returnLockedBufferLocked(CpuConsumer::LockedBuffer* buffer);
+
+ // Called by AImage to close image
+ void releaseImageLocked(AImage* image);
+
+ static int getBufferWidth(CpuConsumer::LockedBuffer* buffer);
+ static int getBufferHeight(CpuConsumer::LockedBuffer* buffer);
+
+ media_status_t setImageListenerLocked(AImageReader_ImageListener* listener);
+
+ // definition of handler and message
+ enum {
+ kWhatImageAvailable
+ };
+ static const char* kCallbackFpKey;
+ static const char* kContextKey;
+ class CallbackHandler : public AHandler {
+ public:
+ CallbackHandler(AImageReader* reader) : mReader(reader) {}
+ void onMessageReceived(const sp<AMessage> &msg) override;
+ private:
+ AImageReader* mReader;
+ };
+ sp<CallbackHandler> mHandler;
+ sp<ALooper> mCbLooper; // Looper thread where callbacks actually happen on
+
+ List<CpuConsumer::LockedBuffer*> mBuffers;
+ const int32_t mWidth;
+ const int32_t mHeight;
+ const int32_t mFormat;
+ const int32_t mMaxImages;
+ const int32_t mNumPlanes;
+
+ struct FrameListener : public ConsumerBase::FrameAvailableListener {
+ public:
+ FrameListener(AImageReader* parent) : mReader(parent) {}
+
+ void onFrameAvailable(const BufferItem& item) override;
+
+ media_status_t setImageListener(AImageReader_ImageListener* listener);
+
+ private:
+ AImageReader_ImageListener mListener = {nullptr, nullptr};
+ wp<AImageReader> mReader;
+ Mutex mLock;
+ };
+ sp<FrameListener> mFrameListener;
+
+ int mHalFormat;
+ android_dataspace mHalDataSpace;
+
+ sp<IGraphicBufferProducer> mProducer;
+ sp<Surface> mSurface;
+ sp<CpuConsumer> mCpuConsumer;
+ sp<ANativeWindow> mWindow;
+
+ List<AImage*> mAcquiredImages;
+
+ Mutex mLock;
+};
+
+#endif // _NDK_IMAGE_READER_PRIV_H
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index cd0c462..5bb2dcd 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -359,6 +359,15 @@
return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
}
+EXPORT
+media_status_t AMediaCodec_setOutputSurface(AMediaCodec *mData, ANativeWindow* window) {
+ sp<Surface> surface = NULL;
+ if (window != NULL) {
+ surface = (Surface*) window;
+ }
+ return translate_error(mData->mCodec->setSurface(surface));
+}
+
//EXPORT
media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
void *userdata) {
@@ -372,6 +381,7 @@
uint8_t key[16];
uint8_t iv[16];
cryptoinfo_mode_t mode;
+ cryptoinfo_pattern_t pattern;
size_t *clearbytes;
size_t *encryptedbytes;
} AMediaCodecCryptoInfo;
@@ -391,6 +401,10 @@
subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
}
+ CryptoPlugin::Pattern pattern;
+ pattern.mEncryptBlocks = crypto->pattern.encryptBlocks;
+ pattern.mSkipBlocks = crypto->pattern.skipBlocks;
+
AString errormsg;
status_t err = codec->mCodec->queueSecureInputBuffer(idx,
offset,
@@ -398,7 +412,8 @@
crypto->numsubsamples,
crypto->key,
crypto->iv,
- (CryptoPlugin::Mode) crypto->mode,
+ (CryptoPlugin::Mode)crypto->mode,
+ pattern,
time,
flags,
&errormsg);
@@ -410,6 +425,12 @@
}
+EXPORT
+void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info,
+ cryptoinfo_pattern_t *pattern) {
+ info->pattern.encryptBlocks = pattern->encryptBlocks;
+ info->pattern.skipBlocks = pattern->skipBlocks;
+}
EXPORT
AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
@@ -431,6 +452,8 @@
memcpy(ret->key, key, 16);
memcpy(ret->iv, iv, 16);
ret->mode = mode;
+ ret->pattern.encryptBlocks = 0;
+ ret->pattern.skipBlocks = 0;
// clearbytes and encryptedbytes point at the actual data, which follows
ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp
index 1cc2f1a..af8ffea 100644
--- a/media/ndk/NdkMediaCrypto.cpp
+++ b/media/ndk/NdkMediaCrypto.cpp
@@ -23,10 +23,12 @@
#include "NdkMediaFormatPriv.h"
+#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/StrongPointer.h>
#include <binder/IServiceManager.h>
#include <media/ICrypto.h>
+#include <media/IMediaDrmService.h>
#include <media/IMediaPlayerService.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_util_Binder.h>
@@ -46,19 +48,30 @@
static sp<ICrypto> makeCrypto() {
sp<IServiceManager> sm = defaultServiceManager();
+ sp<ICrypto> crypto;
- sp<IBinder> binder =
- sm->getService(String16("media.player"));
-
- sp<IMediaPlayerService> service =
- interface_cast<IMediaPlayerService>(binder);
-
- if (service == NULL) {
- return NULL;
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("media.mediadrmservice.enable", value, NULL)
+ && (!strcmp("1", value) || !strcasecmp("true", value))) {
+ sp<IBinder> binder =
+ sm->getService(String16("media.drm"));
+ sp<IMediaDrmService> service =
+ interface_cast<IMediaDrmService>(binder);
+ if (service == NULL) {
+ return NULL;
+ }
+ crypto = service->makeCrypto();
+ } else {
+ sp<IBinder> binder =
+ sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> service =
+ interface_cast<IMediaPlayerService>(binder);
+ if (service == NULL) {
+ return NULL;
+ }
+ crypto = service->makeCrypto();
}
- sp<ICrypto> crypto = service->makeCrypto();
-
if (crypto == NULL || (crypto->initCheck() != OK && crypto->initCheck() != NO_INIT)) {
return NULL;
}
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 83a5ba1..ea47d57 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -19,6 +19,7 @@
#include "NdkMediaDrm.h"
+#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/StrongPointer.h>
#include <gui/Surface.h>
@@ -27,6 +28,7 @@
#include <media/IDrmClient.h>
#include <media/stagefright/MediaErrors.h>
#include <binder/IServiceManager.h>
+#include <media/IMediaDrmService.h>
#include <media/IMediaPlayerService.h>
#include <ndk/NdkMediaCrypto.h>
@@ -148,19 +150,30 @@
static sp<IDrm> CreateDrm() {
sp<IServiceManager> sm = defaultServiceManager();
+ sp<IDrm> drm;
- sp<IBinder> binder =
- sm->getService(String16("media.player"));
-
- sp<IMediaPlayerService> service =
- interface_cast<IMediaPlayerService>(binder);
-
- if (service == NULL) {
- return NULL;
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("media.mediadrmservice.enable", value, NULL)
+ && (!strcmp("1", value) || !strcasecmp("true", value))) {
+ sp<IBinder> binder =
+ sm->getService(String16("media.drm"));
+ sp<IMediaDrmService> service =
+ interface_cast<IMediaDrmService>(binder);
+ if (service == NULL) {
+ return NULL;
+ }
+ drm = service->makeDrm();
+ } else {
+ sp<IBinder> binder =
+ sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> service =
+ interface_cast<IMediaPlayerService>(binder);
+ if (service == NULL) {
+ return NULL;
+ }
+ drm = service->makeDrm();
}
- sp<IDrm> drm = service->makeDrm();
-
if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
return NULL;
}
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 0ecd64f..b869c54 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -243,15 +243,27 @@
while (len > 0) {
numentries++;
+ if (len < 16) {
+ ALOGE("invalid PSSH data");
+ return NULL;
+ }
// skip uuid
data += 16;
len -= 16;
// get data length
+ if (len < 4) {
+ ALOGE("invalid PSSH data");
+ return NULL;
+ }
uint32_t datalen = *((uint32_t*)data);
data += 4;
len -= 4;
+ if (len < datalen) {
+ ALOGE("invalid PSSH data");
+ return NULL;
+ }
// skip the data
data += datalen;
len -= datalen;
@@ -265,6 +277,10 @@
// extra pointer for each entry, and an extra size_t for the entire PsshInfo.
size_t newsize = buffer->size() - (sizeof(uint32_t) * numentries) + sizeof(size_t)
+ ((sizeof(void*) + sizeof(size_t)) * numentries);
+ if (newsize <= buffer->size()) {
+ ALOGE("invalid PSSH data");
+ return NULL;
+ }
ex->mPsshBuf = new ABuffer(newsize);
ex->mPsshBuf->setRange(0, newsize);
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index a354d58..5598d5d 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -46,6 +46,10 @@
ALOGV("private ctor");
AMediaFormat* mData = new AMediaFormat();
mData->mFormat = *((sp<AMessage>*)data);
+ if (mData->mFormat == NULL) {
+ ALOGW("got NULL format");
+ mData->mFormat = new AMessage;
+ }
return mData;
}
diff --git a/media/utils/BatteryNotifier.cpp b/media/utils/BatteryNotifier.cpp
index 7f9cd7a..341d391 100644
--- a/media/utils/BatteryNotifier.cpp
+++ b/media/utils/BatteryNotifier.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#define LOG_TAG "BatteryNotifier"
+//#define LOG_NDEBUG 0
+
#include "include/mediautils/BatteryNotifier.h"
#include <binder/IServiceManager.h>
@@ -64,7 +67,7 @@
sp<IBatteryStats> batteryService = getBatteryService_l();
mVideoRefCount = 0;
if (batteryService != nullptr) {
- batteryService->noteResetAudio();
+ batteryService->noteResetVideo();
}
}
@@ -72,7 +75,7 @@
Mutex::Autolock _l(mLock);
sp<IBatteryStats> batteryService = getBatteryService_l();
if (mAudioRefCount == 0 && batteryService != nullptr) {
- batteryService->noteStartAudio(AID_MEDIA);
+ batteryService->noteStartAudio(AID_AUDIOSERVER);
}
mAudioRefCount++;
}
@@ -88,7 +91,7 @@
mAudioRefCount--;
if (mAudioRefCount == 0 && batteryService != nullptr) {
- batteryService->noteStopAudio(AID_MEDIA);
+ batteryService->noteStopAudio(AID_AUDIOSERVER);
}
}
@@ -190,20 +193,25 @@
const String16 name("batterystats");
mBatteryStatService = interface_cast<IBatteryStats>(sm->checkService(name));
if (mBatteryStatService == nullptr) {
- ALOGE("batterystats service unavailable!");
+ // this may occur normally during the init sequence as mediaserver
+ // and audioserver start before the batterystats service is available.
+ ALOGW("batterystats service unavailable!");
return nullptr;
}
mDeathNotifier = new DeathNotifier();
IInterface::asBinder(mBatteryStatService)->linkToDeath(mDeathNotifier);
- // Notify start now if media already started
+ // Notify start now if mediaserver or audioserver is already started.
+ // 1) mediaserver and audioserver is started before batterystats service
+ // 2) batterystats server may have crashed.
if (mVideoRefCount > 0) {
mBatteryStatService->noteStartVideo(AID_MEDIA);
}
if (mAudioRefCount > 0) {
- mBatteryStatService->noteStartAudio(AID_MEDIA);
+ mBatteryStatService->noteStartAudio(AID_AUDIOSERVER);
}
+ // TODO: Notify for camera and flashlight state as well?
}
return mBatteryStatService;
}
diff --git a/radio/IRadioService.cpp b/radio/IRadioService.cpp
index 8c2b3ef..81acf9e 100644
--- a/radio/IRadioService.cpp
+++ b/radio/IRadioService.cpp
@@ -87,7 +87,8 @@
data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
data.writeInt32(handle);
data.writeStrongBinder(IInterface::asBinder(client));
- ALOGV("attach() config %p withAudio %d region %d type %d", config, withAudio, config->region, config->band.type);
+ ALOGV("attach() config %p withAudio %d region %d type %d",
+ config == NULL ? 0 : config, withAudio, config->region, config->band.type);
if (config == NULL) {
data.writeInt32(0);
} else {
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 9b4ba79..302e4dc 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -41,12 +41,12 @@
libaudioresampler \
libaudiospdif \
libaudioutils \
- libcommon_time_client \
libcutils \
libutils \
liblog \
libbinder \
libmedia \
+ libmediautils \
libnbaio \
libhardware \
libhardware_legacy \
@@ -127,6 +127,9 @@
LOCAL_MODULE := libaudioresampler
+# uncomment to disable NEON on architectures that actually do support NEON, for benchmarking
+#LOCAL_CFLAGS += -DUSE_NEON=false
+
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index fab1ef5..4ee8d6c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -56,13 +56,12 @@
#include <powermanager/PowerManager.h>
-#include <common_time/cc_helper.h>
-
#include <media/IMediaLogService.h>
#include <media/nbaio/Pipe.h>
#include <media/nbaio/PipeReader.h>
#include <media/AudioParameter.h>
+#include <mediautils/BatteryNotifier.h>
#include <private/android_filesystem_config.h>
// ----------------------------------------------------------------------------
@@ -108,7 +107,7 @@
// ----------------------------------------------------------------------------
const char *formatToString(audio_format_t format) {
- switch (format & AUDIO_FORMAT_MAIN_MASK) {
+ switch (audio_get_main_format(format)) {
case AUDIO_FORMAT_PCM:
switch (format) {
case AUDIO_FORMAT_PCM_16_BIT: return "pcm16";
@@ -131,6 +130,7 @@
case AUDIO_FORMAT_OPUS: return "opus";
case AUDIO_FORMAT_AC3: return "ac-3";
case AUDIO_FORMAT_E_AC3: return "e-ac-3";
+ case AUDIO_FORMAT_IEC61937: return "iec61937";
default:
break;
}
@@ -184,13 +184,18 @@
mSystemReady(false)
{
getpid_cached = getpid();
- char value[PROPERTY_VALUE_MAX];
- bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
+ // disable media.log until the service is reenabled, see b/26306954
+ const bool doLog = false; // property_get_bool("ro.test_harness", false);
if (doLog) {
mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters",
MemoryHeapBase::READ_ONLY);
}
+ // reset battery stats.
+ // if the audio service has crashed, battery stats could be left
+ // in bad state, reset the state upon service start.
+ BatteryNotifier::getInstance().noteResetAudio();
+
#ifdef TEE_SINK
(void) property_get("ro.debuggable", value, "0");
int debuggable = atoi(value);
@@ -255,16 +260,17 @@
}
// Tell media.log service about any old writers that still need to be unregistered
- sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
- if (binder != 0) {
- sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
- for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
- sp<IMemory> iMemory(mUnregisteredWriters.top()->getIMemory());
- mUnregisteredWriters.pop();
- mediaLogService->unregisterWriter(iMemory);
+ if (mLogMemoryDealer != 0) {
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
+ if (binder != 0) {
+ sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
+ for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
+ sp<IMemory> iMemory(mUnregisteredWriters.top()->getIMemory());
+ mUnregisteredWriters.pop();
+ mediaLogService->unregisterWriter(iMemory);
+ }
}
}
-
}
static const char * const audio_interfaces[] = {
@@ -1156,7 +1162,9 @@
if (ret != NO_ERROR) {
return 0;
}
- if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) {
+ if ((sampleRate == 0) ||
+ !audio_is_valid_format(format) || !audio_has_proportional_frames(format) ||
+ !audio_is_input_channel(channelMask)) {
return 0;
}
@@ -1352,8 +1360,7 @@
AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
: RefBase(),
mAudioFlinger(audioFlinger),
- mPid(pid),
- mTimedTrackCount(0)
+ mPid(pid)
{
size_t heapSize = kClientSharedHeapSizeBytes;
// Increase heap size on non low ram devices to limit risk of reconnection failure for
@@ -1375,31 +1382,6 @@
return mMemoryDealer;
}
-// Reserve one of the limited slots for a timed audio track associated
-// with this client
-bool AudioFlinger::Client::reserveTimedTrack()
-{
- const int kMaxTimedTracksPerClient = 4;
-
- Mutex::Autolock _l(mTimedTrackLock);
-
- if (mTimedTrackCount >= kMaxTimedTracksPerClient) {
- ALOGW("can not create timed track - pid %d has exceeded the limit",
- mPid);
- return false;
- }
-
- mTimedTrackCount++;
- return true;
-}
-
-// Release a slot for a timed audio track
-void AudioFlinger::Client::releaseTimedTrack()
-{
- Mutex::Autolock _l(mTimedTrackLock);
- mTimedTrackCount--;
-}
-
// ----------------------------------------------------------------------------
AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger,
@@ -1451,8 +1433,15 @@
cblk.clear();
buffers.clear();
+ const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ if (!isTrustedCallingUid(callingUid)) {
+ ALOGW_IF((uid_t)clientUid != callingUid,
+ "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, clientUid);
+ clientUid = callingUid;
+ }
+
// check calling permissions
- if (!recordingAllowed(opPackageName)) {
+ if (!recordingAllowed(opPackageName, tid, clientUid)) {
ALOGE("openRecord() permission denied: recording not allowed");
lStatus = PERMISSION_DENIED;
goto Exit;
@@ -1502,7 +1491,6 @@
}
ALOGV("openRecord() lSessionId: %d input %d", lSessionId, input);
- // TODO: the uid should be passed in as a parameter to openRecord
recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
frameCount, lSessionId, notificationFrames,
clientUid, flags, tid, &lStatus);
@@ -2585,7 +2573,7 @@
// check recording permission for visualizer
if ((memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) &&
- !recordingAllowed(opPackageName)) {
+ !recordingAllowed(opPackageName, pid, IPCThreadState::self()->getCallingUid())) {
lStatus = PERMISSION_DENIED;
goto Exit;
}
@@ -2966,8 +2954,7 @@
void *buffer = malloc(TEE_SINK_READ * frameSize);
for (;;) {
size_t count = TEE_SINK_READ;
- ssize_t actual = teeSource->read(buffer, count,
- AudioBufferProvider::kInvalidPTS);
+ ssize_t actual = teeSource->read(buffer, count);
bool wasFirstRead = firstRead;
firstRead = false;
if (actual <= 0) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 08fa70d..f2f11e3 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -23,8 +23,6 @@
#include <sys/types.h>
#include <limits.h>
-#include <common_time/cc_helper.h>
-
#include <cutils/compiler.h>
#include <media/IAudioFlinger.h>
@@ -59,6 +57,7 @@
#include "AudioStreamOut.h"
#include "SpdifStreamOut.h"
#include "AudioHwDevice.h"
+#include "LinearMap.h"
#include <powermanager/IPowerManager.h>
@@ -78,14 +77,6 @@
// ----------------------------------------------------------------------------
-// The macro FCC_2 highlights some (but not all) places where there are are 2-channel assumptions.
-// This is typically due to legacy implementation of stereo input or output.
-// Search also for "2", "left", "right", "[0]", "[1]", ">> 16", "<< 16", etc.
-#define FCC_2 2 // FCC_2 = Fixed Channel Count 2
-// The macro FCC_8 highlights places where there are 8-channel assumptions.
-// This is typically due to audio mixer and resampler limitations.
-#define FCC_8 8 // FCC_8 = Fixed Channel Count 8
-
static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3);
@@ -422,18 +413,12 @@
pid_t pid() const { return mPid; }
sp<AudioFlinger> audioFlinger() const { return mAudioFlinger; }
- bool reserveTimedTrack();
- void releaseTimedTrack();
-
private:
Client(const Client&);
Client& operator = (const Client&);
const sp<AudioFlinger> mAudioFlinger;
sp<MemoryDealer> mMemoryDealer;
const pid_t mPid;
-
- Mutex mTimedTrackLock;
- int mTimedTrackCount;
};
// --- Notification Client ---
@@ -504,12 +489,6 @@
virtual void flush();
virtual void pause();
virtual status_t attachAuxEffect(int effectId);
- virtual status_t allocateTimedBuffer(size_t size,
- sp<IMemory>* buffer);
- virtual status_t queueTimedBuffer(const sp<IMemory>& buffer,
- int64_t pts);
- virtual status_t setMediaTimeTransform(const LinearTransform& xform,
- int target);
virtual status_t setParameters(const String8& keyValuePairs);
virtual status_t getTimestamp(AudioTimestamp& timestamp);
virtual void signal(); // signal playback thread for a change in control block
diff --git a/services/audioflinger/AudioHwDevice.cpp b/services/audioflinger/AudioHwDevice.cpp
index 3191598..7494930 100644
--- a/services/audioflinger/AudioHwDevice.cpp
+++ b/services/audioflinger/AudioHwDevice.cpp
@@ -68,7 +68,7 @@
status);
// If the data is encoded then try again using wrapped PCM.
- bool wrapperNeeded = !audio_is_linear_pcm(originalConfig.format)
+ bool wrapperNeeded = !audio_has_proportional_frames(originalConfig.format)
&& ((flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0)
&& ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0);
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 8a9a837..aea6b67 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -36,8 +36,6 @@
#include <audio_utils/primitives.h>
#include <audio_utils/format.h>
-#include <common_time/local_clock.h>
-#include <common_time/cc_helper.h>
#include "AudioMixerOps.h"
#include "AudioMixer.h"
@@ -786,7 +784,6 @@
mMixerInFormat,
resamplerChannelCount,
devSampleRate, quality);
- resampler->setLocalTimeFreq(sLocalTimeFreq);
}
return true;
}
@@ -906,13 +903,13 @@
}
-void AudioMixer::process(int64_t pts)
+void AudioMixer::process()
{
- mState.hook(&mState, pts);
+ mState.hook(&mState);
}
-void AudioMixer::process__validate(state_t* state, int64_t pts)
+void AudioMixer::process__validate(state_t* state)
{
ALOGW_IF(!state->needsChanged,
"in process__validate() but nothing's invalid");
@@ -1042,7 +1039,7 @@
countActiveTracks, state->enabledTracks,
all16BitsStereoNoResample, resampling, volumeRamp);
- state->hook(state, pts);
+ state->hook(state);
// Now that the volume ramp has been done, set optimal state and
// track hooks for subsequent mixer process
@@ -1367,7 +1364,7 @@
}
// no-op case
-void AudioMixer::process__nop(state_t* state, int64_t pts)
+void AudioMixer::process__nop(state_t* state)
{
ALOGVV("process__nop\n");
uint32_t e0 = state->enabledTracks;
@@ -1401,9 +1398,7 @@
size_t outFrames = state->frameCount;
while (outFrames) {
t3.buffer.frameCount = outFrames;
- int64_t outputPTS = calculateOutputPTS(
- t3, pts, state->frameCount - outFrames);
- t3.bufferProvider->getNextBuffer(&t3.buffer, outputPTS);
+ t3.bufferProvider->getNextBuffer(&t3.buffer);
if (t3.buffer.raw == NULL) break;
outFrames -= t3.buffer.frameCount;
t3.bufferProvider->releaseBuffer(&t3.buffer);
@@ -1414,7 +1409,7 @@
}
// generic code without resampling
-void AudioMixer::process__genericNoResampling(state_t* state, int64_t pts)
+void AudioMixer::process__genericNoResampling(state_t* state)
{
ALOGVV("process__genericNoResampling\n");
int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
@@ -1427,7 +1422,7 @@
e0 &= ~(1<<i);
track_t& t = state->tracks[i];
t.buffer.frameCount = state->frameCount;
- t.bufferProvider->getNextBuffer(&t.buffer, pts);
+ t.bufferProvider->getNextBuffer(&t.buffer);
t.frameCount = t.buffer.frameCount;
t.in = t.buffer.raw;
}
@@ -1486,9 +1481,7 @@
t.bufferProvider->releaseBuffer(&t.buffer);
t.buffer.frameCount = (state->frameCount - numFrames) -
(BLOCKSIZE - outFrames);
- int64_t outputPTS = calculateOutputPTS(
- t, pts, numFrames + (BLOCKSIZE - outFrames));
- t.bufferProvider->getNextBuffer(&t.buffer, outputPTS);
+ t.bufferProvider->getNextBuffer(&t.buffer);
t.in = t.buffer.raw;
if (t.in == NULL) {
enabledTracks &= ~(1<<i);
@@ -1522,7 +1515,7 @@
// generic code with resampling
-void AudioMixer::process__genericResampling(state_t* state, int64_t pts)
+void AudioMixer::process__genericResampling(state_t* state)
{
ALOGVV("process__genericResampling\n");
// this const just means that local variable outTemp doesn't change
@@ -1561,7 +1554,6 @@
// acquire/release the buffers because it's done by
// the resampler.
if (t.needs & NEEDS_RESAMPLE) {
- t.resampler->setPTS(pts);
t.hook(&t, outTemp, numFrames, state->resampleTemp, aux);
} else {
@@ -1569,8 +1561,7 @@
while (outFrames < numFrames) {
t.buffer.frameCount = numFrames - outFrames;
- int64_t outputPTS = calculateOutputPTS(t, pts, outFrames);
- t.bufferProvider->getNextBuffer(&t.buffer, outputPTS);
+ t.bufferProvider->getNextBuffer(&t.buffer);
t.in = t.buffer.raw;
// t.in == NULL can happen if the track was flushed just after having
// been enabled for mixing.
@@ -1592,8 +1583,7 @@
}
// one track, 16 bits stereo without resampling is the most common case
-void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state,
- int64_t pts)
+void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state)
{
ALOGVV("process__OneTrack16BitsStereoNoResampling\n");
// This method is only called when state->enabledTracks has exactly
@@ -1615,8 +1605,7 @@
const uint32_t vrl = t.volumeRL;
while (numFrames) {
b.frameCount = numFrames;
- int64_t outputPTS = calculateOutputPTS(t, pts, out - t.mainBuffer);
- t.bufferProvider->getNextBuffer(&b, outputPTS);
+ t.bufferProvider->getNextBuffer(&b);
const int16_t *in = b.i16;
// in == NULL can happen if the track was flushed just after having
@@ -1677,24 +1666,10 @@
}
}
-int64_t AudioMixer::calculateOutputPTS(const track_t& t, int64_t basePTS,
- int outputFrameIndex)
-{
- if (AudioBufferProvider::kInvalidPTS == basePTS) {
- return AudioBufferProvider::kInvalidPTS;
- }
-
- return basePTS + ((outputFrameIndex * sLocalTimeFreq) / t.sampleRate);
-}
-
-/*static*/ uint64_t AudioMixer::sLocalTimeFreq;
/*static*/ pthread_once_t AudioMixer::sOnceControl = PTHREAD_ONCE_INIT;
/*static*/ void AudioMixer::sInitRoutine()
{
- LocalClock lc;
- sLocalTimeFreq = lc.getLocalFreq(); // for the resampler
-
DownmixerBufferProvider::init(); // for the downmixer
}
@@ -1836,7 +1811,7 @@
* TA: int32_t (Q4.27)
*/
template <int MIXTYPE, typename TO, typename TI, typename TA>
-void AudioMixer::process_NoResampleOneTrack(state_t* state, int64_t pts)
+void AudioMixer::process_NoResampleOneTrack(state_t* state)
{
ALOGVV("process_NoResampleOneTrack\n");
// CLZ is faster than CTZ on ARM, though really not sure if true after 31 - clz.
@@ -1852,8 +1827,7 @@
AudioBufferProvider::Buffer& b(t->buffer);
// get input buffer
b.frameCount = numFrames;
- const int64_t outputPTS = calculateOutputPTS(*t, pts, state->frameCount - numFrames);
- t->bufferProvider->getNextBuffer(&b, outputPTS);
+ t->bufferProvider->getNextBuffer(&b);
const TI *in = reinterpret_cast<TI*>(b.raw);
// in == NULL can happen if the track was flushed just after having
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 7165c6c..e788ac3 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -126,7 +126,7 @@
void setParameter(int name, int target, int param, void *value);
void setBufferProvider(int name, AudioBufferProvider* bufferProvider);
- void process(int64_t pts);
+ void process();
uint32_t trackNames() const { return mTrackNames; }
@@ -278,7 +278,7 @@
void reconfigureBufferProviders();
};
- typedef void (*process_hook_t)(state_t* state, int64_t pts);
+ typedef void (*process_hook_t)(state_t* state);
// pad to 32-bytes to fill cache line
struct state_t {
@@ -328,17 +328,12 @@
static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp,
int32_t* aux);
- static void process__validate(state_t* state, int64_t pts);
- static void process__nop(state_t* state, int64_t pts);
- static void process__genericNoResampling(state_t* state, int64_t pts);
- static void process__genericResampling(state_t* state, int64_t pts);
- static void process__OneTrack16BitsStereoNoResampling(state_t* state,
- int64_t pts);
+ static void process__validate(state_t* state);
+ static void process__nop(state_t* state);
+ static void process__genericNoResampling(state_t* state);
+ static void process__genericResampling(state_t* state);
+ static void process__OneTrack16BitsStereoNoResampling(state_t* state);
- static int64_t calculateOutputPTS(const track_t& t, int64_t basePTS,
- int outputFrameIndex);
-
- static uint64_t sLocalTimeFreq;
static pthread_once_t sOnceControl;
static void sInitRoutine();
@@ -359,7 +354,7 @@
// multi-format process hooks
template <int MIXTYPE, typename TO, typename TI, typename TA>
- static void process_NoResampleOneTrack(state_t* state, int64_t pts);
+ static void process_NoResampleOneTrack(state_t* state);
// multi-format track hooks
template <int MIXTYPE, typename TO, typename TI, typename TA>
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index e49b7b1..4f8b413 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -29,7 +29,8 @@
#include "AudioResamplerDyn.h"
#ifdef __arm__
- #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
+ // bug 13102576
+ //#define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
#endif
namespace android {
@@ -261,8 +262,8 @@
int32_t sampleRate, src_quality quality) :
mChannelCount(inChannelCount),
mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
- mPhaseFraction(0), mLocalTimeFreq(0),
- mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) {
+ mPhaseFraction(0),
+ mQuality(quality) {
const int maxChannels = quality < DYN_LOW_QUALITY ? 2 : 8;
if (inChannelCount < 1
@@ -304,23 +305,6 @@
mVolume[1] = u4_12_from_float(clampFloatVol(right));
}
-void AudioResampler::setLocalTimeFreq(uint64_t freq) {
- mLocalTimeFreq = freq;
-}
-
-void AudioResampler::setPTS(int64_t pts) {
- mPTS = pts;
-}
-
-int64_t AudioResampler::calculateOutputPTS(int outputFrameIndex) {
-
- if (mPTS == AudioBufferProvider::kInvalidPTS) {
- return AudioBufferProvider::kInvalidPTS;
- } else {
- return mPTS + ((outputFrameIndex * mLocalTimeFreq) / mSampleRate);
- }
-}
-
void AudioResampler::reset() {
mInputIndex = 0;
mPhaseFraction = 0;
@@ -368,8 +352,7 @@
// buffer is empty, fetch a new one
while (mBuffer.frameCount == 0) {
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer,
- calculateOutputPTS(outputIndex / 2));
+ provider->getNextBuffer(&mBuffer);
if (mBuffer.raw == NULL) {
goto resampleStereo16_exit;
}
@@ -465,8 +448,7 @@
// buffer is empty, fetch a new one
while (mBuffer.frameCount == 0) {
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer,
- calculateOutputPTS(outputIndex / 2));
+ provider->getNextBuffer(&mBuffer);
if (mBuffer.raw == NULL) {
mInputIndex = inputIndex;
mPhaseFraction = phaseFraction;
diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
index a8e3e6f..c4627e8 100644
--- a/services/audioflinger/AudioResampler.h
+++ b/services/audioflinger/AudioResampler.h
@@ -59,10 +59,6 @@
virtual void init() = 0;
virtual void setSampleRate(int32_t inSampleRate);
virtual void setVolume(float left, float right);
- virtual void setLocalTimeFreq(uint64_t freq);
-
- // set the PTS of the next buffer output by the resampler
- virtual void setPTS(int64_t pts);
// Resample int16_t samples from provider and accumulate into 'out'.
// A mono provider delivers a sequence of samples.
@@ -103,8 +99,6 @@
AudioResampler(const AudioResampler&);
AudioResampler& operator=(const AudioResampler&);
- int64_t calculateOutputPTS(int outputFrameIndex);
-
const int32_t mChannelCount;
const int32_t mSampleRate;
int32_t mInSampleRate;
@@ -117,8 +111,6 @@
size_t mInputIndex;
int32_t mPhaseIncrement;
uint32_t mPhaseFraction;
- uint64_t mLocalTimeFreq;
- int64_t mPTS;
// returns the inFrameCount required to generate outFrameCount frames.
//
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
index 172c2a5..6a324ad 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/services/audioflinger/AudioResamplerCubic.cpp
@@ -66,7 +66,7 @@
// fetch first buffer
if (mBuffer.frameCount == 0) {
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer, mPTS);
+ provider->getNextBuffer(&mBuffer);
if (mBuffer.raw == NULL) {
return 0;
}
@@ -97,8 +97,7 @@
inputIndex = 0;
provider->releaseBuffer(&mBuffer);
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer,
- calculateOutputPTS(outputIndex / 2));
+ provider->getNextBuffer(&mBuffer);
if (mBuffer.raw == NULL) {
goto save_state; // ugly, but efficient
}
@@ -135,7 +134,7 @@
// fetch first buffer
if (mBuffer.frameCount == 0) {
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer, mPTS);
+ provider->getNextBuffer(&mBuffer);
if (mBuffer.raw == NULL) {
return 0;
}
@@ -166,8 +165,7 @@
inputIndex = 0;
provider->releaseBuffer(&mBuffer);
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer,
- calculateOutputPTS(outputIndex / 2));
+ provider->getNextBuffer(&mBuffer);
if (mBuffer.raw == NULL) {
goto save_state; // ugly, but efficient
}
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp
index 6481b85..618b56c 100644
--- a/services/audioflinger/AudioResamplerDyn.cpp
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -527,8 +527,7 @@
// We may not fetch a new buffer if the existing data is sufficient.
while (mBuffer.frameCount == 0 && inFrameCount > 0) {
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer,
- calculateOutputPTS(outputIndex / OUTPUT_CHANNELS));
+ provider->getNextBuffer(&mBuffer);
if (mBuffer.raw == NULL) {
goto resample_exit;
}
diff --git a/services/audioflinger/AudioResamplerFirOps.h b/services/audioflinger/AudioResamplerFirOps.h
index 658285d..2a26496 100644
--- a/services/audioflinger/AudioResamplerFirOps.h
+++ b/services/audioflinger/AudioResamplerFirOps.h
@@ -26,11 +26,15 @@
#endif
#if defined(__aarch64__) || defined(__ARM_NEON__)
+#ifndef USE_NEON
#define USE_NEON (true)
-#include <arm_neon.h>
+#endif
#else
#define USE_NEON (false)
#endif
+#if USE_NEON
+#include <arm_neon.h>
+#endif
template<typename T, typename U>
struct is_same
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
index 41730ee..f600d6c 100644
--- a/services/audioflinger/AudioResamplerSinc.cpp
+++ b/services/audioflinger/AudioResamplerSinc.cpp
@@ -43,10 +43,14 @@
#endif
#if defined(__aarch64__) || defined(__ARM_NEON__)
-#include <arm_neon.h>
-#define USE_NEON
+#ifndef USE_NEON
+#define USE_NEON (true)
+#endif
#else
-#undef USE_NEON
+#define USE_NEON (false)
+#endif
+#if USE_NEON
+#include <arm_neon.h>
#endif
#define UNUSED(x) ((void)(x))
@@ -301,8 +305,7 @@
// buffer is empty, fetch a new one
while (mBuffer.frameCount == 0) {
mBuffer.frameCount = inFrameCount;
- provider->getNextBuffer(&mBuffer,
- calculateOutputPTS(outputIndex / 2));
+ provider->getNextBuffer(&mBuffer);
if (mBuffer.raw == NULL) {
goto resample_exit;
}
@@ -418,7 +421,7 @@
size_t count = offset;
-#ifndef USE_NEON
+#if !USE_NEON
int32_t l = 0;
int32_t r = 0;
for (size_t i=0 ; i<count ; i++) {
diff --git a/services/audioflinger/AudioStreamOut.cpp b/services/audioflinger/AudioStreamOut.cpp
index b6d1be7..6026bbb 100644
--- a/services/audioflinger/AudioStreamOut.cpp
+++ b/services/audioflinger/AudioStreamOut.cpp
@@ -35,7 +35,7 @@
, mFramesWrittenAtStandby(0)
, mRenderPosition(0)
, mRateMultiplier(1)
- , mHalFormatIsLinearPcm(false)
+ , mHalFormatHasProportionalFrames(false)
, mHalFrameSize(0)
{
}
@@ -96,7 +96,7 @@
// Adjust for standby using HAL rate frames.
// Only apply this correction if the HAL is getting PCM frames.
- if (mHalFormatIsLinearPcm) {
+ if (mHalFormatHasProportionalFrames) {
uint64_t adjustedPosition = (halPosition <= mFramesWrittenAtStandby) ?
0 : (halPosition - mFramesWrittenAtStandby);
// Scale from HAL sample rate to application rate.
@@ -116,16 +116,21 @@
const char *address)
{
audio_stream_out_t *outStream;
+
+ audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937)
+ ? (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
+ : flags;
+
int status = hwDev()->open_output_stream(
hwDev(),
handle,
devices,
- flags,
+ customFlags,
config,
&outStream,
address);
- ALOGV("AudioStreamOut::open(), HAL open_output_stream returned "
- " %p, sampleRate %d, Format %#x, "
+ ALOGV("AudioStreamOut::open(), HAL returned "
+ " stream %p, sampleRate %d, Format %#x, "
"channelMask %#x, status %d",
outStream,
config->sample_rate,
@@ -133,10 +138,26 @@
config->channel_mask,
status);
+ // Some HALs may not recognize AUDIO_FORMAT_IEC61937. But if we declare
+ // it as PCM then it will probably work.
+ if (status != NO_ERROR && config->format == AUDIO_FORMAT_IEC61937) {
+ struct audio_config customConfig = *config;
+ customConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+
+ status = hwDev()->open_output_stream(
+ hwDev(),
+ handle,
+ devices,
+ customFlags,
+ &customConfig,
+ &outStream,
+ address);
+ ALOGV("AudioStreamOut::open(), treat IEC61937 as PCM, status = %d", status);
+ }
+
if (status == NO_ERROR) {
stream = outStream;
- mHalFormatIsLinearPcm = audio_is_linear_pcm(config->format);
- ALOGI("AudioStreamOut::open(), mHalFormatIsLinearPcm = %d", (int)mHalFormatIsLinearPcm);
+ mHalFormatHasProportionalFrames = audio_has_proportional_frames(config->format);
mHalFrameSize = audio_stream_out_frame_size(stream);
}
diff --git a/services/audioflinger/AudioStreamOut.h b/services/audioflinger/AudioStreamOut.h
index 06a2277..768f537 100644
--- a/services/audioflinger/AudioStreamOut.h
+++ b/services/audioflinger/AudioStreamOut.h
@@ -106,7 +106,7 @@
uint64_t mFramesWrittenAtStandby;
uint64_t mRenderPosition; // reset by flush or standby
int mRateMultiplier;
- bool mHalFormatIsLinearPcm;
+ bool mHalFormatHasProportionalFrames;
size_t mHalFrameSize;
};
diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp
index a8be206..2ca2cac 100644
--- a/services/audioflinger/BufferProviders.cpp
+++ b/services/audioflinger/BufferProviders.cpp
@@ -70,13 +70,12 @@
free(mLocalBufferData);
}
-status_t CopyBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer,
- int64_t pts)
+status_t CopyBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer)
{
- //ALOGV("CopyBufferProvider(%p)::getNextBuffer(%p (%zu), %lld)",
- // this, pBuffer, pBuffer->frameCount, pts);
+ //ALOGV("CopyBufferProvider(%p)::getNextBuffer(%p (%zu))",
+ // this, pBuffer, pBuffer->frameCount);
if (mLocalBufferFrameCount == 0) {
- status_t res = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
+ status_t res = mTrackBufferProvider->getNextBuffer(pBuffer);
if (res == OK) {
copyFrames(pBuffer->raw, pBuffer->raw, pBuffer->frameCount);
}
@@ -84,7 +83,7 @@
}
if (mBuffer.frameCount == 0) {
mBuffer.frameCount = pBuffer->frameCount;
- status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
+ status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer);
// At one time an upstream buffer provider had
// res == OK and mBuffer.frameCount == 0, doesn't seem to happen now 7/18/2014.
//
@@ -356,13 +355,13 @@
}
status_t TimestretchBufferProvider::getNextBuffer(
- AudioBufferProvider::Buffer *pBuffer, int64_t pts)
+ AudioBufferProvider::Buffer *pBuffer)
{
- ALOGV("TimestretchBufferProvider(%p)::getNextBuffer(%p (%zu), %lld)",
- this, pBuffer, pBuffer->frameCount, pts);
+ ALOGV("TimestretchBufferProvider(%p)::getNextBuffer(%p (%zu))",
+ this, pBuffer, pBuffer->frameCount);
// BYPASS
- //return mTrackBufferProvider->getNextBuffer(pBuffer, pts);
+ //return mTrackBufferProvider->getNextBuffer(pBuffer);
// check if previously processed data is sufficient.
if (pBuffer->frameCount <= mRemaining) {
@@ -391,7 +390,7 @@
mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL
? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1;
- status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
+ status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer);
ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
diff --git a/services/audioflinger/BufferProviders.h b/services/audioflinger/BufferProviders.h
index 4bc895c..abd43c6 100644
--- a/services/audioflinger/BufferProviders.h
+++ b/services/audioflinger/BufferProviders.h
@@ -64,7 +64,7 @@
virtual ~CopyBufferProvider();
// Overrides AudioBufferProvider methods
- virtual status_t getNextBuffer(Buffer *buffer, int64_t pts);
+ virtual status_t getNextBuffer(Buffer *buffer);
virtual void releaseBuffer(Buffer *buffer);
// Overrides PassthruBufferProvider
@@ -156,7 +156,7 @@
virtual ~TimestretchBufferProvider();
// Overrides AudioBufferProvider methods
- virtual status_t getNextBuffer(Buffer* buffer, int64_t pts);
+ virtual status_t getNextBuffer(Buffer* buffer);
virtual void releaseBuffer(Buffer* buffer);
// Overrides PassthruBufferProvider
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index 1bba5f6..bb83858 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -166,8 +166,7 @@
ALOG_ASSERT(mReadBuffer != NULL);
dumpState->mReadSequence++;
ATRACE_BEGIN("read");
- ssize_t framesRead = mInputSource->read(mReadBuffer, frameCount,
- AudioBufferProvider::kInvalidPTS);
+ ssize_t framesRead = mInputSource->read(mReadBuffer, frameCount);
ATRACE_END();
dumpState->mReadSequence++;
if (framesRead >= 0) {
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 45c68b5..1446d19 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -37,12 +37,11 @@
#include <cpustats/ThreadCpuUsage.h>
#endif
#endif
+#include <audio_utils/conversion.h>
#include <audio_utils/format.h>
#include "AudioMixer.h"
#include "FastMixer.h"
-#define FCC_2 2 // fixed channel count assumption
-
namespace android {
/*static*/ const FastMixerState FastMixer::sInitial;
@@ -66,7 +65,8 @@
mFastTracksGen(0),
mTotalNativeFramesWritten(0),
// timestamp
- mNativeFramesWrittenButNotPresented(0) // the = 0 is to silence the compiler
+ mNativeFramesWrittenButNotPresented(0), // the = 0 is to silence the compiler
+ mMasterMono(false)
{
// FIXME pass sInitial as parameter to base class constructor, and make it static local
mPrevious = &sInitial;
@@ -402,13 +402,8 @@
ftDump->mFramesReady = framesReady;
}
- int64_t pts;
- if (mOutputSink == NULL || (OK != mOutputSink->getNextWriteTimestamp(&pts))) {
- pts = AudioBufferProvider::kInvalidPTS;
- }
-
// process() is CPU-bound
- mMixer->process(pts);
+ mMixer->process();
mMixerBufferState = MIXED;
} else if (mMixerBufferState == MIXED) {
mMixerBufferState = UNDEFINED;
@@ -419,6 +414,10 @@
memset(mMixerBuffer, 0, mMixerBufferSize);
mMixerBufferState = ZEROED;
}
+
+ if (mMasterMono.load()) { // memory_order_seq_cst
+ mono_blend(mMixerBuffer, mMixerBufferFormat, Format_channelCount(mFormat), frameCount, true /*limit*/);
+ }
// prepare the buffer used to write to sink
void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer;
if (mFormat.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 06a68fb..e38878e 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_AUDIO_FAST_MIXER_H
#define ANDROID_AUDIO_FAST_MIXER_H
+#include <atomic>
#include "FastThread.h"
#include "StateQueue.h"
#include "FastMixerState.h"
@@ -36,6 +37,8 @@
FastMixerStateQueue* sq();
+ virtual void setMasterMono(bool mono) { mMasterMono.store(mono); /* memory_order_seq_cst */ }
+
private:
FastMixerStateQueue mSQ;
@@ -82,6 +85,8 @@
AudioTimestamp mTimestamp;
uint32_t mNativeFramesWrittenButNotPresented;
+ // accessed without lock between multiple threads.
+ std::atomic_bool mMasterMono;
}; // class FastMixer
} // namespace android
diff --git a/services/audioflinger/LinearMap.h b/services/audioflinger/LinearMap.h
new file mode 100644
index 0000000..fca14dd
--- /dev/null
+++ b/services/audioflinger/LinearMap.h
@@ -0,0 +1,366 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_LINEAR_MAP_H
+#define ANDROID_LINEAR_MAP_H
+
+#include <stdint.h>
+
+namespace android {
+
+/*
+A general purpose lookup utility that defines a mapping between X and Y as a
+continuous set of line segments with shared (x, y) end-points.
+The (x, y) points must be added in order, monotonically increasing in both x and y;
+a log warning is emitted if this does not happen (See general usage notes below).
+
+A limited history of (x, y) points is kept for space reasons (See general usage notes).
+
+In AudioFlinger, we use the LinearMap to associate track frames to
+sink frames. When we want to obtain a client track timestamp, we first
+get a timestamp from the sink. The sink timestamp's position (mPosition)
+corresponds to the sink frames written. We use LinearMap to figure out which track frame
+the sink frame corresponds to. This allows us to substitute a track frame for the
+the sink frame (keeping the mTime identical) and return that timestamp back to the client.
+
+The method findX() can be used to retrieve an x value from a given y value and is
+used for timestamps, similarly for findY() which is provided for completeness.
+
+We update the (track frame, sink frame) points in the LinearMap each time we write data
+to the sink by the AudioFlinger PlaybackThread (MixerThread).
+
+
+AudioFlinger Timestamp Notes:
+
+1) Example: Obtaining a track timestamp during playback. In this case, the LinearMap
+looks something like this:
+
+Track Frame Sink Frame
+(track start)
+0 50000 (track starts here, the sink may already be running)
+1000 51000
+2000 52000
+
+When we request a track timestamp, we call the sink getTimestamp() and get for example
+mPosition = 51020. Using the LinearMap, we find we have played to track frame 1020.
+We substitute the sink mPosition of 51020 with the track position 1020,
+and return that timestamp to the app.
+
+2) Example: Obtaining a track timestamp duing pause. In this case, the LinearMap
+looks something like this:
+
+Track Frame Sink Frame
+... (some time has gone by)
+15000 30000
+16000 31000
+17000 32000
+(pause here)
+(suppose we call sink getTimestamp() here and get sink mPosition = 31100; that means
+ we have played to track frame 16100. The track timestamp mPosition will
+ continue to advance until the sink timestamp returns a value of mPosition
+ greater than 32000, corresponding to track frame 17000 when the pause was called).
+17000 33000
+17000 34000
+...
+
+3) If the track underruns, it appears as if a pause was called on that track.
+
+4) If there is an underrun in the HAL layer, then it may be possible that
+the sink getTimestamp() will return a value greater than the number of frames written
+(it should always be less). This should be rare, if not impossible by some
+HAL implementations of the sink getTimestamp. In that case, timing is lost
+and we will return the most recent track frame written.
+
+5) When called with no points in the map, findX() returns the start value (default 0).
+This is consistent with starting after a stop() or flush().
+
+6) Resuming after Track standby will be similar to coming out of pause, as the HAL ensures
+framesWritten() and getTimestamp() are contiguous for non-offloaded/direct tracks.
+
+7) LinearMap works for different speeds and sample rates as it uses
+linear interpolation. Since AudioFlinger only updates speed and sample rate
+exactly at the sample points pushed into the LinearMap, the returned values
+from findX() and findY() are accurate regardless of how many speed or sample
+rate changes are made, so long as the coordinate looked up is within the
+sample history.
+
+General usage notes:
+
+1) In order for the LinearMap to work reliably, you cannot look backwards more
+than the size of its circular buffer history, set upon creation (typically 16).
+If you look back further, the position is extrapolated either from a passed in
+extrapolation parameter or from the oldest line segment.
+
+2) Points must monotonically increase in x and y. The increment between adjacent
+points cannot be greater than signed 32 bits. Wrap in the x, y coordinates are supported,
+since we use differences in our computation.
+
+3) If the frame data is discontinuous (due to stop or flush) call reset() to clear
+the sample counter.
+
+4) If (x, y) are not strictly monotonic increasing, i.e. (x2 > x1) and (y2 > y1),
+then one or both of the inverses y = f(x) or x = g(y) may have multiple solutions.
+In that case, the most recent solution is returned by findX() or findY(). We
+do not warn if (x2 == x1) or (y2 == y1), but we do logcat warn if (x2 < x1) or
+(y2 < y1).
+
+5) Due to rounding it is possible x != findX(findY(x)) or y != findY(findX(y))
+even when the inverse exists. Nevertheless, the values should be close.
+
+*/
+
+template <typename T>
+class LinearMap {
+public:
+ // This enumeration describes the reliability of the findX() or findY() estimation
+ // in descending order.
+ enum FindMethod {
+ FIND_METHOD_INTERPOLATION, // High reliability (errors due to rounding)
+ FIND_METHOD_FORWARD_EXTRAPOLATION, // Reliability based on no future speed changes
+ FIND_METHOD_BACKWARD_EXTRAPOLATION, // Reliability based on prior estimated speed
+ FIND_METHOD_START_VALUE, // No samples in history, using start value
+ };
+
+ LinearMap(size_t size)
+ : mSize(size),
+ mPos(0), // a circular buffer, so could start anywhere. the first sample is at 1.
+ mSamples(0),
+ // mStepValid(false), // only valid if mSamples > 1
+ // mExtrapolateTail(false), // only valid if mSamples > 0
+ mX(new T[size]),
+ mY(new T[size]) { }
+
+ ~LinearMap() {
+ delete[] mX;
+ delete[] mY;
+ }
+
+ // Add a new sample point to the linear map.
+ //
+ // The difference between the new sample and the previous sample
+ // in the x or y coordinate must be less than INT32_MAX for purposes
+ // of the linear interpolation or extrapolation.
+ //
+ // The value should be monotonic increasing (e.g. diff >= 0);
+ // logcat warnings are issued if they are not.
+ __attribute__((no_sanitize("integer")))
+ void push(T x, T y) {
+ // Assumption: we assume x, y are monotonic increasing values,
+ // which (can) wrap in precision no less than 32 bits and have
+ // "step" or differences between adjacent points less than 32 bits.
+
+ if (mSamples > 0) {
+ const bool lastStepValid = mStepValid;
+ int32_t xdiff;
+ int32_t ydiff;
+ // check difference assumption here
+ mStepValid = checkedDiff(&xdiff, x, mX[mPos], "x")
+ & /* bitwise AND to always warn for ydiff, though logical AND is also OK */
+ checkedDiff(&ydiff, y, mY[mPos], "y");
+
+ // Optimization: do not add a new sample if the line segment would
+ // simply extend the previous line segment. This extends the useful
+ // history by removing redundant points.
+ if (mSamples > 1 && mStepValid && lastStepValid) {
+ const size_t prev = previousPosition();
+ const int32_t xdiff2 = x - mX[prev];
+ const int32_t ydiff2 = y - mY[prev];
+
+ // if both current step and previous step are valid (non-negative and
+ // less than INT32_MAX for precision greater than 4 bytes)
+ // then the sum of the two steps is valid when the
+ // int32_t difference is non-negative.
+ if (xdiff2 >= 0 && ydiff2 >= 0
+ && (int64_t)xdiff2 * ydiff == (int64_t)ydiff2 * xdiff) {
+ // ALOGD("reusing sample! (%u, %u) sample depth %zd", x, y, mSamples);
+ mX[mPos] = x;
+ mY[mPos] = y;
+ return;
+ }
+ }
+ }
+ if (++mPos >= mSize) {
+ mPos = 0;
+ }
+ if (mSamples < mSize) {
+ mExtrapolateTail = false;
+ ++mSamples;
+ } else {
+ // we enable extrapolation beyond the oldest sample
+ // if the sample buffers are completely full and we
+ // no longer know the full history.
+ mExtrapolateTail = true;
+ }
+ mX[mPos] = x;
+ mY[mPos] = y;
+ }
+
+ // clear all samples from the circular array
+ void reset() {
+ // no need to reset mPos, we use a circular buffer.
+ // computed values such as mStepValid are set after a subsequent push().
+ mSamples = 0;
+ }
+
+ // returns true if LinearMap contains at least one sample.
+ bool hasData() const {
+ return mSamples != 0;
+ }
+
+ // find the corresponding X point from a Y point.
+ // See findU for details.
+ __attribute__((no_sanitize("integer")))
+ T findX(T y, FindMethod *method = NULL, double extrapolation = 0.0, T startValue = 0) const {
+ return findU(y, mX, mY, method, extrapolation, startValue);
+ }
+
+ // find the corresponding Y point from a X point.
+ // See findU for details.
+ __attribute__((no_sanitize("integer")))
+ T findY(T x, FindMethod *method = NULL, double extrapolation = 0.0, T startValue = 0) const {
+ return findU(x, mY, mX, method, extrapolation, startValue);
+ }
+
+protected:
+
+ // returns false if the diff is out of int32_t bounds or negative.
+ __attribute__((no_sanitize("integer")))
+ static inline bool checkedDiff(int32_t *diff, T x2, T x1, const char *coord) {
+ if (sizeof(T) >= 8) {
+ const int64_t diff64 = x2 - x1;
+ *diff = (int32_t)diff64; // intentionally lose precision
+ if (diff64 > INT32_MAX) {
+ ALOGW("LinearMap: %s overflow diff(%lld) from %llu - %llu exceeds INT32_MAX",
+ coord, (long long)diff64,
+ (unsigned long long)x2, (unsigned long long)x1);
+ return false;
+ } else if (diff64 < 0) {
+ ALOGW("LinearMap: %s negative diff(%lld) from %llu - %llu",
+ coord, (long long)diff64,
+ (unsigned long long)x2, (unsigned long long)x1);
+ return false;
+ }
+ return true;
+ }
+ // for 32 bit integers we cannot detect overflow (it
+ // shows up as a negative difference).
+ *diff = x2 - x1;
+ if (*diff < 0) {
+ ALOGW("LinearMap: %s negative diff(%d) from %u - %u",
+ coord, *diff, (unsigned)x2, (unsigned)x1);
+ return false;
+ }
+ return true;
+ }
+
+ // Returns the previous position in the mSamples array
+ // going backwards back steps.
+ //
+ // Parameters:
+ // back: number of backward steps, cannot be less than zero or greater than mSamples.
+ //
+ __attribute__((no_sanitize("integer")))
+ size_t previousPosition(ssize_t back = 1) const {
+ LOG_ALWAYS_FATAL_IF(back < 0 || (size_t)back > mSamples, "Invalid back(%zd)", back);
+ ssize_t position = mPos - back;
+ if (position < 0) position += mSize;
+ return (size_t)position;
+ }
+
+ // A generic implementation of finding the "other coordinate" with coordinates
+ // (u, v) = (x, y) or (u, v) = (y, x).
+ //
+ // Parameters:
+ // uArray: the u axis samples.
+ // vArray: the v axis samples.
+ // method: [out] how the returned value was computed.
+ // extrapolation: the slope used when extrapolating from the
+ // first sample value or the last sample value in the history.
+ // If mExtrapolateTail is set, the slope of the last line segment
+ // is used if the extrapolation parameter is zero to continue the tail of history.
+ // At this time, we do not use a different value for forward extrapolation from the
+ // head of history from backward extrapolation from the tail of history.
+ // TODO: back extrapolation value could be stored along with mX, mY in history.
+ // startValue: used only when there are no samples in history. One can detect
+ // whether there are samples in history by the method hasData().
+ //
+ __attribute__((no_sanitize("integer")))
+ T findU(T v, T *uArray, T *vArray, FindMethod *method,
+ double extrapolation, T startValue) const {
+ if (mSamples == 0) {
+ if (method != NULL) {
+ *method = FIND_METHOD_START_VALUE;
+ }
+ return startValue; // nothing yet
+ }
+ ssize_t previous = 0;
+ int32_t diff = 0;
+ for (ssize_t i = 0; i < (ssize_t)mSamples; ++i) {
+ size_t current = previousPosition(i);
+
+ // Assumption: even though the type "T" may have precision greater
+ // than 32 bits, the difference between adjacent points is limited to 32 bits.
+ diff = v - vArray[current];
+ if (diff >= 0 ||
+ (i == (ssize_t)mSamples - 1 && mExtrapolateTail && extrapolation == 0.0)) {
+ // ALOGD("depth = %zd out of %zd", i, limit);
+ if (i == 0) {
+ if (method != NULL) {
+ *method = FIND_METHOD_FORWARD_EXTRAPOLATION;
+ }
+ return uArray[current] + diff * extrapolation;
+ }
+ // interpolate / extrapolate: For this computation, we
+ // must use differentials here otherwise we have inconsistent
+ // values on modulo wrap. previous is always valid here since
+ // i > 0. we also perform rounding with the assumption
+ // that uStep, vStep, and diff are non-negative.
+ int32_t uStep = uArray[previous] - uArray[current]; // non-negative
+ int32_t vStep = vArray[previous] - vArray[current]; // positive
+ T u = uStep <= 0 || vStep <= 0 ? // we do not permit negative ustep or vstep
+ uArray[current]
+ : ((int64_t)diff * uStep + (vStep >> 1)) / vStep + uArray[current];
+ // ALOGD("u:%u diff:%d uStep:%d vStep:%d u_current:%d",
+ // u, diff, uStep, vStep, uArray[current]);
+ if (method != NULL) {
+ *method = (diff >= 0) ?
+ FIND_METHOD_INTERPOLATION : FIND_METHOD_BACKWARD_EXTRAPOLATION;
+ }
+ return u;
+ }
+ previous = current;
+ }
+ // previous is always valid here.
+ if (method != NULL) {
+ *method = FIND_METHOD_BACKWARD_EXTRAPOLATION;
+ }
+ return uArray[previous] + diff * extrapolation;
+ }
+
+private:
+ const size_t mSize; // Size of mX and mY arrays (history).
+ size_t mPos; // Index in mX and mY of last pushed data;
+ // (incremented after push) [0, mSize - 1].
+ size_t mSamples; // Number of valid samples in the array [0, mSize].
+ bool mStepValid; // Last sample step was valid (non-negative)
+ bool mExtrapolateTail; // extrapolate tail using oldest line segment
+ T * const mX; // History of X values as a circular array.
+ T * const mY; // History of Y values as a circular array.
+};
+
+} // namespace android
+
+#endif // ANDROID_LINEAR_MAP_H
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index f6078a2..a6cb9c0 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -152,7 +152,8 @@
return BAD_VALUE;
}
if (patch->num_sources == 0 || patch->num_sources > AUDIO_PATCH_PORTS_MAX ||
- patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
+ (patch->num_sinks == 0 && patch->num_sources != 2) ||
+ patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
return BAD_VALUE;
}
// limit number of sources to 1 for now or 2 sources for special cross hw module case.
@@ -203,18 +204,18 @@
}
// manage patches requiring a software bridge
+ // - special patch request with 2 sources (reuse one existing output mix) OR
// - Device to device AND
// - source HW module != destination HW module OR
// - audio HAL version < 3.0
- // - special patch request with 2 sources (reuse one existing output mix)
- if ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
- ((patch->sinks[0].ext.device.hw_module != srcModule) ||
- (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) ||
- (patch->num_sources == 2))) {
+ if ((patch->num_sources == 2) ||
+ ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
+ ((patch->sinks[0].ext.device.hw_module != srcModule) ||
+ (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0)))) {
if (patch->num_sources == 2) {
if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
- patch->sinks[0].ext.device.hw_module !=
- patch->sources[1].ext.mix.hw_module) {
+ (patch->num_sinks != 0 && patch->sinks[0].ext.device.hw_module !=
+ patch->sources[1].ext.mix.hw_module)) {
ALOGW("createAudioPatch() invalid source combination");
status = INVALID_OPERATION;
goto exit;
@@ -379,12 +380,16 @@
}
// create patch from playback thread output to sink device
- patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
- subPatch.sinks[0] = audioPatch->sinks[0];
- status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
- if (status != NO_ERROR) {
+ if (audioPatch->num_sinks != 0) {
+ patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
+ subPatch.sinks[0] = audioPatch->sinks[0];
+ status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
+ if (status != NO_ERROR) {
+ patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ return status;
+ }
+ } else {
patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- return status;
}
// use a pseudo LCM between input and output framecount
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 7bc6f0c..fe3cc53 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -83,13 +83,13 @@
Track& operator = (const Track&);
// AudioBufferProvider interface
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer,
- int64_t pts = kInvalidPTS);
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
// releaseBuffer() not overridden
// ExtendedAudioBufferProvider interface
virtual size_t framesReady() const;
virtual size_t framesReleased() const;
+ virtual void onTimestamp(const AudioTimestamp ×tamp);
bool isPausing() const { return mState == PAUSING; }
bool isPaused() const { return mState == PAUSED; }
@@ -101,6 +101,8 @@
void flushAck();
bool isResumePending();
void resumeAck();
+ void updateTrackFrameInfo(uint32_t trackFramesReleased, uint32_t sinkFramesWritten,
+ AudioTimestamp *timeStamp = NULL);
sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
@@ -138,6 +140,12 @@
size_t mPresentationCompleteFrames; // number of frames written to the
// audio HAL when this track will be fully rendered
// zero means not monitoring
+
+ // access these three variables only when holding thread lock.
+ LinearMap<uint32_t> mFrameMap; // track frame to server frame mapping
+ bool mSinkTimestampValid; // valid cached timestamp
+ AudioTimestamp mSinkTimestamp;
+
private:
// The following fields are only for fast tracks, and should be in a subclass
int mFastIndex; // index within FastMixerState::mFastTracks[];
@@ -158,92 +166,6 @@
}; // end of Track
-class TimedTrack : public Track {
- public:
- static sp<TimedTrack> create(PlaybackThread *thread,
- const sp<Client>& client,
- audio_stream_type_t streamType,
- uint32_t sampleRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- size_t frameCount,
- const sp<IMemory>& sharedBuffer,
- int sessionId,
- int uid);
- virtual ~TimedTrack();
-
- class TimedBuffer {
- public:
- TimedBuffer();
- TimedBuffer(const sp<IMemory>& buffer, int64_t pts);
- const sp<IMemory>& buffer() const { return mBuffer; }
- int64_t pts() const { return mPTS; }
- uint32_t position() const { return mPosition; }
- void setPosition(uint32_t pos) { mPosition = pos; }
- private:
- sp<IMemory> mBuffer;
- int64_t mPTS;
- uint32_t mPosition;
- };
-
- // Mixer facing methods.
- virtual size_t framesReady() const;
-
- // AudioBufferProvider interface
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer,
- int64_t pts);
- virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
-
- // Client/App facing methods.
- status_t allocateTimedBuffer(size_t size,
- sp<IMemory>* buffer);
- status_t queueTimedBuffer(const sp<IMemory>& buffer,
- int64_t pts);
- status_t setMediaTimeTransform(const LinearTransform& xform,
- TimedAudioTrack::TargetTimeline target);
-
- private:
- TimedTrack(PlaybackThread *thread,
- const sp<Client>& client,
- audio_stream_type_t streamType,
- uint32_t sampleRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- size_t frameCount,
- const sp<IMemory>& sharedBuffer,
- int sessionId,
- int uid);
-
- void timedYieldSamples_l(AudioBufferProvider::Buffer* buffer);
- void timedYieldSilence_l(uint32_t numFrames,
- AudioBufferProvider::Buffer* buffer);
- void trimTimedBufferQueue_l();
- void trimTimedBufferQueueHead_l(const char* logTag);
- void updateFramesPendingAfterTrim_l(const TimedBuffer& buf,
- const char* logTag);
-
- uint64_t mLocalTimeFreq;
- LinearTransform mLocalTimeToSampleTransform;
- LinearTransform mMediaTimeToSampleTransform;
- sp<MemoryDealer> mTimedMemoryDealer;
-
- Vector<TimedBuffer> mTimedBufferQueue;
- bool mQueueHeadInFlight;
- bool mTrimQueueHeadOnRelease;
- uint32_t mFramesPendingInQueue;
-
- uint8_t* mTimedSilenceBuffer;
- uint32_t mTimedSilenceBufferSize;
- mutable Mutex mTimedBufferQueueLock;
- bool mTimedAudioOutputOnTime;
- CCHelper mCCHelper;
-
- Mutex mMediaTimeTransformLock;
- LinearTransform mMediaTimeTransform;
- bool mMediaTimeTransformValid;
- TimedAudioTrack::TargetTimeline mMediaTimeTransformTarget;
-};
-
// playback track, used by DuplicatingThread
class OutputTrack : public Track {
@@ -303,8 +225,7 @@
virtual ~PatchTrack();
// AudioBufferProvider interface
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer,
- int64_t pts);
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
// PatchProxyBufferProvider interface
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 25d6d95..6f84af1 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -54,6 +54,10 @@
void handleSyncStartEvent(const sp<SyncEvent>& event);
void clearSyncStartEvent();
+ void updateTrackFrameInfo(int64_t trackFramesReleased,
+ int64_t sourceFramesRead,
+ uint32_t halSampleRate,
+ const ExtendedTimestamp ×tamp);
private:
friend class AudioFlinger; // for mState
@@ -61,8 +65,7 @@
RecordTrack& operator = (const RecordTrack&);
// AudioBufferProvider interface
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer,
- int64_t pts = kInvalidPTS);
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
// releaseBuffer() not overridden
bool mOverflow; // overflow on most recent attempt to fill client buffer
@@ -99,8 +102,7 @@
virtual ~PatchRecord();
// AudioBufferProvider interface
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer,
- int64_t pts);
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
// PatchProxyBufferProvider interface
diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp
index 2e68dad..afc2440 100644
--- a/services/audioflinger/ServiceUtilities.cpp
+++ b/services/audioflinger/ServiceUtilities.cpp
@@ -32,29 +32,37 @@
// Not valid until initialized by AudioFlinger constructor. It would have to be
// re-initialized if the process containing AudioFlinger service forks (which it doesn't).
+// This is often used to validate binder interface calls within audioserver
+// (e.g. AudioPolicyManager to AudioFlinger).
pid_t getpid_cached;
-bool recordingAllowed(const String16& opPackageName) {
- // Note: We are getting the UID from the calling IPC thread state because all
- // clients that perform recording create AudioRecord in their own processes
- // and the system does not create AudioRecord objects on behalf of apps. This
- // differs from playback where in some situations the system recreates AudioTrack
- // instances associated with a client's MediaPlayer on behalf of this client.
- // In the latter case we have to store the client UID and pass in along for
- // security checks.
+// A trusted calling UID may specify the client UID as part of a binder interface call.
+// otherwise the calling UID must be equal to the client UID.
+bool isTrustedCallingUid(uid_t uid) {
+ switch (uid) {
+ case AID_MEDIA:
+ case AID_AUDIOSERVER:
+ return true;
+ default:
+ return false;
+ }
+}
+bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid) {
+ // we're always OK.
if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
+
static const String16 sRecordAudio("android.permission.RECORD_AUDIO");
+ // We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
+ // may open a record track on behalf of a client. Note that pid may be a tid.
// IMPORTANT: Don't use PermissionCache - a runtime permission and may change.
- const bool ok = checkCallingPermission(sRecordAudio);
+ const bool ok = checkPermission(sRecordAudio, pid, uid);
if (!ok) {
ALOGE("Request requires android.permission.RECORD_AUDIO");
return false;
}
- const uid_t uid = IPCThreadState::self()->getCallingUid();
-
// To permit command-line native tests
if (uid == AID_ROOT) return true;
diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h
index fba6dce..1e79553 100644
--- a/services/audioflinger/ServiceUtilities.h
+++ b/services/audioflinger/ServiceUtilities.h
@@ -19,8 +19,8 @@
namespace android {
extern pid_t getpid_cached;
-
-bool recordingAllowed(const String16& opPackageName);
+bool isTrustedCallingUid(uid_t uid);
+bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
bool captureAudioOutputAllowed();
bool captureHotwordAllowed();
bool settingsAllowed();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 7d2d550..4807400 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -36,6 +36,7 @@
#include <hardware/audio.h>
#include <audio_effects/effect_ns.h>
#include <audio_effects/effect_aec.h>
+#include <audio_utils/conversion.h>
#include <audio_utils/primitives.h>
#include <audio_utils/format.h>
#include <audio_utils/minifloat.h>
@@ -48,12 +49,10 @@
#include <media/nbaio/Pipe.h>
#include <media/nbaio/PipeReader.h>
#include <media/nbaio/SourceAudioBufferProvider.h>
+#include <mediautils/BatteryNotifier.h>
#include <powermanager/PowerManager.h>
-#include <common_time/cc_helper.h>
-#include <common_time/local_clock.h>
-
#include "AudioFlinger.h"
#include "AudioMixer.h"
#include "BufferProviders.h"
@@ -221,6 +220,94 @@
}
#endif
+// Track the CLOCK_BOOTTIME versus CLOCK_MONOTONIC timebase offset
+struct {
+ // call when you acquire a partial wakelock
+ void acquire(const sp<IBinder> &wakeLockToken) {
+ pthread_mutex_lock(&mLock);
+ if (wakeLockToken.get() == nullptr) {
+ adjustTimebaseOffset(&mBoottimeOffset, ExtendedTimestamp::TIMEBASE_BOOTTIME);
+ } else {
+ if (mCount == 0) {
+ adjustTimebaseOffset(&mBoottimeOffset, ExtendedTimestamp::TIMEBASE_BOOTTIME);
+ }
+ ++mCount;
+ }
+ pthread_mutex_unlock(&mLock);
+ }
+
+ // call when you release a partial wakelock.
+ void release(const sp<IBinder> &wakeLockToken) {
+ if (wakeLockToken.get() == nullptr) {
+ return;
+ }
+ pthread_mutex_lock(&mLock);
+ if (--mCount < 0) {
+ ALOGE("negative wakelock count");
+ mCount = 0;
+ }
+ pthread_mutex_unlock(&mLock);
+ }
+
+ // retrieves the boottime timebase offset from monotonic.
+ int64_t getBoottimeOffset() {
+ pthread_mutex_lock(&mLock);
+ int64_t boottimeOffset = mBoottimeOffset;
+ pthread_mutex_unlock(&mLock);
+ return boottimeOffset;
+ }
+
+ // Adjusts the timebase offset between TIMEBASE_MONOTONIC
+ // and the selected timebase.
+ // Currently only TIMEBASE_BOOTTIME is allowed.
+ //
+ // This only needs to be called upon acquiring the first partial wakelock
+ // after all other partial wakelocks are released.
+ //
+ // We do an empirical measurement of the offset rather than parsing
+ // /proc/timer_list since the latter is not a formal kernel ABI.
+ static void adjustTimebaseOffset(int64_t *offset, ExtendedTimestamp::Timebase timebase) {
+ int clockbase;
+ switch (timebase) {
+ case ExtendedTimestamp::TIMEBASE_BOOTTIME:
+ clockbase = SYSTEM_TIME_BOOTTIME;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("invalid timebase %d", timebase);
+ break;
+ }
+ // try three times to get the clock offset, choose the one
+ // with the minimum gap in measurements.
+ const int tries = 3;
+ nsecs_t bestGap, measured;
+ for (int i = 0; i < tries; ++i) {
+ const nsecs_t tmono = systemTime(SYSTEM_TIME_MONOTONIC);
+ const nsecs_t tbase = systemTime(clockbase);
+ const nsecs_t tmono2 = systemTime(SYSTEM_TIME_MONOTONIC);
+ const nsecs_t gap = tmono2 - tmono;
+ if (i == 0 || gap < bestGap) {
+ bestGap = gap;
+ measured = tbase - ((tmono + tmono2) >> 1);
+ }
+ }
+
+ // to avoid micro-adjusting, we don't change the timebase
+ // unless it is significantly different.
+ //
+ // Assumption: It probably takes more than toleranceNs to
+ // suspend and resume the device.
+ static int64_t toleranceNs = 10000; // 10 us
+ if (llabs(*offset - measured) > toleranceNs) {
+ ALOGV("Adjusting timebase offset old: %lld new: %lld",
+ (long long)*offset, (long long)measured);
+ *offset = measured;
+ }
+ }
+
+ pthread_mutex_t mLock;
+ int32_t mCount;
+ int64_t mBoottimeOffset;
+} gBoottime = { PTHREAD_MUTEX_INITIALIZER, 0, 0 }; // static, so use POD initialization
// ----------------------------------------------------------------------------
// CPU Stats
@@ -357,54 +444,54 @@
audio_devices_t mDevices;
const char * mString;
} mappingsOut[] = {
- AUDIO_DEVICE_OUT_EARPIECE, "EARPIECE",
- AUDIO_DEVICE_OUT_SPEAKER, "SPEAKER",
- AUDIO_DEVICE_OUT_WIRED_HEADSET, "WIRED_HEADSET",
- AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "WIRED_HEADPHONE",
- AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "BLUETOOTH_SCO",
- AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, "BLUETOOTH_SCO_HEADSET",
- AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, "BLUETOOTH_SCO_CARKIT",
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "BLUETOOTH_A2DP",
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, "BLUETOOTH_A2DP_HEADPHONES",
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, "BLUETOOTH_A2DP_SPEAKER",
- AUDIO_DEVICE_OUT_AUX_DIGITAL, "AUX_DIGITAL",
- AUDIO_DEVICE_OUT_HDMI, "HDMI",
- AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET, "ANLG_DOCK_HEADSET",
- AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, "DGTL_DOCK_HEADSET",
- AUDIO_DEVICE_OUT_USB_ACCESSORY, "USB_ACCESSORY",
- AUDIO_DEVICE_OUT_USB_DEVICE, "USB_DEVICE",
- AUDIO_DEVICE_OUT_TELEPHONY_TX, "TELEPHONY_TX",
- AUDIO_DEVICE_OUT_LINE, "LINE",
- AUDIO_DEVICE_OUT_HDMI_ARC, "HDMI_ARC",
- AUDIO_DEVICE_OUT_SPDIF, "SPDIF",
- AUDIO_DEVICE_OUT_FM, "FM",
- AUDIO_DEVICE_OUT_AUX_LINE, "AUX_LINE",
- AUDIO_DEVICE_OUT_SPEAKER_SAFE, "SPEAKER_SAFE",
- AUDIO_DEVICE_OUT_IP, "IP",
- AUDIO_DEVICE_NONE, "NONE", // must be last
+ {AUDIO_DEVICE_OUT_EARPIECE, "EARPIECE"},
+ {AUDIO_DEVICE_OUT_SPEAKER, "SPEAKER"},
+ {AUDIO_DEVICE_OUT_WIRED_HEADSET, "WIRED_HEADSET"},
+ {AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "WIRED_HEADPHONE"},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "BLUETOOTH_SCO"},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, "BLUETOOTH_SCO_HEADSET"},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, "BLUETOOTH_SCO_CARKIT"},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "BLUETOOTH_A2DP"},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"BLUETOOTH_A2DP_HEADPHONES"},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, "BLUETOOTH_A2DP_SPEAKER"},
+ {AUDIO_DEVICE_OUT_AUX_DIGITAL, "AUX_DIGITAL"},
+ {AUDIO_DEVICE_OUT_HDMI, "HDMI"},
+ {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET,"ANLG_DOCK_HEADSET"},
+ {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET,"DGTL_DOCK_HEADSET"},
+ {AUDIO_DEVICE_OUT_USB_ACCESSORY, "USB_ACCESSORY"},
+ {AUDIO_DEVICE_OUT_USB_DEVICE, "USB_DEVICE"},
+ {AUDIO_DEVICE_OUT_TELEPHONY_TX, "TELEPHONY_TX"},
+ {AUDIO_DEVICE_OUT_LINE, "LINE"},
+ {AUDIO_DEVICE_OUT_HDMI_ARC, "HDMI_ARC"},
+ {AUDIO_DEVICE_OUT_SPDIF, "SPDIF"},
+ {AUDIO_DEVICE_OUT_FM, "FM"},
+ {AUDIO_DEVICE_OUT_AUX_LINE, "AUX_LINE"},
+ {AUDIO_DEVICE_OUT_SPEAKER_SAFE, "SPEAKER_SAFE"},
+ {AUDIO_DEVICE_OUT_IP, "IP"},
+ {AUDIO_DEVICE_NONE, "NONE"}, // must be last
}, mappingsIn[] = {
- AUDIO_DEVICE_IN_COMMUNICATION, "COMMUNICATION",
- AUDIO_DEVICE_IN_AMBIENT, "AMBIENT",
- AUDIO_DEVICE_IN_BUILTIN_MIC, "BUILTIN_MIC",
- AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "BLUETOOTH_SCO_HEADSET",
- AUDIO_DEVICE_IN_WIRED_HEADSET, "WIRED_HEADSET",
- AUDIO_DEVICE_IN_AUX_DIGITAL, "AUX_DIGITAL",
- AUDIO_DEVICE_IN_VOICE_CALL, "VOICE_CALL",
- AUDIO_DEVICE_IN_TELEPHONY_RX, "TELEPHONY_RX",
- AUDIO_DEVICE_IN_BACK_MIC, "BACK_MIC",
- AUDIO_DEVICE_IN_REMOTE_SUBMIX, "REMOTE_SUBMIX",
- AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, "ANLG_DOCK_HEADSET",
- AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET, "DGTL_DOCK_HEADSET",
- AUDIO_DEVICE_IN_USB_ACCESSORY, "USB_ACCESSORY",
- AUDIO_DEVICE_IN_USB_DEVICE, "USB_DEVICE",
- AUDIO_DEVICE_IN_FM_TUNER, "FM_TUNER",
- AUDIO_DEVICE_IN_TV_TUNER, "TV_TUNER",
- AUDIO_DEVICE_IN_LINE, "LINE",
- AUDIO_DEVICE_IN_SPDIF, "SPDIF",
- AUDIO_DEVICE_IN_BLUETOOTH_A2DP, "BLUETOOTH_A2DP",
- AUDIO_DEVICE_IN_LOOPBACK, "LOOPBACK",
- AUDIO_DEVICE_IN_IP, "IP",
- AUDIO_DEVICE_NONE, "NONE", // must be last
+ {AUDIO_DEVICE_IN_COMMUNICATION, "COMMUNICATION"},
+ {AUDIO_DEVICE_IN_AMBIENT, "AMBIENT"},
+ {AUDIO_DEVICE_IN_BUILTIN_MIC, "BUILTIN_MIC"},
+ {AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "BLUETOOTH_SCO_HEADSET"},
+ {AUDIO_DEVICE_IN_WIRED_HEADSET, "WIRED_HEADSET"},
+ {AUDIO_DEVICE_IN_AUX_DIGITAL, "AUX_DIGITAL"},
+ {AUDIO_DEVICE_IN_VOICE_CALL, "VOICE_CALL"},
+ {AUDIO_DEVICE_IN_TELEPHONY_RX, "TELEPHONY_RX"},
+ {AUDIO_DEVICE_IN_BACK_MIC, "BACK_MIC"},
+ {AUDIO_DEVICE_IN_REMOTE_SUBMIX, "REMOTE_SUBMIX"},
+ {AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, "ANLG_DOCK_HEADSET"},
+ {AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET, "DGTL_DOCK_HEADSET"},
+ {AUDIO_DEVICE_IN_USB_ACCESSORY, "USB_ACCESSORY"},
+ {AUDIO_DEVICE_IN_USB_DEVICE, "USB_DEVICE"},
+ {AUDIO_DEVICE_IN_FM_TUNER, "FM_TUNER"},
+ {AUDIO_DEVICE_IN_TV_TUNER, "TV_TUNER"},
+ {AUDIO_DEVICE_IN_LINE, "LINE"},
+ {AUDIO_DEVICE_IN_SPDIF, "SPDIF"},
+ {AUDIO_DEVICE_IN_BLUETOOTH_A2DP, "BLUETOOTH_A2DP"},
+ {AUDIO_DEVICE_IN_LOOPBACK, "LOOPBACK"},
+ {AUDIO_DEVICE_IN_IP, "IP"},
+ {AUDIO_DEVICE_NONE, "NONE"}, // must be last
};
String8 result;
audio_devices_t allDevices = AUDIO_DEVICE_NONE;
@@ -442,9 +529,11 @@
audio_input_flags_t mFlag;
const char * mString;
} mappings[] = {
- AUDIO_INPUT_FLAG_FAST, "FAST",
- AUDIO_INPUT_FLAG_HW_HOTWORD, "HW_HOTWORD",
- AUDIO_INPUT_FLAG_NONE, "NONE", // must be last
+ {AUDIO_INPUT_FLAG_FAST, "FAST"},
+ {AUDIO_INPUT_FLAG_HW_HOTWORD, "HW_HOTWORD"},
+ {AUDIO_INPUT_FLAG_RAW, "RAW"},
+ {AUDIO_INPUT_FLAG_SYNC, "SYNC"},
+ {AUDIO_INPUT_FLAG_NONE, "NONE"}, // must be last
};
String8 result;
audio_input_flags_t allFlags = AUDIO_INPUT_FLAG_NONE;
@@ -476,14 +565,17 @@
audio_output_flags_t mFlag;
const char * mString;
} mappings[] = {
- AUDIO_OUTPUT_FLAG_DIRECT, "DIRECT",
- AUDIO_OUTPUT_FLAG_PRIMARY, "PRIMARY",
- AUDIO_OUTPUT_FLAG_FAST, "FAST",
- AUDIO_OUTPUT_FLAG_DEEP_BUFFER, "DEEP_BUFFER",
- AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD, "COMPRESS_OFFLOAD",
- AUDIO_OUTPUT_FLAG_NON_BLOCKING, "NON_BLOCKING",
- AUDIO_OUTPUT_FLAG_HW_AV_SYNC, "HW_AV_SYNC",
- AUDIO_OUTPUT_FLAG_NONE, "NONE", // must be last
+ {AUDIO_OUTPUT_FLAG_DIRECT, "DIRECT"},
+ {AUDIO_OUTPUT_FLAG_PRIMARY, "PRIMARY"},
+ {AUDIO_OUTPUT_FLAG_FAST, "FAST"},
+ {AUDIO_OUTPUT_FLAG_DEEP_BUFFER, "DEEP_BUFFER"},
+ {AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD,"COMPRESS_OFFLOAD"},
+ {AUDIO_OUTPUT_FLAG_NON_BLOCKING, "NON_BLOCKING"},
+ {AUDIO_OUTPUT_FLAG_HW_AV_SYNC, "HW_AV_SYNC"},
+ {AUDIO_OUTPUT_FLAG_RAW, "RAW"},
+ {AUDIO_OUTPUT_FLAG_SYNC, "SYNC"},
+ {AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO, "IEC958_NONAUDIO"},
+ {AUDIO_OUTPUT_FLAG_NONE, "NONE"}, // must be last
};
String8 result;
audio_output_flags_t allFlags = AUDIO_OUTPUT_FLAG_NONE;
@@ -521,6 +613,7 @@
case AUDIO_SOURCE_VOICE_RECOGNITION: return "voice recognition";
case AUDIO_SOURCE_VOICE_COMMUNICATION: return "voice communication";
case AUDIO_SOURCE_REMOTE_SUBMIX: return "remote submix";
+ case AUDIO_SOURCE_UNPROCESSED: return "unprocessed";
case AUDIO_SOURCE_FM_TUNER: return "FM tuner";
case AUDIO_SOURCE_HOTWORD: return "hotword";
default: return "unknown";
@@ -541,7 +634,8 @@
mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
// mName will be set by concrete (non-virtual) subclass
mDeathRecipient(new PMDeathRecipient(this)),
- mSystemReady(systemReady)
+ mSystemReady(systemReady),
+ mNotifiedBatteryStart(false)
{
memset(&mPatch, 0, sizeof(struct audio_patch));
}
@@ -662,7 +756,19 @@
// sendSetParameterConfigEvent_l() must be called with ThreadBase::mLock held
status_t AudioFlinger::ThreadBase::sendSetParameterConfigEvent_l(const String8& keyValuePair)
{
- sp<ConfigEvent> configEvent = (ConfigEvent *)new SetParameterConfigEvent(keyValuePair);
+ sp<ConfigEvent> configEvent;
+ AudioParameter param(keyValuePair);
+ int value;
+ if (param.getInt(String8(AUDIO_PARAMETER_MONO_OUTPUT), value) == NO_ERROR) {
+ setMasterMono_l(value != 0);
+ if (param.size() == 1) {
+ return NO_ERROR; // should be a solo parameter - we don't pass down
+ }
+ param.remove(String8(AUDIO_PARAMETER_MONO_OUTPUT));
+ configEvent = new SetParameterConfigEvent(param.toString());
+ } else {
+ configEvent = new SetParameterConfigEvent(keyValuePair);
+ }
return sendConfigEvent_l(configEvent);
}
@@ -832,8 +938,8 @@
dprintf(fd, " Channel count: %u\n", mChannelCount);
dprintf(fd, " Channel mask: 0x%08x (%s)\n", mChannelMask,
channelMaskToString(mChannelMask, mType != RECORD).string());
- dprintf(fd, " Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
- dprintf(fd, " Frame size: %zu bytes\n", mFrameSize);
+ dprintf(fd, " Processing format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
+ dprintf(fd, " Processing frame size: %zu bytes\n", mFrameSize);
dprintf(fd, " Pending config events:");
size_t numConfig = mConfigEvents.size();
if (numConfig) {
@@ -907,14 +1013,14 @@
status = mPowerManager->acquireWakeLockWithUid(POWERMANAGER_PARTIAL_WAKE_LOCK,
binder,
getWakeLockTag(),
- String16("media"),
+ String16("audioserver"),
uid,
true /* FIXME force oneway contrary to .aidl */);
} else {
status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
binder,
getWakeLockTag(),
- String16("media"),
+ String16("audioserver"),
true /* FIXME force oneway contrary to .aidl */);
}
if (status == NO_ERROR) {
@@ -922,6 +1028,12 @@
}
ALOGV("acquireWakeLock_l() %s status %d", mThreadName, status);
}
+
+ if (!mNotifiedBatteryStart) {
+ BatteryNotifier::getInstance().noteStartAudio();
+ mNotifiedBatteryStart = true;
+ }
+ gBoottime.acquire(mWakeLockToken);
}
void AudioFlinger::ThreadBase::releaseWakeLock()
@@ -932,6 +1044,7 @@
void AudioFlinger::ThreadBase::releaseWakeLock_l()
{
+ gBoottime.release(mWakeLockToken);
if (mWakeLockToken != 0) {
ALOGV("releaseWakeLock_l() %s", mThreadName);
if (mPowerManager != 0) {
@@ -940,6 +1053,11 @@
}
mWakeLockToken.clear();
}
+
+ if (mNotifiedBatteryStart) {
+ BatteryNotifier::getInstance().noteStopAudio();
+ mNotifiedBatteryStart = false;
+ }
}
void AudioFlinger::ThreadBase::updateWakeLockUids(const SortedVector<int> &uids) {
@@ -963,8 +1081,12 @@
void AudioFlinger::ThreadBase::updateWakeLockUids_l(const SortedVector<int> &uids) {
getPowerManager_l();
- if (mWakeLockToken == NULL) {
- ALOGE("no wake lock to update!");
+ if (mWakeLockToken == NULL) { // token may be NULL if AudioFlinger::systemReady() not called.
+ if (mSystemReady) {
+ ALOGE("no wake lock to update, but system ready!");
+ } else {
+ ALOGW("no wake lock to update, system not ready yet");
+ }
return;
}
if (mPowerManager != 0) {
@@ -1457,9 +1579,7 @@
mScreenState(AudioFlinger::mScreenState),
// index 0 is reserved for normal mixer's submix
mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1),
- mHwSupportsPause(false), mHwPaused(false), mFlushPending(false),
- // mLatchD, mLatchQ,
- mLatchDValid(false), mLatchQValid(false)
+ mHwSupportsPause(false), mHwPaused(false), mFlushPending(false)
{
snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id);
mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
@@ -1631,13 +1751,9 @@
sp<Track> track;
status_t lStatus;
- bool isTimed = (*flags & IAudioFlinger::TRACK_TIMED) != 0;
-
// client expresses a preference for FAST, but we get the final say
if (*flags & IAudioFlinger::TRACK_FAST) {
if (
- // not timed
- (!isTimed) &&
// either of these use cases:
(
// use case 1: shared buffer with any frame count
@@ -1681,11 +1797,11 @@
ALOGV("AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%d mFrameCount=%d",
frameCount, mFrameCount);
} else {
- ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: isTimed=%d sharedBuffer=%p frameCount=%d "
+ ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: sharedBuffer=%p frameCount=%d "
"mFrameCount=%d format=%#x mFormat=%#x isLinear=%d channelMask=%#x "
"sampleRate=%u mSampleRate=%u "
"hasFastMixer=%d tid=%d fastTrackAvailMask=%#x",
- isTimed, sharedBuffer.get(), frameCount, mFrameCount, format, mFormat,
+ sharedBuffer.get(), frameCount, mFrameCount, format, mFormat,
audio_is_linear_pcm(format),
channelMask, sampleRate, mSampleRate, hasFastMixer(), tid, mFastTrackAvailMask);
*flags &= ~IAudioFlinger::TRACK_FAST;
@@ -1697,7 +1813,7 @@
// This is probably too conservative, but legacy application code may depend on it.
// If you change this calculation, also review the start threshold which is related.
if (!(*flags & IAudioFlinger::TRACK_FAST)
- && audio_is_linear_pcm(format) && sharedBuffer == 0) {
+ && audio_has_proportional_frames(format) && sharedBuffer == 0) {
// this must match AudioTrack.cpp calculateMinFrameCount().
// TODO: Move to a common library
uint32_t latencyMs = mOutput->stream->get_latency(mOutput->stream);
@@ -1720,7 +1836,7 @@
switch (mType) {
case DIRECT:
- if (audio_is_linear_pcm(format)) {
+ if (audio_is_linear_pcm(format)) { // TODO maybe use audio_has_proportional_frames()?
if (sampleRate != mSampleRate || format != mFormat || channelMask != mChannelMask) {
ALOGE("createTrack_l() Bad parameter: sampleRate %u format %#x, channelMask 0x%08x "
"for output %p with format %#x",
@@ -1784,17 +1900,10 @@
}
}
- if (!isTimed) {
- track = new Track(this, client, streamType, sampleRate, format,
- channelMask, frameCount, NULL, sharedBuffer,
- sessionId, uid, *flags, TrackBase::TYPE_DEFAULT);
- } else {
- track = TimedTrack::create(this, client, streamType, sampleRate, format,
- channelMask, frameCount, sharedBuffer, sessionId, uid);
- }
+ track = new Track(this, client, streamType, sampleRate, format,
+ channelMask, frameCount, NULL, sharedBuffer,
+ sessionId, uid, *flags, TrackBase::TYPE_DEFAULT);
- // new Track always returns non-NULL,
- // but TimedTrack::create() is a factory that could fail by returning NULL
lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY;
if (lStatus != NO_ERROR) {
ALOGE("createTrack_l() initCheck failed %d; no control block?", lStatus);
@@ -2443,16 +2552,6 @@
} else {
bytesWritten = framesWritten;
}
- mLatchDValid = false;
- status_t status = mNormalSink->getTimestamp(mLatchD.mTimestamp);
- if (status == NO_ERROR) {
- size_t totalFramesWritten = mNormalSink->framesWritten();
- if (totalFramesWritten >= mLatchD.mTimestamp.mPosition) {
- mLatchD.mUnpresentedFrames = totalFramesWritten - mLatchD.mTimestamp.mPosition;
- // mLatchD.mFramesReleased is set immediately before D is clocked into Q
- mLatchDValid = true;
- }
- }
// otherwise use the HAL / AudioStreamOut directly
} else {
// Direct output and offload threads
@@ -2554,7 +2653,7 @@
size_t size = mTracks.size();
for (size_t i = 0; i < size; i++) {
sp<Track> t = mTracks[i];
- if (t->streamType() == streamType) {
+ if (t->streamType() == streamType && t->isExternalTrack()) {
t->invalidate();
}
}
@@ -2758,21 +2857,47 @@
}
// Gather the framesReleased counters for all active tracks,
- // and latch them atomically with the timestamp.
- // FIXME We're using raw pointers as indices. A unique track ID would be a better index.
- mLatchD.mFramesReleased.clear();
- size_t size = mActiveTracks.size();
- for (size_t i = 0; i < size; i++) {
- sp<Track> t = mActiveTracks[i].promote();
- if (t != 0) {
- mLatchD.mFramesReleased.add(t.get(),
- t->mAudioTrackServerProxy->framesReleased());
+ // and associate with the sink frames written out. We need
+ // this to convert the sink timestamp to the track timestamp.
+ if (mNormalSink != 0) {
+ bool updateTracks = true;
+ bool cacheTimestamp = false;
+ AudioTimestamp timeStamp;
+ // FIXME: Use a 64 bit mNormalSink->framesWritten() counter.
+ // At this time, we must always use cached timestamps even when
+ // going through mPipeSink (which is non-blocking). The reason is that
+ // the track may be removed from the active list for many hours and
+ // the mNormalSink->framesWritten() will wrap making the linear
+ // mapping fail.
+ //
+ // (Also mAudioTrackServerProxy->framesReleased() needs to be
+ // updated to 64 bits for 64 bit frame position.)
+ //
+ if (true /* see comment above, should be: mNormalSink == mOutputSink */) {
+ // If we use a hardware device, we must cache the sink timestamp now.
+ // hardware devices can block timestamp access during data writes.
+ if (mNormalSink->getTimestamp(timeStamp) == NO_ERROR) {
+ cacheTimestamp = true;
+ } else {
+ updateTracks = false;
+ }
}
- }
- if (mLatchDValid) {
- mLatchQ = mLatchD;
- mLatchDValid = false;
- mLatchQValid = true;
+ if (updateTracks) {
+ // sinkFramesWritten for non-offloaded tracks are contiguous
+ // even after standby() is called. This is useful for the track frame
+ // to sink frame mapping.
+ const uint32_t sinkFramesWritten = mNormalSink->framesWritten();
+ const size_t size = mActiveTracks.size();
+ for (size_t i = 0; i < size; ++i) {
+ sp<Track> t = mActiveTracks[i].promote();
+ if (t != 0 && !t->isFastTrack()) {
+ t->updateTrackFrameInfo(
+ t->mAudioTrackServerProxy->framesReleased(),
+ sinkFramesWritten,
+ cacheTimestamp ? &timeStamp : NULL);
+ }
+ }
+ }
}
saveOutputTracks();
@@ -2893,6 +3018,13 @@
void *buffer = mEffectBufferValid ? mEffectBuffer : mSinkBuffer;
audio_format_t format = mEffectBufferValid ? mEffectBufferFormat : mFormat;
+ // mono blend occurs for mixer threads only (not direct or offloaded)
+ // and is handled here if we're going directly to the sink.
+ if (requireMonoBlend() && !mEffectBufferValid) {
+ mono_blend(mMixerBuffer, mMixerBufferFormat, mChannelCount, mNormalFrameCount,
+ true /*limit*/);
+ }
+
memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
mNormalFrameCount * mChannelCount);
}
@@ -2928,6 +3060,12 @@
// TODO use mSleepTimeUs == 0 as an additional condition.
if (mEffectBufferValid) {
//ALOGV("writing effect buffer to sink buffer format %#x", mFormat);
+
+ if (requireMonoBlend()) {
+ mono_blend(mEffectBuffer, mEffectBufferFormat, mChannelCount, mNormalFrameCount,
+ true /*limit*/);
+ }
+
memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
mNormalFrameCount * mChannelCount);
}
@@ -3270,7 +3408,8 @@
: PlaybackThread(audioFlinger, output, id, device, type, systemReady),
// mAudioMixer below
// mFastMixer below
- mFastMixerFutex(0)
+ mFastMixerFutex(0),
+ mMasterMono(false)
// mOutputSink below
// mPipeSink below
// mNormalSink below
@@ -3592,22 +3731,8 @@
void AudioFlinger::MixerThread::threadLoop_mix()
{
- // obtain the presentation timestamp of the next output buffer
- int64_t pts;
- status_t status = INVALID_OPERATION;
-
- if (mNormalSink != 0) {
- status = mNormalSink->getNextWriteTimestamp(&pts);
- } else {
- status = mOutputSink->getNextWriteTimestamp(&pts);
- }
-
- if (status != NO_ERROR) {
- pts = AudioBufferProvider::kInvalidPTS;
- }
-
// mix buffers...
- mAudioMixer->process(pts);
+ mAudioMixer->process();
mCurrentWriteLength = mSinkBufferSize;
// increase sleep time progressively when application underrun condition clears.
// Only increase sleep time if the mixer is ready for two consecutive times to avoid
@@ -3740,6 +3865,8 @@
recentUnderruns > 0) {
// FIXME fast mixer will pull & mix partial buffers, but we count as a full underrun
track->mAudioTrackServerProxy->tallyUnderrunFrames(recentUnderruns * mFrameCount);
+ } else {
+ track->mAudioTrackServerProxy->tallyUnderrunFrames(0);
}
// This is similar to the state machine for normal tracks,
@@ -3849,7 +3976,10 @@
// because we're about to decrement the last sp<> on those tracks.
block = FastMixerStateQueue::BLOCK_UNTIL_ACKED;
} else {
- LOG_ALWAYS_FATAL("fast track %d should have been active", j);
+ LOG_ALWAYS_FATAL("fast track %d should have been active; "
+ "mState=%d, mTrackMask=%#x, recentUnderruns=%u, isShared=%d",
+ j, track->mState, state->mTrackMask, recentUnderruns,
+ track->sharedBuffer() != 0);
}
tracksToRemove->add(track);
// Avoids a misleading display in dumpsys
@@ -4106,7 +4236,10 @@
ALOGV("track(%p) underrun, framesReady(%zu) < framesDesired(%zd)",
track, framesReady, desiredFrames);
track->mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
+ } else {
+ track->mAudioTrackServerProxy->tallyUnderrunFrames(0);
}
+
// clear effect chain input buffer if an active track underruns to avoid sending
// previous audio buffer again to effects
chain = getEffectChain_l(track->sessionId());
@@ -4394,10 +4527,15 @@
PlaybackThread::dumpInternals(fd, args);
dprintf(fd, " Thread throttle time (msecs): %u\n", mThreadThrottleTimeMs);
dprintf(fd, " AudioMixer tracks: 0x%08x\n", mAudioMixer->trackNames());
+ dprintf(fd, " Master mono: %s\n", mMasterMono ? "on" : "off");
// Make a non-atomic copy of fast mixer dump state so it won't change underneath us
- const FastMixerDumpState copy(mFastMixerDumpState);
- copy.dump(fd);
+ // while we are dumping it. It may be inconsistent, but it won't mutate!
+ // This is a large object so we place it on the heap.
+ // FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
+ const FastMixerDumpState *copy = new FastMixerDumpState(mFastMixerDumpState);
+ copy->dump(fd);
+ delete copy;
#ifdef STATE_QUEUE_DUMP
// Similar for state queue
@@ -4591,7 +4729,7 @@
// Do not use a high threshold for compressed audio.
uint32_t minFrames;
if ((track->sharedBuffer() == 0) && !track->isStopping_1() && !track->isPausing()
- && (track->mRetryCount > 1) && audio_is_linear_pcm(mFormat)) {
+ && (track->mRetryCount > 1) && audio_has_proportional_frames(mFormat)) {
minFrames = mNormalFrameCount;
} else {
minFrames = 1;
@@ -4652,7 +4790,7 @@
// We have consumed all the buffers of this track.
// Remove it from the list of active tracks.
size_t audioHALFrames;
- if (audio_is_linear_pcm(mFormat)) {
+ if (audio_has_proportional_frames(mFormat)) {
audioHALFrames = (latency_l() * mSampleRate) / 1000;
} else {
audioHALFrames = 0;
@@ -4760,7 +4898,7 @@
} else {
mSleepTimeUs = mIdleSleepTimeUs;
}
- } else if (mBytesWritten != 0 && audio_is_linear_pcm(mFormat)) {
+ } else if (mBytesWritten != 0 && audio_has_proportional_frames(mFormat)) {
memset(mSinkBuffer, 0, mFrameCount * mFrameSize);
mSleepTimeUs = 0;
}
@@ -4867,7 +5005,7 @@
uint32_t AudioFlinger::DirectOutputThread::activeSleepTimeUs() const
{
uint32_t time;
- if (audio_is_linear_pcm(mFormat)) {
+ if (audio_has_proportional_frames(mFormat)) {
time = PlaybackThread::activeSleepTimeUs();
} else {
time = 10000;
@@ -4878,7 +5016,7 @@
uint32_t AudioFlinger::DirectOutputThread::idleSleepTimeUs() const
{
uint32_t time;
- if (audio_is_linear_pcm(mFormat)) {
+ if (audio_has_proportional_frames(mFormat)) {
time = (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000) / 2;
} else {
time = 10000;
@@ -4889,7 +5027,7 @@
uint32_t AudioFlinger::DirectOutputThread::suspendSleepTimeUs() const
{
uint32_t time;
- if (audio_is_linear_pcm(mFormat)) {
+ if (audio_has_proportional_frames(mFormat)) {
time = (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000);
} else {
time = 10000;
@@ -4906,7 +5044,7 @@
// no delay on outputs with HW A/V sync
if (usesHwAvSync()) {
mStandbyDelayNs = 0;
- } else if ((mType == OFFLOAD) && !audio_is_linear_pcm(mFormat)) {
+ } else if ((mType == OFFLOAD) && !audio_has_proportional_frames(mFormat)) {
mStandbyDelayNs = kOffloadStandbyDelayNs;
} else {
mStandbyDelayNs = microseconds(mActiveSleepTimeUs*2);
@@ -5308,7 +5446,7 @@
{
// mix buffers...
if (outputsReady(outputTracks)) {
- mAudioMixer->process(AudioBufferProvider::kInvalidPTS);
+ mAudioMixer->process();
} else {
if (mMixerBufferValid) {
memset(mMixerBuffer, 0, mMixerBufferSize);
@@ -5651,6 +5789,9 @@
}
}
+ mTimestamp.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_BOOTTIME] =
+ gBoottime.getBoottimeOffset();
+
// used to request a deferred sleep, to be executed later while mutex is unlocked
uint32_t sleepUs = 0;
@@ -5848,7 +5989,7 @@
if (mPipeSource != 0) {
size_t framesToRead = mBufferSize / mFrameSize;
framesRead = mPipeSource->read((uint8_t*)mRsmpInBuffer + rear * mFrameSize,
- framesToRead, AudioBufferProvider::kInvalidPTS);
+ framesToRead);
if (framesRead == 0) {
// since pipe is non-blocking, simulate blocking input
sleepUs = (framesToRead * 1000000LL) / mSampleRate;
@@ -5864,6 +6005,28 @@
}
}
+ // Update server timestamp with server stats
+ // systemTime() is optional if the hardware supports timestamps.
+ mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] += framesRead;
+ mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = systemTime();
+
+ // Update server timestamp with kernel stats
+ if (mInput->stream->get_capture_position != nullptr) {
+ int64_t position, time;
+ int ret = mInput->stream->get_capture_position(mInput->stream, &position, &time);
+ if (ret == NO_ERROR) {
+ mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = position;
+ mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = time;
+ // Note: In general record buffers should tend to be empty in
+ // a properly running pipeline.
+ //
+ // Also, it is not advantageous to call get_presentation_position during the read
+ // as the read obtains a lock, preventing the timestamp call from executing.
+ }
+ }
+ // Use this to track timestamp information
+ // ALOGD("%s", mTimestamp.toString().c_str());
+
if (framesRead < 0 || (framesRead == 0 && mPipeSource == 0)) {
ALOGE("read failed: framesRead=%d", framesRead);
// Force input into standby so that it tries to recover at next read attempt
@@ -5992,6 +6155,11 @@
break;
}
+ // update frame information and push timestamp out
+ activeTrack->updateTrackFrameInfo(
+ activeTrack->mServerProxy->framesReleased(),
+ mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER],
+ mSampleRate, mTimestamp);
}
unlock:
@@ -6373,9 +6541,13 @@
dprintf(fd, " Fast capture thread: %s\n", hasFastCapture() ? "yes" : "no");
dprintf(fd, " Fast track available: %s\n", mFastTrackAvail ? "yes" : "no");
- // Make a non-atomic copy of fast capture dump state so it won't change underneath us
- const FastCaptureDumpState copy(mFastCaptureDumpState);
- copy.dump(fd);
+ // Make a non-atomic copy of fast capture dump state so it won't change underneath us
+ // while we are dumping it. It may be inconsistent, but it won't mutate!
+ // This is a large object so we place it on the heap.
+ // FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
+ const FastCaptureDumpState *copy = new FastCaptureDumpState(mFastCaptureDumpState);
+ copy->dump(fd);
+ delete copy;
}
void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args __unused)
@@ -6466,7 +6638,7 @@
// AudioBufferProvider interface
status_t AudioFlinger::RecordThread::ResamplerBufferProvider::getNextBuffer(
- AudioBufferProvider::Buffer* buffer, int64_t pts __unused)
+ AudioBufferProvider::Buffer* buffer)
{
sp<ThreadBase> threadBase = mRecordTrack->mThread.promote();
if (threadBase == 0) {
@@ -6567,7 +6739,7 @@
AudioBufferProvider::Buffer buffer;
for (size_t i = frames; i > 0; ) {
buffer.frameCount = i;
- status_t status = provider->getNextBuffer(&buffer, 0);
+ status_t status = provider->getNextBuffer(&buffer);
if (status != OK || buffer.frameCount == 0) {
frames -= i; // cannot fill request.
break;
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 46ac300..7c92c1c 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -400,6 +400,8 @@
String16 getWakeLockTag();
virtual void preExit() { }
+ virtual void setMasterMono_l(bool mono __unused) { }
+ virtual bool requireMonoBlend() { return false; }
friend class AudioFlinger; // for mEffectChains
@@ -457,6 +459,7 @@
static const size_t kLogSize = 4 * 1024;
sp<NBLog::Writer> mNBLogWriter;
bool mSystemReady;
+ bool mNotifiedBatteryStart;
};
// --- PlaybackThread ---
@@ -838,19 +841,6 @@
bool mHwSupportsPause;
bool mHwPaused;
bool mFlushPending;
-private:
- // timestamp latch:
- // D input is written by threadLoop_write while mutex is unlocked, and read while locked
- // Q output is written while locked, and read while locked
- struct {
- AudioTimestamp mTimestamp;
- uint32_t mUnpresentedFrames;
- KeyedVector<Track *, uint32_t> mFramesReleased;
- } mLatchD, mLatchQ;
- bool mLatchDValid; // true means mLatchD is valid
- // (except for mFramesReleased which is filled in later),
- // and clock it into latch at next opportunity
- bool mLatchQValid; // true means mLatchQ is valid
};
class MixerThread : public PlaybackThread {
@@ -908,6 +898,7 @@
// mFastMixer->sq() // for mutating and pushing state
int32_t mFastMixerFutex; // for cold idle
+ std::atomic_bool mMasterMono;
public:
virtual bool hasFastMixer() const { return mFastMixer != 0; }
virtual FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const {
@@ -915,6 +906,17 @@
return mFastMixerDumpState.mTracks[fastIndex].mUnderruns;
}
+protected:
+ virtual void setMasterMono_l(bool mono) {
+ mMasterMono.store(mono);
+ if (mFastMixer != nullptr) { /* hasFastMixer() */
+ mFastMixer->setMasterMono(mMasterMono);
+ }
+ }
+ // the FastMixer performs mono blend if it exists.
+ // Blending with limiter is not idempotent,
+ // and blending without limiter is idempotent but inefficient to do twice.
+ virtual bool requireMonoBlend() { return mMasterMono.load() && !hasFastMixer(); }
};
class DirectOutputThread : public PlaybackThread {
@@ -1096,7 +1098,7 @@
virtual void sync(size_t *framesAvailable = NULL, bool *hasOverrun = NULL);
// AudioBufferProvider interface
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts);
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
private:
RecordTrack * const mRecordTrack;
@@ -1309,6 +1311,8 @@
// rolling index that is never cleared
int32_t mRsmpInRear; // last filled frame + 1
+ ExtendedTimestamp mTimestamp;
+
// For dumpsys
const sp<NBAIO_Sink> mTeeSink;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 98bf96e..26067e3 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -50,7 +50,6 @@
enum track_type {
TYPE_DEFAULT,
- TYPE_TIMED,
TYPE_OUTPUT,
TYPE_PATCH,
};
@@ -83,7 +82,6 @@
sp<IMemory> getBuffers() const { return mBufferMemory; }
void* buffer() const { return mBuffer; }
bool isFastTrack() const { return (mFlags & IAudioFlinger::TRACK_FAST) != 0; }
- bool isTimedTrack() const { return (mType == TYPE_TIMED); }
bool isOutputTrack() const { return (mType == TYPE_OUTPUT); }
bool isPatchTrack() const { return (mType == TYPE_PATCH); }
bool isExternalTrack() const { return !isOutputTrack() && !isPatchTrack(); }
@@ -93,7 +91,7 @@
TrackBase& operator = (const TrackBase&);
// AudioBufferProvider interface
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts) = 0;
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
// ExtendedAudioBufferProvider interface is only needed for Track,
@@ -132,7 +130,7 @@
}
bool isOut() const { return mIsOut; }
- // true for Track and TimedTrack, false for RecordTrack,
+ // true for Track, false for RecordTrack,
// this could be a track type if needed later
const wp<ThreadBase> mThread;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 0e24b52..536581c 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -27,9 +27,6 @@
#include <private/media/AudioTrackShared.h>
-#include <common_time/cc_helper.h>
-#include <common_time/local_clock.h>
-
#include "AudioMixer.h"
#include "AudioFlinger.h"
#include "ServiceUtilities.h"
@@ -53,6 +50,10 @@
#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 {
// ----------------------------------------------------------------------------
@@ -88,7 +89,7 @@
mChannelCount(isOut ?
audio_channel_count_from_out_mask(channelMask) :
audio_channel_count_from_in_mask(channelMask)),
- mFrameSize(audio_is_linear_pcm(format) ?
+ mFrameSize(audio_has_proportional_frames(format) ?
mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)),
mFrameCount(frameCount),
mSessionId(sessionId),
@@ -100,13 +101,11 @@
mType(type),
mThreadIoHandle(thread->id())
{
- // if the caller is us, trust the specified uid
- if (IPCThreadState::self()->getCallingPid() != getpid_cached || clientUid == -1) {
- int newclientUid = IPCThreadState::self()->getCallingUid();
- if (clientUid != -1 && clientUid != newclientUid) {
- ALOGW("uid %d tried to pass itself off as %d", newclientUid, clientUid);
- }
- clientUid = newclientUid;
+ const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ if (!isTrustedCallingUid(callingUid) || clientUid == -1) {
+ ALOGW_IF(clientUid != -1 && clientUid != (int)callingUid,
+ "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, clientUid);
+ clientUid = (int)callingUid;
}
// clientUid contains the uid of the app that is responsible for this track, so we can blame
// battery usage on it.
@@ -244,7 +243,7 @@
// AudioBufferProvider interface
// getNextBuffer() = 0;
-// This implementation of releaseBuffer() is used by Track and RecordTrack, but not TimedTrack
+// This implementation of releaseBuffer() is used by Track and RecordTrack
void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
{
#ifdef TEE_SINK
@@ -310,43 +309,6 @@
return mTrack->attachAuxEffect(EffectId);
}
-status_t AudioFlinger::TrackHandle::allocateTimedBuffer(size_t size,
- sp<IMemory>* buffer) {
- if (!mTrack->isTimedTrack())
- return INVALID_OPERATION;
-
- PlaybackThread::TimedTrack* tt =
- reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get());
- return tt->allocateTimedBuffer(size, buffer);
-}
-
-status_t AudioFlinger::TrackHandle::queueTimedBuffer(const sp<IMemory>& buffer,
- int64_t pts) {
- if (!mTrack->isTimedTrack())
- return INVALID_OPERATION;
-
- if (buffer == 0 || buffer->pointer() == NULL) {
- ALOGE("queueTimedBuffer() buffer is 0 or has NULL pointer()");
- return BAD_VALUE;
- }
-
- PlaybackThread::TimedTrack* tt =
- reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get());
- return tt->queueTimedBuffer(buffer, pts);
-}
-
-status_t AudioFlinger::TrackHandle::setMediaTimeTransform(
- const LinearTransform& xform, int target) {
-
- if (!mTrack->isTimedTrack())
- return INVALID_OPERATION;
-
- PlaybackThread::TimedTrack* tt =
- reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get());
- return tt->setMediaTimeTransform(
- xform, static_cast<TimedAudioTrack::TargetTimeline>(target));
-}
-
status_t AudioFlinger::TrackHandle::setParameters(const String8& keyValuePairs) {
return mTrack->setParameters(keyValuePairs);
}
@@ -399,6 +361,9 @@
mAuxBuffer(NULL),
mAuxEffectId(0), mHasVolumeController(false),
mPresentationCompleteFrames(0),
+ mFrameMap(16 /* sink-frame-to-track-frame map memory */),
+ mSinkTimestampValid(false),
+ // mSinkTimestamp
mFastIndex(-1),
mCachedVolume(1.0),
mIsInvalid(false),
@@ -592,7 +557,7 @@
// AudioBufferProvider interface
status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(
- AudioBufferProvider::Buffer* buffer, int64_t pts __unused)
+ AudioBufferProvider::Buffer* buffer)
{
ServerProxy::Buffer buf;
size_t desiredFrames = buffer->frameCount;
@@ -602,7 +567,10 @@
buffer->raw = buf.mRaw;
if (buf.mFrameCount == 0) {
mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
+ } else {
+ mAudioTrackServerProxy->tallyUnderrunFrames(0);
}
+
return status;
}
@@ -628,6 +596,20 @@
return mAudioTrackServerProxy->framesReleased();
}
+void AudioFlinger::PlaybackThread::Track::onTimestamp(const AudioTimestamp ×tamp)
+{
+ // This call comes from a FastTrack and should be kept lockless.
+ // The server side frames are already translated to client frames.
+
+ ExtendedTimestamp ets;
+ ets.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
+ timestamp.mTime.tv_sec * 1000000000LL + timestamp.mTime.tv_nsec;
+ ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = timestamp.mPosition;
+
+ // Caution, this doesn't set the timebase for BOOTTIME properly, but is ignored right now.
+ mAudioTrackServerProxy->setTimestamp(ets);
+}
+
// Don't call for fast tracks; the framesReady() could result in priority inversion
bool AudioFlinger::PlaybackThread::Track::isReady() const {
if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) {
@@ -691,6 +673,11 @@
ALOGV("? => ACTIVE (%d) on thread %p", mName, this);
}
+ // states to reset position info for non-offloaded/direct tracks
+ if (!isOffloaded() && !isDirect()
+ && (state == IDLE || state == STOPPED || state == FLUSHED)) {
+ mFrameMap.reset();
+ }
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
if (isFastTrack()) {
// refresh fast track underruns on start because that field is never cleared
@@ -897,36 +884,31 @@
Mutex::Autolock _l(thread->mLock);
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
- status_t result = INVALID_OPERATION;
- if (!isOffloaded() && !isDirect()) {
- if (!playbackThread->mLatchQValid) {
- return INVALID_OPERATION;
- }
- // FIXME Not accurate under dynamic changes of sample rate and speed.
- // Do not use track's mSampleRate as it is not current for mixer tracks.
- uint32_t sampleRate = mAudioTrackServerProxy->getSampleRate();
- AudioPlaybackRate playbackRate = mAudioTrackServerProxy->getPlaybackRate();
- uint32_t unpresentedFrames = ((double) playbackThread->mLatchQ.mUnpresentedFrames *
- sampleRate * playbackRate.mSpeed)/ playbackThread->mSampleRate;
- // FIXME Since we're using a raw pointer as the key, it is theoretically possible
- // for a brand new track to share the same address as a recently destroyed
- // track, and thus for us to get the frames released of the wrong track.
- // It is unlikely that we would be able to call getTimestamp() so quickly
- // right after creating a new track. Nevertheless, the index here should
- // be changed to something that is unique. Or use a completely different strategy.
- ssize_t i = playbackThread->mLatchQ.mFramesReleased.indexOfKey(this);
- uint32_t framesWritten = i >= 0 ?
- playbackThread->mLatchQ.mFramesReleased[i] :
- mAudioTrackServerProxy->framesReleased();
- if (framesWritten >= unpresentedFrames) {
- timestamp.mPosition = framesWritten - unpresentedFrames;
- timestamp.mTime = playbackThread->mLatchQ.mTimestamp.mTime;
- result = NO_ERROR;
- }
- } else { // offloaded or direct
- result = playbackThread->getTimestamp_l(timestamp);
+ if (isOffloaded() || isDirect()) {
+ return playbackThread->getTimestamp_l(timestamp);
}
+ if (!mFrameMap.hasData()) {
+ // WOULD_BLOCK is consistent with AudioTrack::getTimestamp() in the
+ // FLUSHED and STOPPED state. We should only return INVALID_OPERATION
+ // when this method is not permitted due to configuration or device.
+ return WOULD_BLOCK;
+ }
+ status_t result = OK;
+ if (!mSinkTimestampValid) { // if no sink position, try to fetch again
+ result = playbackThread->getTimestamp_l(mSinkTimestamp);
+ }
+
+ if (result == OK) {
+ // Lookup the track frame corresponding to the sink frame position.
+ timestamp.mPosition = mFrameMap.findX(mSinkTimestamp.mPosition);
+ timestamp.mTime = mSinkTimestamp.mTime;
+ // ALOGD("track (server-side) timestamp: mPosition(%u) mTime(%llu)",
+ // timestamp.mPosition, TIME_TO_NANOS(timestamp.mTime));
+ }
+ // (Possible) FIXME: mSinkTimestamp is updated only when the track is on
+ // the Thread active list. If the track is no longer on the thread active
+ // list should we use current time?
return result;
}
@@ -1116,526 +1098,19 @@
mResumeToStopping = false;
}
}
-// ----------------------------------------------------------------------------
-sp<AudioFlinger::PlaybackThread::TimedTrack>
-AudioFlinger::PlaybackThread::TimedTrack::create(
- PlaybackThread *thread,
- const sp<Client>& client,
- audio_stream_type_t streamType,
- uint32_t sampleRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- size_t frameCount,
- const sp<IMemory>& sharedBuffer,
- int sessionId,
- int uid)
-{
- if (!client->reserveTimedTrack())
- return 0;
-
- return new TimedTrack(
- thread, client, streamType, sampleRate, format, channelMask, frameCount,
- sharedBuffer, sessionId, uid);
-}
-
-AudioFlinger::PlaybackThread::TimedTrack::TimedTrack(
- PlaybackThread *thread,
- const sp<Client>& client,
- audio_stream_type_t streamType,
- uint32_t sampleRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- size_t frameCount,
- const sp<IMemory>& sharedBuffer,
- int sessionId,
- int uid)
- : Track(thread, client, streamType, sampleRate, format, channelMask,
- frameCount, (sharedBuffer != 0) ? sharedBuffer->pointer() : NULL, sharedBuffer,
- sessionId, uid, IAudioFlinger::TRACK_TIMED, TYPE_TIMED),
- mQueueHeadInFlight(false),
- mTrimQueueHeadOnRelease(false),
- mFramesPendingInQueue(0),
- mTimedSilenceBuffer(NULL),
- mTimedSilenceBufferSize(0),
- mTimedAudioOutputOnTime(false),
- mMediaTimeTransformValid(false)
-{
- LocalClock lc;
- mLocalTimeFreq = lc.getLocalFreq();
-
- mLocalTimeToSampleTransform.a_zero = 0;
- mLocalTimeToSampleTransform.b_zero = 0;
- mLocalTimeToSampleTransform.a_to_b_numer = sampleRate;
- mLocalTimeToSampleTransform.a_to_b_denom = mLocalTimeFreq;
- LinearTransform::reduce(&mLocalTimeToSampleTransform.a_to_b_numer,
- &mLocalTimeToSampleTransform.a_to_b_denom);
-
- mMediaTimeToSampleTransform.a_zero = 0;
- mMediaTimeToSampleTransform.b_zero = 0;
- mMediaTimeToSampleTransform.a_to_b_numer = sampleRate;
- mMediaTimeToSampleTransform.a_to_b_denom = 1000000;
- LinearTransform::reduce(&mMediaTimeToSampleTransform.a_to_b_numer,
- &mMediaTimeToSampleTransform.a_to_b_denom);
-}
-
-AudioFlinger::PlaybackThread::TimedTrack::~TimedTrack() {
- mClient->releaseTimedTrack();
- delete [] mTimedSilenceBuffer;
-}
-
-status_t AudioFlinger::PlaybackThread::TimedTrack::allocateTimedBuffer(
- size_t size, sp<IMemory>* buffer) {
-
- Mutex::Autolock _l(mTimedBufferQueueLock);
-
- trimTimedBufferQueue_l();
-
- // lazily initialize the shared memory heap for timed buffers
- if (mTimedMemoryDealer == NULL) {
- const int kTimedBufferHeapSize = 512 << 10;
-
- mTimedMemoryDealer = new MemoryDealer(kTimedBufferHeapSize,
- "AudioFlingerTimed");
- if (mTimedMemoryDealer == NULL) {
- return NO_MEMORY;
- }
- }
-
- sp<IMemory> newBuffer = mTimedMemoryDealer->allocate(size);
- if (newBuffer == 0 || newBuffer->pointer() == NULL) {
- return NO_MEMORY;
- }
-
- *buffer = newBuffer;
- return NO_ERROR;
-}
-
-// caller must hold mTimedBufferQueueLock
-void AudioFlinger::PlaybackThread::TimedTrack::trimTimedBufferQueue_l() {
- int64_t mediaTimeNow;
- {
- Mutex::Autolock mttLock(mMediaTimeTransformLock);
- if (!mMediaTimeTransformValid)
- return;
-
- int64_t targetTimeNow;
- status_t res = (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME)
- ? mCCHelper.getCommonTime(&targetTimeNow)
- : mCCHelper.getLocalTime(&targetTimeNow);
-
- if (OK != res)
- return;
-
- if (!mMediaTimeTransform.doReverseTransform(targetTimeNow,
- &mediaTimeNow)) {
- return;
- }
- }
-
- size_t trimEnd;
- for (trimEnd = 0; trimEnd < mTimedBufferQueue.size(); trimEnd++) {
- int64_t bufEnd;
-
- if ((trimEnd + 1) < mTimedBufferQueue.size()) {
- // We have a next buffer. Just use its PTS as the PTS of the frame
- // following the last frame in this buffer. If the stream is sparse
- // (ie, there are deliberate gaps left in the stream which should be
- // filled with silence by the TimedAudioTrack), then this can result
- // in one extra buffer being left un-trimmed when it could have
- // been. In general, this is not typical, and we would rather
- // optimized away the TS calculation below for the more common case
- // where PTSes are contiguous.
- bufEnd = mTimedBufferQueue[trimEnd + 1].pts();
- } else {
- // We have no next buffer. Compute the PTS of the frame following
- // the last frame in this buffer by computing the duration of of
- // this frame in media time units and adding it to the PTS of the
- // buffer.
- int64_t frameCount = mTimedBufferQueue[trimEnd].buffer()->size()
- / mFrameSize;
-
- if (!mMediaTimeToSampleTransform.doReverseTransform(frameCount,
- &bufEnd)) {
- ALOGE("Failed to convert frame count of %lld to media time"
- " duration" " (scale factor %d/%u) in %s",
- frameCount,
- mMediaTimeToSampleTransform.a_to_b_numer,
- mMediaTimeToSampleTransform.a_to_b_denom,
- __PRETTY_FUNCTION__);
- break;
- }
- bufEnd += mTimedBufferQueue[trimEnd].pts();
- }
-
- if (bufEnd > mediaTimeNow)
- break;
-
- // Is the buffer we want to use in the middle of a mix operation right
- // now? If so, don't actually trim it. Just wait for the releaseBuffer
- // from the mixer which should be coming back shortly.
- if (!trimEnd && mQueueHeadInFlight) {
- mTrimQueueHeadOnRelease = true;
- }
- }
-
- size_t trimStart = mTrimQueueHeadOnRelease ? 1 : 0;
- if (trimStart < trimEnd) {
- // Update the bookkeeping for framesReady()
- for (size_t i = trimStart; i < trimEnd; ++i) {
- updateFramesPendingAfterTrim_l(mTimedBufferQueue[i], "trim");
- }
-
- // Now actually remove the buffers from the queue.
- mTimedBufferQueue.removeItemsAt(trimStart, trimEnd);
- }
-}
-
-void AudioFlinger::PlaybackThread::TimedTrack::trimTimedBufferQueueHead_l(
- const char* logTag) {
- ALOG_ASSERT(mTimedBufferQueue.size() > 0,
- "%s called (reason \"%s\"), but timed buffer queue has no"
- " elements to trim.", __FUNCTION__, logTag);
-
- updateFramesPendingAfterTrim_l(mTimedBufferQueue[0], logTag);
- mTimedBufferQueue.removeAt(0);
-}
-
-void AudioFlinger::PlaybackThread::TimedTrack::updateFramesPendingAfterTrim_l(
- const TimedBuffer& buf,
- const char* logTag __unused) {
- uint32_t bufBytes = buf.buffer()->size();
- uint32_t consumedAlready = buf.position();
-
- ALOG_ASSERT(consumedAlready <= bufBytes,
- "Bad bookkeeping while updating frames pending. Timed buffer is"
- " only %u bytes long, but claims to have consumed %u"
- " bytes. (update reason: \"%s\")",
- bufBytes, consumedAlready, logTag);
-
- uint32_t bufFrames = (bufBytes - consumedAlready) / mFrameSize;
- ALOG_ASSERT(mFramesPendingInQueue >= bufFrames,
- "Bad bookkeeping while updating frames pending. Should have at"
- " least %u queued frames, but we think we have only %u. (update"
- " reason: \"%s\")",
- bufFrames, mFramesPendingInQueue, logTag);
-
- mFramesPendingInQueue -= bufFrames;
-}
-
-status_t AudioFlinger::PlaybackThread::TimedTrack::queueTimedBuffer(
- const sp<IMemory>& buffer, int64_t pts) {
-
- {
- Mutex::Autolock mttLock(mMediaTimeTransformLock);
- if (!mMediaTimeTransformValid)
- return INVALID_OPERATION;
- }
-
- Mutex::Autolock _l(mTimedBufferQueueLock);
-
- uint32_t bufFrames = buffer->size() / mFrameSize;
- mFramesPendingInQueue += bufFrames;
- mTimedBufferQueue.add(TimedBuffer(buffer, pts));
-
- return NO_ERROR;
-}
-
-status_t AudioFlinger::PlaybackThread::TimedTrack::setMediaTimeTransform(
- const LinearTransform& xform, TimedAudioTrack::TargetTimeline target) {
-
- ALOGVV("setMediaTimeTransform az=%lld bz=%lld n=%d d=%u tgt=%d",
- xform.a_zero, xform.b_zero, xform.a_to_b_numer, xform.a_to_b_denom,
- target);
-
- if (!(target == TimedAudioTrack::LOCAL_TIME ||
- target == TimedAudioTrack::COMMON_TIME)) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock lock(mMediaTimeTransformLock);
- mMediaTimeTransform = xform;
- mMediaTimeTransformTarget = target;
- mMediaTimeTransformValid = true;
-
- return NO_ERROR;
-}
-
-#define min(a, b) ((a) < (b) ? (a) : (b))
-
-// implementation of getNextBuffer for tracks whose buffers have timestamps
-status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer(
- AudioBufferProvider::Buffer* buffer, int64_t pts)
-{
- if (pts == AudioBufferProvider::kInvalidPTS) {
- buffer->raw = NULL;
- buffer->frameCount = 0;
- mTimedAudioOutputOnTime = false;
- return INVALID_OPERATION;
- }
-
- Mutex::Autolock _l(mTimedBufferQueueLock);
-
- ALOG_ASSERT(!mQueueHeadInFlight,
- "getNextBuffer called without releaseBuffer!");
-
- while (true) {
-
- // if we have no timed buffers, then fail
- if (mTimedBufferQueue.isEmpty()) {
- buffer->raw = NULL;
- buffer->frameCount = 0;
- return NOT_ENOUGH_DATA;
- }
-
- TimedBuffer& head = mTimedBufferQueue.editItemAt(0);
-
- // calculate the PTS of the head of the timed buffer queue expressed in
- // local time
- int64_t headLocalPTS;
- {
- Mutex::Autolock mttLock(mMediaTimeTransformLock);
-
- ALOG_ASSERT(mMediaTimeTransformValid, "media time transform invalid");
-
- if (mMediaTimeTransform.a_to_b_denom == 0) {
- // the transform represents a pause, so yield silence
- timedYieldSilence_l(buffer->frameCount, buffer);
- return NO_ERROR;
- }
-
- int64_t transformedPTS;
- if (!mMediaTimeTransform.doForwardTransform(head.pts(),
- &transformedPTS)) {
- // the transform failed. this shouldn't happen, but if it does
- // then just drop this buffer
- ALOGW("timedGetNextBuffer transform failed");
- buffer->raw = NULL;
- buffer->frameCount = 0;
- trimTimedBufferQueueHead_l("getNextBuffer; no transform");
- return NO_ERROR;
- }
-
- if (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME) {
- if (OK != mCCHelper.commonTimeToLocalTime(transformedPTS,
- &headLocalPTS)) {
- buffer->raw = NULL;
- buffer->frameCount = 0;
- return INVALID_OPERATION;
- }
- } else {
- headLocalPTS = transformedPTS;
- }
- }
-
- uint32_t sr = sampleRate();
-
- // adjust the head buffer's PTS to reflect the portion of the head buffer
- // that has already been consumed
- int64_t effectivePTS = headLocalPTS +
- ((head.position() / mFrameSize) * mLocalTimeFreq / sr);
-
- // Calculate the delta in samples between the head of the input buffer
- // queue and the start of the next output buffer that will be written.
- // If the transformation fails because of over or underflow, it means
- // that the sample's position in the output stream is so far out of
- // whack that it should just be dropped.
- int64_t sampleDelta;
- if (llabs(effectivePTS - pts) >= (static_cast<int64_t>(1) << 31)) {
- ALOGV("*** head buffer is too far from PTS: dropped buffer");
- trimTimedBufferQueueHead_l("getNextBuffer, buf pts too far from"
- " mix");
- continue;
- }
- if (!mLocalTimeToSampleTransform.doForwardTransform(
- (effectivePTS - pts) << 32, &sampleDelta)) {
- ALOGV("*** too late during sample rate transform: dropped buffer");
- trimTimedBufferQueueHead_l("getNextBuffer, bad local to sample");
- continue;
- }
-
- ALOGVV("*** getNextBuffer head.pts=%lld head.pos=%d pts=%lld"
- " sampleDelta=[%d.%08x]",
- head.pts(), head.position(), pts,
- static_cast<int32_t>((sampleDelta >= 0 ? 0 : 1)
- + (sampleDelta >> 32)),
- static_cast<uint32_t>(sampleDelta & 0xFFFFFFFF));
-
- // if the delta between the ideal placement for the next input sample and
- // the current output position is within this threshold, then we will
- // concatenate the next input samples to the previous output
- const int64_t kSampleContinuityThreshold =
- (static_cast<int64_t>(sr) << 32) / 250;
-
- // if this is the first buffer of audio that we're emitting from this track
- // then it should be almost exactly on time.
- const int64_t kSampleStartupThreshold = 1LL << 32;
-
- if ((mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleContinuityThreshold) ||
- (!mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleStartupThreshold)) {
- // the next input is close enough to being on time, so concatenate it
- // with the last output
- timedYieldSamples_l(buffer);
-
- ALOGVV("*** on time: head.pos=%d frameCount=%u",
- head.position(), buffer->frameCount);
- return NO_ERROR;
- }
-
- // Looks like our output is not on time. Reset our on timed status.
- // Next time we mix samples from our input queue, then should be within
- // the StartupThreshold.
- mTimedAudioOutputOnTime = false;
- if (sampleDelta > 0) {
- // the gap between the current output position and the proper start of
- // the next input sample is too big, so fill it with silence
- uint32_t framesUntilNextInput = (sampleDelta + 0x80000000) >> 32;
-
- timedYieldSilence_l(framesUntilNextInput, buffer);
- ALOGV("*** silence: frameCount=%u", buffer->frameCount);
- return NO_ERROR;
- } else {
- // the next input sample is late
- uint32_t lateFrames = static_cast<uint32_t>(-((sampleDelta + 0x80000000) >> 32));
- size_t onTimeSamplePosition =
- head.position() + lateFrames * mFrameSize;
-
- if (onTimeSamplePosition > head.buffer()->size()) {
- // all the remaining samples in the head are too late, so
- // drop it and move on
- ALOGV("*** too late: dropped buffer");
- trimTimedBufferQueueHead_l("getNextBuffer, dropped late buffer");
- continue;
- } else {
- // skip over the late samples
- head.setPosition(onTimeSamplePosition);
-
- // yield the available samples
- timedYieldSamples_l(buffer);
-
- ALOGV("*** late: head.pos=%d frameCount=%u", head.position(), buffer->frameCount);
- return NO_ERROR;
- }
- }
- }
-}
-
-// Yield samples from the timed buffer queue head up to the given output
-// buffer's capacity.
-//
-// Caller must hold mTimedBufferQueueLock
-void AudioFlinger::PlaybackThread::TimedTrack::timedYieldSamples_l(
- AudioBufferProvider::Buffer* buffer) {
-
- const TimedBuffer& head = mTimedBufferQueue[0];
-
- buffer->raw = (static_cast<uint8_t*>(head.buffer()->pointer()) +
- head.position());
-
- uint32_t framesLeftInHead = ((head.buffer()->size() - head.position()) /
- mFrameSize);
- size_t framesRequested = buffer->frameCount;
- buffer->frameCount = min(framesLeftInHead, framesRequested);
-
- mQueueHeadInFlight = true;
- mTimedAudioOutputOnTime = true;
-}
-
-// Yield samples of silence up to the given output buffer's capacity
-//
-// Caller must hold mTimedBufferQueueLock
-void AudioFlinger::PlaybackThread::TimedTrack::timedYieldSilence_l(
- uint32_t numFrames, AudioBufferProvider::Buffer* buffer) {
-
- // lazily allocate a buffer filled with silence
- if (mTimedSilenceBufferSize < numFrames * mFrameSize) {
- delete [] mTimedSilenceBuffer;
- mTimedSilenceBufferSize = numFrames * mFrameSize;
- mTimedSilenceBuffer = new uint8_t[mTimedSilenceBufferSize];
- memset(mTimedSilenceBuffer, 0, mTimedSilenceBufferSize);
- }
-
- buffer->raw = mTimedSilenceBuffer;
- size_t framesRequested = buffer->frameCount;
- buffer->frameCount = min(numFrames, framesRequested);
-
- mTimedAudioOutputOnTime = false;
-}
-
-// AudioBufferProvider interface
-void AudioFlinger::PlaybackThread::TimedTrack::releaseBuffer(
- AudioBufferProvider::Buffer* buffer) {
-
- Mutex::Autolock _l(mTimedBufferQueueLock);
-
- // If the buffer which was just released is part of the buffer at the head
- // of the queue, be sure to update the amt of the buffer which has been
- // consumed. If the buffer being returned is not part of the head of the
- // queue, its either because the buffer is part of the silence buffer, or
- // because the head of the timed queue was trimmed after the mixer called
- // getNextBuffer but before the mixer called releaseBuffer.
- if (buffer->raw == mTimedSilenceBuffer) {
- ALOG_ASSERT(!mQueueHeadInFlight,
- "Queue head in flight during release of silence buffer!");
- goto done;
- }
-
- ALOG_ASSERT(mQueueHeadInFlight,
- "TimedTrack::releaseBuffer of non-silence buffer, but no queue"
- " head in flight.");
-
- if (mTimedBufferQueue.size()) {
- TimedBuffer& head = mTimedBufferQueue.editItemAt(0);
-
- void* start = head.buffer()->pointer();
- void* end = reinterpret_cast<void*>(
- reinterpret_cast<uint8_t*>(head.buffer()->pointer())
- + head.buffer()->size());
-
- ALOG_ASSERT((buffer->raw >= start) && (buffer->raw < end),
- "released buffer not within the head of the timed buffer"
- " queue; qHead = [%p, %p], released buffer = %p",
- start, end, buffer->raw);
-
- head.setPosition(head.position() +
- (buffer->frameCount * mFrameSize));
- mQueueHeadInFlight = false;
-
- ALOG_ASSERT(mFramesPendingInQueue >= buffer->frameCount,
- "Bad bookkeeping during releaseBuffer! Should have at"
- " least %u queued frames, but we think we have only %u",
- buffer->frameCount, mFramesPendingInQueue);
-
- mFramesPendingInQueue -= buffer->frameCount;
-
- if ((static_cast<size_t>(head.position()) >= head.buffer()->size())
- || mTrimQueueHeadOnRelease) {
- trimTimedBufferQueueHead_l("releaseBuffer");
- mTrimQueueHeadOnRelease = false;
- }
+//To be called with thread lock held
+void AudioFlinger::PlaybackThread::Track::updateTrackFrameInfo(
+ uint32_t trackFramesReleased, uint32_t sinkFramesWritten, AudioTimestamp *timeStamp) {
+ mFrameMap.push(trackFramesReleased, sinkFramesWritten);
+ if (timeStamp == NULL) {
+ mSinkTimestampValid = false;
} else {
- LOG_ALWAYS_FATAL("TimedTrack::releaseBuffer of non-silence buffer with no"
- " buffers in the timed buffer queue");
+ mSinkTimestampValid = true;
+ mSinkTimestamp = *timeStamp;
}
-
-done:
- buffer->raw = 0;
- buffer->frameCount = 0;
}
-size_t AudioFlinger::PlaybackThread::TimedTrack::framesReady() const {
- Mutex::Autolock _l(mTimedBufferQueueLock);
- return mFramesPendingInQueue;
-}
-
-AudioFlinger::PlaybackThread::TimedTrack::TimedBuffer::TimedBuffer()
- : mPTS(0), mPosition(0) {}
-
-AudioFlinger::PlaybackThread::TimedTrack::TimedBuffer::TimedBuffer(
- const sp<IMemory>& buffer, int64_t pts)
- : mBuffer(buffer), mPTS(pts), mPosition(0) {}
-
-
// ----------------------------------------------------------------------------
AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
@@ -1854,7 +1329,7 @@
// AudioBufferProvider interface
status_t AudioFlinger::PlaybackThread::PatchTrack::getNextBuffer(
- AudioBufferProvider::Buffer* buffer, int64_t pts)
+ AudioBufferProvider::Buffer* buffer)
{
ALOG_ASSERT(mPeerProxy != 0, "PatchTrack::getNextBuffer() called without peer proxy");
Proxy::Buffer buf;
@@ -1865,7 +1340,7 @@
if (buf.mFrameCount == 0) {
return WOULD_BLOCK;
}
- status = Track::getNextBuffer(buffer, pts);
+ status = Track::getNextBuffer(buffer);
return status;
}
@@ -1978,7 +1453,8 @@
}
mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
- mFrameSize, !isExternalTrack());
+ mFrameSize, !isExternalTrack());
+
mResamplerBufferProvider = new ResamplerBufferProvider(this);
if (flags & IAudioFlinger::TRACK_FAST) {
@@ -2004,8 +1480,7 @@
}
// AudioBufferProvider interface
-status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer,
- int64_t pts __unused)
+status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
{
ServerProxy::Buffer buf;
buf.mFrameCount = buffer->frameCount;
@@ -2116,6 +1591,24 @@
mFramesToDrop = 0;
}
+void AudioFlinger::RecordThread::RecordTrack::updateTrackFrameInfo(
+ int64_t trackFramesReleased, int64_t sourceFramesRead,
+ uint32_t halSampleRate, const ExtendedTimestamp ×tamp)
+{
+ ExtendedTimestamp local = timestamp;
+
+ // Convert HAL frames to server-side track frames at track sample rate.
+ // We use trackFramesReleased and sourceFramesRead as an anchor point.
+ for (int i = ExtendedTimestamp::LOCATION_SERVER; i < ExtendedTimestamp::LOCATION_MAX; ++i) {
+ if (local.mTimeNs[i] != 0) {
+ const int64_t relativeServerFrames = local.mPosition[i] - sourceFramesRead;
+ const int64_t relativeTrackFrames = relativeServerFrames
+ * mSampleRate / halSampleRate; // TODO: potential computation overflow
+ local.mPosition[i] = relativeTrackFrames + trackFramesReleased;
+ }
+ }
+ mServerProxy->setTimestamp(local);
+}
AudioFlinger::RecordThread::PatchRecord::PatchRecord(RecordThread *recordThread,
uint32_t sampleRate,
@@ -2145,7 +1638,7 @@
// AudioBufferProvider interface
status_t AudioFlinger::RecordThread::PatchRecord::getNextBuffer(
- AudioBufferProvider::Buffer* buffer, int64_t pts)
+ AudioBufferProvider::Buffer* buffer)
{
ALOG_ASSERT(mPeerProxy != 0, "PatchRecord::getNextBuffer() called without peer proxy");
Proxy::Buffer buf;
@@ -2157,7 +1650,7 @@
if (buf.mFrameCount == 0) {
return WOULD_BLOCK;
}
- status = RecordTrack::getNextBuffer(buffer, pts);
+ status = RecordTrack::getNextBuffer(buffer);
return status;
}
diff --git a/services/audioflinger/test-resample.cpp b/services/audioflinger/test-resample.cpp
index 7893778..bae3c5b 100644
--- a/services/audioflinger/test-resample.cpp
+++ b/services/audioflinger/test-resample.cpp
@@ -272,9 +272,7 @@
mFrameSize(frameSize),
mNextFrame(0), mUnrel(0), mPvalues(Pvalues), mNextPidx(0) {
}
- virtual status_t getNextBuffer(Buffer* buffer,
- int64_t pts = kInvalidPTS) {
- (void)pts; // suppress warning
+ virtual status_t getNextBuffer(Buffer* buffer) {
size_t requestedFrames = buffer->frameCount;
if (requestedFrames > mNumFrames - mNextFrame) {
buffer->frameCount = mNumFrames - mNextFrame;
diff --git a/services/audioflinger/tests/Android.mk b/services/audioflinger/tests/Android.mk
index e152468..6182de0 100644
--- a/services/audioflinger/tests/Android.mk
+++ b/services/audioflinger/tests/Android.mk
@@ -47,7 +47,6 @@
LOCAL_SHARED_LIBRARIES := \
libeffects \
libnbaio \
- libcommon_time_client \
libaudioresampler \
libaudioutils \
libdl \
diff --git a/services/audioflinger/tests/README b/services/audioflinger/tests/README
new file mode 100644
index 0000000..508e960
--- /dev/null
+++ b/services/audioflinger/tests/README
@@ -0,0 +1,13 @@
+For libsonic dependency:
+pushd external/sonic
+mm
+popd
+
+To build resampler library:
+pushd ..
+Optionally uncomment USE_NEON=false in Android.mk
+mm
+popd
+
+Then build here:
+mm
diff --git a/services/audioflinger/tests/run_all_unit_tests.sh b/services/audioflinger/tests/run_all_unit_tests.sh
index ffae6ae..113f39e 100755
--- a/services/audioflinger/tests/run_all_unit_tests.sh
+++ b/services/audioflinger/tests/run_all_unit_tests.sh
@@ -8,4 +8,5 @@
echo "waiting for device"
adb root && adb wait-for-device remount
-adb shell /system/bin/resampler_tests
+#adb shell /system/bin/resampler_tests
+adb shell /data/nativetest/resampler_tests/resampler_tests
diff --git a/services/audioflinger/tests/test-mixer.cpp b/services/audioflinger/tests/test-mixer.cpp
index 8da6245..65e22da 100644
--- a/services/audioflinger/tests/test-mixer.cpp
+++ b/services/audioflinger/tests/test-mixer.cpp
@@ -307,7 +307,7 @@
(char *) auxAddr + i * auxFrameSize);
}
}
- mixer->process(AudioBufferProvider::kInvalidPTS);
+ mixer->process();
}
outputFrames = i; // reset output frames to the data actually produced.
diff --git a/services/audioflinger/tests/test_utils.h b/services/audioflinger/tests/test_utils.h
index 3d51cdc..283c768 100644
--- a/services/audioflinger/tests/test_utils.h
+++ b/services/audioflinger/tests/test_utils.h
@@ -112,7 +112,7 @@
mNextIdx = 0;
}
- virtual android::status_t getNextBuffer(Buffer* buffer, int64_t pts __unused = kInvalidPTS)
+ virtual android::status_t getNextBuffer(Buffer* buffer)
{
size_t requestedFrames = buffer->frameCount;
if (requestedFrames > mNumFrames - mNextFrame) {
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index 5b38e1c..8218edd 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -24,6 +24,7 @@
$(call include-path-for, audio-utils) \
$(TOPDIR)frameworks/av/services/audiopolicy/common/include \
$(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \
+ $(TOPDIR)frameworks/av/services/audiopolicy/utilities
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -55,8 +56,7 @@
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
- managerdefault/AudioPolicyManager.cpp \
+LOCAL_SRC_FILES:= managerdefault/AudioPolicyManager.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -66,12 +66,15 @@
ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1)
+ifneq ($(USE_XML_AUDIO_POLICY_CONF), 1)
+$(error Configurable policy does not support legacy conf file)
+endif #ifneq ($(USE_XML_AUDIO_POLICY_CONF), 1)
+
LOCAL_REQUIRED_MODULES := \
parameter-framework.policy \
audio_policy_criteria.conf \
-LOCAL_C_INCLUDES += \
- $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include \
+LOCAL_C_INCLUDES += $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include
LOCAL_SHARED_LIBRARIES += libaudiopolicyengineconfigurable
@@ -79,16 +82,25 @@
LOCAL_SHARED_LIBRARIES += libaudiopolicyenginedefault
-endif
+endif # ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1)
LOCAL_C_INCLUDES += \
$(TOPDIR)frameworks/av/services/audiopolicy/common/include \
$(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \
+ $(TOPDIR)frameworks/av/services/audiopolicy/utilities
LOCAL_STATIC_LIBRARIES := \
libmedia_helper \
libaudiopolicycomponents
+ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
+LOCAL_STATIC_LIBRARIES += libxml2
+
+LOCAL_SHARED_LIBRARIES += libicuuc
+
+LOCAL_CFLAGS += -DUSE_XML_AUDIO_POLICY_CONF
+endif #ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
+
LOCAL_MODULE:= libaudiopolicymanagerdefault
include $(BUILD_SHARED_LIBRARY)
@@ -108,7 +120,7 @@
LOCAL_C_INCLUDES += \
$(TOPDIR)frameworks/av/services/audiopolicy/common/include \
- $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \
+ $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface
LOCAL_MODULE:= libaudiopolicymanager
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index c1e7bc0..dd3f144 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -225,8 +225,12 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle) = 0;
+ audio_io_handle_t *handle,
+ uid_t uid) = 0;
virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
+
+ virtual status_t setMasterMono(bool mono) = 0;
+ virtual status_t getMasterMono(bool *mono) = 0;
};
@@ -331,6 +335,9 @@
virtual audio_unique_id_t newAudioUniqueId() = 0;
virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
+
+ virtual void onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source) = 0;
};
extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface);
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 712f7a7..d091179 100755
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -30,6 +30,17 @@
float mDBAttenuation;
};
+/**
+ * device categories used for volume curve management.
+ */
+enum device_category {
+ DEVICE_CATEGORY_HEADSET,
+ DEVICE_CATEGORY_SPEAKER,
+ DEVICE_CATEGORY_EARPIECE,
+ DEVICE_CATEGORY_EXT_MEDIA,
+ DEVICE_CATEGORY_CNT
+};
+
class Volume
{
public:
@@ -50,17 +61,6 @@
};
/**
- * device categories used for volume curve management.
- */
- enum device_category {
- DEVICE_CATEGORY_HEADSET,
- DEVICE_CATEGORY_SPEAKER,
- DEVICE_CATEGORY_EARPIECE,
- DEVICE_CATEGORY_EXT_MEDIA,
- DEVICE_CATEGORY_CNT
- };
-
- /**
* extract one device relevant for volume control from multiple device selection
*
* @param[in] device for which the volume category is associated
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 4b73e3c..d9e7212 100755
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -18,6 +18,8 @@
#include <system/audio.h>
+static const audio_format_t gDynamicFormat = AUDIO_FORMAT_DEFAULT;
+
// For mixed output and inputs, the policy will use max mixer sampling rates.
// Do not limit sampling rate otherwise
#define MAX_MIXER_SAMPLING_RATE 192000
@@ -86,3 +88,18 @@
(((device & AUDIO_DEVICE_BIT_IN) == 0) &&
((device & APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL) != 0));
}
+
+/* Indicates if audio formats are equivalent when considering a match between
+ * audio HAL supported formats and client requested formats
+ */
+static inline bool audio_formats_match(audio_format_t format1,
+ audio_format_t format2)
+{
+ if (audio_is_linear_pcm(format1) &&
+ (audio_bytes_per_sample(format1) > 2) &&
+ audio_is_linear_pcm(format2) &&
+ (audio_bytes_per_sample(format2) > 2)) {
+ return true;
+ }
+ return format1 == format2;
+}
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 8728ff3..5c81410 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -5,28 +5,55 @@
LOCAL_SRC_FILES:= \
src/DeviceDescriptor.cpp \
src/AudioGain.cpp \
- src/StreamDescriptor.cpp \
src/HwModule.cpp \
src/IOProfile.cpp \
src/AudioPort.cpp \
+ src/AudioProfile.cpp \
+ src/AudioRoute.cpp \
src/AudioPolicyMix.cpp \
src/AudioPatch.cpp \
src/AudioInputDescriptor.cpp \
src/AudioOutputDescriptor.cpp \
+ src/AudioCollections.cpp \
src/EffectDescriptor.cpp \
- src/ConfigParsingUtils.cpp \
src/SoundTriggerSession.cpp \
src/SessionRoute.cpp \
+ src/AudioSourceDescriptor.cpp \
+ src/VolumeCurve.cpp \
+ src/TypeConverter.cpp \
+ src/AudioSession.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
liblog \
-LOCAL_C_INCLUDES += \
+LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
$(TOPDIR)frameworks/av/services/audiopolicy/common/include \
- $(TOPDIR)frameworks/av/services/audiopolicy
+ $(TOPDIR)frameworks/av/services/audiopolicy \
+ $(TOPDIR)frameworks/av/services/audiopolicy/utilities \
+
+ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
+
+LOCAL_SRC_FILES += src/Serializer.cpp
+
+LOCAL_STATIC_LIBRARIES += libxml2
+
+LOCAL_SHARED_LIBRARIES += libicuuc
+
+LOCAL_C_INCLUDES += \
+ $(TOPDIR)external/libxml2/include \
+ $(TOPDIR)external/icu/icu4c/source/common
+
+else
+
+LOCAL_SRC_FILES += \
+ src/ConfigParsingUtils.cpp \
+ src/StreamDescriptor.cpp \
+ src/Gains.cpp
+
+endif #ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
LOCAL_EXPORT_C_INCLUDE_DIRS := \
$(LOCAL_PATH)/include
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
new file mode 100644
index 0000000..8f00d22
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+class AudioPort;
+class AudioRoute;
+
+class AudioPortVector : public Vector<sp<AudioPort> >
+{
+public:
+ sp<AudioPort> findByTagName(const String8 &tagName) const;
+};
+
+
+class AudioRouteVector : public Vector<sp<AudioRoute> >
+{
+public:
+ status_t dump(int fd, int spaces) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
index 21fbf9b..cea5c0b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
@@ -28,10 +28,39 @@
AudioGain(int index, bool useInChannelMask);
virtual ~AudioGain() {}
+ void setMode(audio_gain_mode_t mode) { mGain.mode = mode; }
+ const audio_gain_mode_t &getMode() const { return mGain.mode; }
+
+ void setChannelMask(audio_channel_mask_t mask) { mGain.channel_mask = mask; }
+ const audio_channel_mask_t &getChannelMask() const { return mGain.channel_mask; }
+
+ void setMinValueInMb(int minValue) { mGain.min_value = minValue; }
+ int getMinValueInMb() const { return mGain.min_value; }
+
+ void setMaxValueInMb(int maxValue) { mGain.max_value = maxValue; }
+ int getMaxValueInMb() const { return mGain.max_value; }
+
+ void setDefaultValueInMb(int defaultValue) { mGain.default_value = defaultValue; }
+ int getDefaultValueInMb() const { return mGain.default_value; }
+
+ void setStepValueInMb(uint32_t stepValue) { mGain.step_value = stepValue; }
+ int getStepValueInMb() const { return mGain.step_value; }
+
+ void setMinRampInMs(uint32_t minRamp) { mGain.min_ramp_ms = minRamp; }
+ int getMinRampInMs() const { return mGain.min_ramp_ms; }
+
+ void setMaxRampInMs(uint32_t maxRamp) { mGain.max_ramp_ms = maxRamp; }
+ int getMaxRampInMs() const { return mGain.max_ramp_ms; }
+
+ // TODO: remove dump from here (split serialization)
void dump(int fd, int spaces, int index) const;
void getDefaultConfig(struct audio_gain_config *config);
status_t checkConfig(const struct audio_gain_config *config);
+
+ const struct audio_gain &getGain() const { return mGain; }
+
+private:
int mIndex;
struct audio_gain mGain;
bool mUseInChannelMask;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 48d09ed..77c0d07 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -17,6 +17,7 @@
#pragma once
#include "AudioPort.h"
+#include "AudioSession.h"
#include <utils/Errors.h>
#include <system/audio.h>
#include <utils/SortedVector.h>
@@ -36,6 +37,7 @@
void setIoHandle(audio_io_handle_t ioHandle);
audio_port_handle_t getId() const;
audio_module_handle_t getModuleHandle() const;
+ uint32_t getOpenRefCount() const;
status_t dump(int fd);
@@ -43,14 +45,7 @@
audio_devices_t mDevice; // current device this input is routed to
AudioMix *mPolicyMix; // non NULL when used by a dynamic policy
audio_patch_handle_t mPatchHandle;
- uint32_t mRefCount; // number of AudioRecord clients using
- // this input
- uint32_t mOpenRefCount;
- audio_source_t mInputSource; // input source selected by application
- //(mediarecorder.h)
const sp<IOProfile> mProfile; // I/O profile this output derives from
- SortedVector<audio_session_t> mSessions; // audio sessions attached to this input
- bool mIsSoundTrigger; // used by a soundtrigger capture
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig = NULL) const;
@@ -60,17 +55,27 @@
SortedVector<audio_session_t> getPreemptedSessions() const;
bool hasPreemptedSession(audio_session_t session) const;
void clearPreemptedSessions();
+ bool isActive() const;
+ bool isSourceActive(audio_source_t source) const;
+ audio_source_t inputSource() const;
+ bool isSoundTrigger() const;
+ status_t addAudioSession(audio_session_t session,
+ const sp<AudioSession>& audioSession);
+ status_t removeAudioSession(audio_session_t session);
+ sp<AudioSession> getAudioSession(audio_session_t session) const;
+ AudioSessionCollection getActiveAudioSessions() const;
private:
audio_port_handle_t mId;
- // Because a preemtible capture session can preempt another one, we end up in an endless loop
+ // audio sessions attached to this input
+ AudioSessionCollection mSessions;
+ // Because a preemptible capture session can preempt another one, we end up in an endless loop
// situation were each session is allowed to restart after being preempted,
// thus preempting the other one which restarts and so on.
// To avoid this situation, we store which audio session was preempted when
// a particular input started and prevent preemption of this active input by this session.
// We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc...
SortedVector<audio_session_t> mPreemptedSessions;
-
};
class AudioInputCollection :
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 50f622d..f8439be 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -22,12 +22,14 @@
#include <utils/Timers.h>
#include <utils/KeyedVector.h>
#include <system/audio.h>
+#include "AudioSourceDescriptor.h"
namespace android {
class IOProfile;
class AudioMix;
class AudioPolicyClientInterface;
+class DeviceDescriptor;
// descriptor for audio outputs. Used to maintain current configuration of each opened audio output
// and keep track of the usage of this output by each audio stream type.
@@ -126,6 +128,31 @@
uint32_t mGlobalRefCount; // non-stream-specific ref count
};
+// Audio output driven by an input device directly.
+class HwAudioOutputDescriptor: public AudioOutputDescriptor
+{
+public:
+ HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+ AudioPolicyClientInterface *clientInterface);
+ virtual ~HwAudioOutputDescriptor() {}
+
+ status_t dump(int fd);
+
+ virtual audio_devices_t supportedDevices();
+ virtual bool setVolume(float volume,
+ audio_stream_type_t stream,
+ audio_devices_t device,
+ uint32_t delayMs,
+ bool force);
+
+ virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig = NULL) const;
+ virtual void toAudioPort(struct audio_port *port) const;
+
+ const sp<AudioSourceDescriptor> mSource;
+
+};
+
class SwAudioOutputCollection :
public DefaultKeyedVector< audio_io_handle_t, sp<SwAudioOutputDescriptor> >
{
@@ -160,4 +187,19 @@
status_t dump(int fd) const;
};
+class HwAudioOutputCollection :
+ public DefaultKeyedVector< audio_io_handle_t, sp<HwAudioOutputDescriptor> >
+{
+public:
+ bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+
+ /**
+ * return true if any output is playing anything besides the stream to ignore
+ */
+ bool isAnyOutputActive(audio_stream_type_t streamToIgnore) const;
+
+ status_t dump(int fd) const;
+};
+
+
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
new file mode 100644
index 0000000..f2756b5
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <AudioGain.h>
+#include <VolumeCurve.h>
+#include <AudioPort.h>
+#include <AudioPatch.h>
+#include <DeviceDescriptor.h>
+#include <IOProfile.h>
+#include <HwModule.h>
+#include <AudioInputDescriptor.h>
+#include <AudioOutputDescriptor.h>
+#include <AudioPolicyMix.h>
+#include <EffectDescriptor.h>
+#include <SoundTriggerSession.h>
+#include <SessionRoute.h>
+
+namespace android {
+
+class AudioPolicyConfig
+{
+public:
+ AudioPolicyConfig(HwModuleCollection &hwModules,
+ DeviceVector &availableOutputDevices,
+ DeviceVector &availableInputDevices,
+ sp<DeviceDescriptor> &defaultOutputDevices,
+ bool &isSpeakerDrcEnabled,
+ VolumeCurvesCollection *volumes = nullptr)
+ : mHwModules(hwModules),
+ mAvailableOutputDevices(availableOutputDevices),
+ mAvailableInputDevices(availableInputDevices),
+ mDefaultOutputDevices(defaultOutputDevices),
+ mVolumeCurves(volumes),
+ mIsSpeakerDrcEnabled(isSpeakerDrcEnabled)
+ {}
+
+ void setVolumes(const VolumeCurvesCollection &volumes)
+ {
+ if (mVolumeCurves != nullptr) {
+ *mVolumeCurves = volumes;
+ }
+ }
+
+ void setHwModules(const HwModuleCollection &hwModules)
+ {
+ mHwModules = hwModules;
+ }
+
+ void addAvailableDevice(const sp<DeviceDescriptor> &availableDevice)
+ {
+ if (audio_is_output_device(availableDevice->type())) {
+ mAvailableOutputDevices.add(availableDevice);
+ } else if (audio_is_input_device(availableDevice->type())) {
+ mAvailableInputDevices.add(availableDevice);
+ }
+ }
+
+ void addAvailableInputDevices(const DeviceVector &availableInputDevices)
+ {
+ mAvailableInputDevices.add(availableInputDevices);
+ }
+
+ void addAvailableOutputDevices(const DeviceVector &availableOutputDevices)
+ {
+ mAvailableOutputDevices.add(availableOutputDevices);
+ }
+
+ void setSpeakerDrcEnabled(bool isSpeakerDrcEnabled)
+ {
+ mIsSpeakerDrcEnabled = isSpeakerDrcEnabled;
+ }
+
+ const HwModuleCollection getHwModules() const { return mHwModules; }
+
+ const DeviceVector &getAvailableInputDevices() const
+ {
+ return mAvailableInputDevices;
+ }
+
+ const DeviceVector &getAvailableOutputDevices() const
+ {
+ return mAvailableOutputDevices;
+ }
+
+ void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
+ {
+ mDefaultOutputDevices = defaultDevice;
+ }
+
+ const sp<DeviceDescriptor> &getDefaultOutputDevice() const { return mDefaultOutputDevices; }
+
+ void setDefault(void)
+ {
+ mDefaultOutputDevices = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
+ sp<HwModule> module;
+ sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
+ mAvailableOutputDevices.add(mDefaultOutputDevices);
+ mAvailableInputDevices.add(defaultInputDevice);
+
+ module = new HwModule("primary");
+
+ sp<OutputProfile> outProfile;
+ outProfile = new OutputProfile(String8("primary"));
+ outProfile->attach(module);
+ outProfile->addAudioProfile(
+ new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
+ outProfile->addSupportedDevice(mDefaultOutputDevices);
+ outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
+ module->mOutputProfiles.add(outProfile);
+
+ sp<InputProfile> inProfile;
+ inProfile = new InputProfile(String8("primary"));
+ inProfile->attach(module);
+ inProfile->addAudioProfile(
+ new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000));
+ inProfile->addSupportedDevice(defaultInputDevice);
+ module->mInputProfiles.add(inProfile);
+
+ mHwModules.add(module);
+ }
+
+private:
+ HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
+ DeviceVector &mAvailableOutputDevices;
+ DeviceVector &mAvailableInputDevices;
+ sp<DeviceDescriptor> &mDefaultOutputDevices;
+ VolumeCurvesCollection *mVolumeCurves;
+ bool &mIsSpeakerDrcEnabled;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index d51f4e1..c952831 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -69,7 +69,8 @@
* @return NO_ERROR if an output was found for the given attribute (in this case, the
* descriptor output param is initialized), error code otherwise.
*/
- status_t getOutputForAttr(audio_attributes_t attributes, sp<SwAudioOutputDescriptor> &desc);
+ status_t getOutputForAttr(audio_attributes_t attributes, uid_t uid,
+ sp<SwAudioOutputDescriptor> &desc);
audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource,
audio_devices_t availableDeviceTypes,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 4fdf5b4..5958f4f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -16,6 +16,8 @@
#pragma once
+#include "AudioCollections.h"
+#include "AudioProfile.h"
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>
@@ -27,14 +29,40 @@
class HwModule;
class AudioGain;
+class AudioRoute;
+typedef Vector<sp<AudioGain> > AudioGainCollection;
class AudioPort : public virtual RefBase
{
public:
- AudioPort(const String8& name, audio_port_type_t type,
- audio_port_role_t role);
+ AudioPort(const String8& name, audio_port_type_t type, audio_port_role_t role) :
+ mName(name), mType(type), mRole(role), mFlags(AUDIO_OUTPUT_FLAG_NONE) {}
+
virtual ~AudioPort() {}
+ void setName(const String8 &name) { mName = name; }
+ const String8 &getName() const { return mName; }
+
+ audio_port_type_t getType() const { return mType; }
+ audio_port_role_t getRole() const { return mRole; }
+
+ virtual const String8 getTagName() const = 0;
+
+ void setGains(const AudioGainCollection &gains) { mGains = gains; }
+ const AudioGainCollection &getGains() const { return mGains; }
+
+ void setFlags(uint32_t flags)
+ {
+ //force direct flag if offload flag is set: offloading implies a direct output stream
+ // and all common behaviors are driven by checking only the direct flag
+ // this should normally be set appropriately in the policy configuration file
+ if (mRole == AUDIO_PORT_ROLE_SOURCE && (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ flags |= AUDIO_OUTPUT_FLAG_DIRECT;
+ }
+ mFlags = flags;
+ }
+ uint32_t getFlags() const { return mFlags; }
+
virtual void attach(const sp<HwModule>& module);
bool isAttached() { return mModule != 0; }
@@ -43,66 +71,86 @@
virtual void toAudioPort(struct audio_port *port) const;
virtual void importAudioPort(const sp<AudioPort> port);
- void clearCapabilities();
- void loadSamplingRates(char *name);
- void loadFormats(char *name);
- void loadOutChannels(char *name);
- void loadInChannels(char *name);
+ void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }
- audio_gain_mode_t loadGainMode(char *name);
- void loadGain(cnode *root, int index);
- virtual void loadGains(cnode *root);
+ void setAudioProfiles(const AudioProfileVector &profiles) { mProfiles = profiles; }
+ AudioProfileVector &getAudioProfiles() { return mProfiles; }
+
+ bool hasValidAudioProfile() const { return mProfiles.hasValidProfile(); }
+
+ bool hasDynamicAudioProfile() const { return mProfiles.hasDynamicProfile(); }
// searches for an exact match
- status_t checkExactSamplingRate(uint32_t samplingRate) const;
- // searches for a compatible match, and returns the best match via updatedSamplingRate
- status_t checkCompatibleSamplingRate(uint32_t samplingRate,
- uint32_t *updatedSamplingRate) const;
- // searches for an exact match
- status_t checkExactChannelMask(audio_channel_mask_t channelMask) const;
- // searches for a compatible match, currently implemented for input channel masks only
- status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
- audio_channel_mask_t *updatedChannelMask) const;
+ status_t checkExactAudioProfile(uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format) const
+ {
+ return mProfiles.checkExactProfile(samplingRate, channelMask, format);
+ }
- status_t checkExactFormat(audio_format_t format) const;
- // searches for a compatible match, currently implemented for input formats only
- status_t checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat) const;
+ // searches for a compatible match, currently implemented for input
+ // parameters are input|output, returned value is the best match.
+ status_t checkCompatibleAudioProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format) const
+ {
+ return mProfiles.checkCompatibleProfile(samplingRate, channelMask, format, mType, mRole);
+ }
+
+ void clearAudioProfiles() { return mProfiles.clearProfiles(); }
+
status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;
- uint32_t pickSamplingRate() const;
- audio_channel_mask_t pickChannelMask() const;
- audio_format_t pickFormat() const;
+ void pickAudioProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format) const;
static const audio_format_t sPcmFormatCompareTable[];
- static int compareFormats(const audio_format_t *format1, const audio_format_t *format2) {
- return compareFormats(*format1, *format2);
- }
+
static int compareFormats(audio_format_t format1, audio_format_t format2);
+ // Used to select an audio HAL output stream with a sample format providing the
+ // less degradation for a given AudioTrack sample format.
+ static bool isBetterFormatMatch(audio_format_t newFormat,
+ audio_format_t currentFormat,
+ audio_format_t targetFormat);
+
audio_module_handle_t getModuleHandle() const;
uint32_t getModuleVersion() const;
const char *getModuleName() const;
- void dump(int fd, int spaces) const;
+ bool useInputChannelMask() const
+ {
+ return ((mType == AUDIO_PORT_TYPE_DEVICE) && (mRole == AUDIO_PORT_ROLE_SOURCE)) ||
+ ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
+ }
+
+ inline bool isDirectOutput() const
+ {
+ return (mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
+ (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
+ }
+
+ void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
+ const AudioRouteVector &getRoutes() const { return mRoutes; }
+
+ void dump(int fd, int spaces, bool verbose = true) const;
void log(const char* indent) const;
- String8 mName;
- audio_port_type_t mType;
- audio_port_role_t mRole;
- bool mUseInChannelMask;
- // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
- // indicates the supported parameters should be read from the output stream
- // after it is opened for the first time
- Vector <uint32_t> mSamplingRates; // supported sampling rates
- Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
- Vector <audio_format_t> mFormats; // supported audio formats
- Vector < sp<AudioGain> > mGains; // gain controllers
+ AudioGainCollection mGains; // gain controllers
sp<HwModule> mModule; // audio HW module exposing this I/O stream
- uint32_t mFlags; // attribute flags (e.g primary output,
- // direct output...).
private:
+ void pickChannelMask(audio_channel_mask_t &channelMask, const ChannelsVector &channelMasks) const;
+ void pickSamplingRate(uint32_t &rate,const SampleRateVector &samplingRates) const;
+
+ String8 mName;
+ audio_port_type_t mType;
+ audio_port_role_t mRole;
+ uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
+ AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
+ AudioRouteVector mRoutes; // Routes involving this port
static volatile int32_t mNextUniqueId;
};
@@ -113,9 +161,9 @@
virtual ~AudioPortConfig() {}
status_t applyAudioPortConfig(const struct audio_port_config *config,
- struct audio_port_config *backupConfig = NULL);
+ struct audio_port_config *backupConfig = NULL);
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig = NULL) const = 0;
+ const struct audio_port_config *srcConfig = NULL) const = 0;
virtual sp<AudioPort> getAudioPort() const = 0;
uint32_t mSamplingRate;
audio_format_t mFormat;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
new file mode 100644
index 0000000..404e27d
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
@@ -0,0 +1,352 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "policy.h"
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+typedef SortedVector<uint32_t> SampleRateVector;
+typedef SortedVector<audio_channel_mask_t> ChannelsVector;
+typedef Vector<audio_format_t> FormatVector;
+
+template <typename T>
+bool operator == (const SortedVector<T> &left, const SortedVector<T> &right);
+
+class AudioProfile : public virtual RefBase
+{
+public:
+ AudioProfile(audio_format_t format,
+ audio_channel_mask_t channelMasks,
+ uint32_t samplingRate) :
+ mName(String8("")),
+ mFormat(format)
+ {
+ mChannelMasks.add(channelMasks);
+ mSamplingRates.add(samplingRate);
+ }
+
+ AudioProfile(audio_format_t format,
+ const ChannelsVector &channelMasks,
+ const SampleRateVector &samplingRateCollection) :
+ mName(String8("")),
+ mFormat(format),
+ mChannelMasks(channelMasks),
+ mSamplingRates(samplingRateCollection)
+ {}
+
+ audio_format_t getFormat() const { return mFormat; }
+
+ void setChannels(const ChannelsVector &channelMasks)
+ {
+ if (mIsDynamicChannels) {
+ mChannelMasks = channelMasks;
+ }
+ }
+ const ChannelsVector &getChannels() const { return mChannelMasks; }
+
+ void setSampleRates(const SampleRateVector &sampleRates)
+ {
+ if (mIsDynamicRate) {
+ mSamplingRates = sampleRates;
+ }
+ }
+ const SampleRateVector &getSampleRates() const { return mSamplingRates; }
+
+ bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }
+
+ void clear()
+ {
+ if (mIsDynamicChannels) {
+ mChannelMasks.clear();
+ }
+ if (mIsDynamicRate) {
+ mSamplingRates.clear();
+ }
+ }
+
+ inline bool supportsChannels(audio_channel_mask_t channels) const
+ {
+ return mChannelMasks.indexOf(channels) >= 0;
+ }
+ inline bool supportsRate(uint32_t rate) const
+ {
+ return mSamplingRates.indexOf(rate) >= 0;
+ }
+
+ status_t checkExact(uint32_t rate, audio_channel_mask_t channels, audio_format_t format) const;
+
+ status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
+ audio_channel_mask_t &updatedChannelMask,
+ audio_port_type_t portType,
+ audio_port_role_t portRole) const;
+
+ status_t checkCompatibleSamplingRate(uint32_t samplingRate,
+ uint32_t &updatedSamplingRate) const;
+
+ bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; }
+ bool hasValidRates() const { return !mSamplingRates.isEmpty(); }
+ bool hasValidChannels() const { return !mChannelMasks.isEmpty(); }
+
+ void setDynamicChannels(bool dynamic) { mIsDynamicChannels = dynamic; }
+ bool isDynamicChannels() const { return mIsDynamicChannels; }
+
+ void setDynamicRate(bool dynamic) { mIsDynamicRate = dynamic; }
+ bool isDynamicRate() const { return mIsDynamicRate; }
+
+ void setDynamicFormat(bool dynamic) { mIsDynamicFormat = dynamic; }
+ bool isDynamicFormat() const { return mIsDynamicFormat; }
+
+ bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
+
+ void dump(int fd, int spaces) const;
+
+private:
+ String8 mName;
+ audio_format_t mFormat;
+ ChannelsVector mChannelMasks;
+ SampleRateVector mSamplingRates;
+
+ bool mIsDynamicFormat = false;
+ bool mIsDynamicChannels = false;
+ bool mIsDynamicRate = false;
+};
+
+
+class AudioProfileVector : public Vector<sp<AudioProfile> >
+{
+public:
+ ssize_t add(const sp<AudioProfile> &profile)
+ {
+ ssize_t index = Vector::add(profile);
+ // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
+ // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
+ // [](const audio_format_t *format1, const audio_format_t *format2) {
+ // return compareFormats(*format1, *format2);
+ // }
+ sort(compareFormats);
+ return index;
+ }
+
+ // This API is intended to be used by the policy manager once retrieving capabilities
+ // for a profile with dynamic format, rate and channels attributes
+ ssize_t addProfileFromHal(const sp<AudioProfile> &profileToAdd)
+ {
+ // Check valid profile to add:
+ if (!profileToAdd->hasValidFormat()) {
+ return -1;
+ }
+ if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+ FormatVector formats;
+ formats.add(profileToAdd->getFormat());
+ setFormats(FormatVector(formats));
+ return 0;
+ }
+ if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
+ setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
+ return 0;
+ }
+ if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+ setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
+ return 0;
+ }
+ // Go through the list of profile to avoid duplicates
+ for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
+ const sp<AudioProfile> &profile = itemAt(profileIndex);
+ if (profile->isValid() && profile == profileToAdd) {
+ // Nothing to do
+ return profileIndex;
+ }
+ }
+ profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
+ return add(profileToAdd);
+ }
+
+ sp<AudioProfile> getFirstValidProfile() const
+ {
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->isValid()) {
+ return itemAt(i);
+ }
+ }
+ return 0;
+ }
+
+ bool hasValidProfile() const { return getFirstValidProfile() != 0; }
+
+ status_t checkExactProfile(uint32_t samplingRate, audio_channel_mask_t channelMask,
+ audio_format_t format) const;
+
+ status_t checkCompatibleProfile(uint32_t &samplingRate, audio_channel_mask_t &channelMask,
+ audio_format_t &format,
+ audio_port_type_t portType,
+ audio_port_role_t portRole) const;
+
+ FormatVector getSupportedFormats() const
+ {
+ FormatVector supportedFormats;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->hasValidFormat()) {
+ supportedFormats.add(itemAt(i)->getFormat());
+ }
+ }
+ return supportedFormats;
+ }
+
+ bool hasDynamicProfile() const
+ {
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->isDynamic()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool hasDynamicFormat() const
+ {
+ return getProfileFor(gDynamicFormat) != 0;
+ }
+
+ bool hasDynamicChannelsFor(audio_format_t format) const
+ {
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicChannels()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool hasDynamicRateFor(audio_format_t format) const
+ {
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicRate()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // One audio profile will be added for each format supported by Audio HAL
+ void setFormats(const FormatVector &formats)
+ {
+ // Only allow to change the format of dynamic profile
+ sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
+ if (dynamicFormatProfile == 0) {
+ return;
+ }
+ for (size_t i = 0; i < formats.size(); i++) {
+ sp<AudioProfile> profile = new AudioProfile(formats[i],
+ dynamicFormatProfile->getChannels(),
+ dynamicFormatProfile->getSampleRates());
+ profile->setDynamicFormat(true);
+ profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
+ profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
+ add(profile);
+ }
+ }
+
+ void clearProfiles()
+ {
+ for (size_t i = size(); i != 0; ) {
+ sp<AudioProfile> profile = itemAt(--i);
+ if (profile->isDynamicFormat() && profile->hasValidFormat()) {
+ removeAt(i);
+ continue;
+ }
+ profile->clear();
+ }
+ }
+
+ void dump(int fd, int spaces) const
+ {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "%*s- Profiles:\n", spaces, "");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "%*sProfile %zu:", spaces + 4, "", i);
+ write(fd, buffer, strlen(buffer));
+ itemAt(i)->dump(fd, spaces + 8);
+ }
+ }
+
+private:
+ void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format)
+ {
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicRate()) {
+ if (profile->hasValidRates()) {
+ // Need to create a new profile with same format
+ sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
+ sampleRates);
+ profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+ add(profileToAdd);
+ } else {
+ profile->setSampleRates(sampleRates);
+ }
+ return;
+ }
+ }
+ }
+
+ void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
+ {
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicChannels()) {
+ if (profile->hasValidChannels()) {
+ // Need to create a new profile with same format
+ sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
+ profile->getSampleRates());
+ profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+ add(profileToAdd);
+ } else {
+ profile->setChannels(channelMasks);
+ }
+ return;
+ }
+ }
+ }
+
+ sp<AudioProfile> getProfileFor(audio_format_t format) const
+ {
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->getFormat() == format) {
+ return itemAt(i);
+ }
+ }
+ return 0;
+ }
+
+ static int compareFormats(const sp<AudioProfile> *profile1, const sp<AudioProfile> *profile2);
+};
+
+bool operator == (const AudioProfile &left, const AudioProfile &right);
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
new file mode 100644
index 0000000..67e197f
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AudioCollections.h"
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+
+namespace android
+{
+
+class AudioPort;
+class DeviceDescriptor;
+
+typedef enum {
+ AUDIO_ROUTE_MUX = 0,
+ AUDIO_ROUTE_MIX = 1
+} audio_route_type_t;
+
+class AudioRoute : public virtual RefBase
+{
+public:
+ AudioRoute(audio_route_type_t type) : mType(type) {}
+
+ void setSources(const AudioPortVector &sources) { mSources = sources; }
+ const AudioPortVector &getSources() const { return mSources; }
+
+ void setSink(const sp<AudioPort> &sink) { mSink = sink; }
+ const sp<AudioPort> &getSink() const { return mSink; }
+
+ audio_route_type_t getType() const { return mType; }
+
+ void dump(int fd, int spaces) const;
+
+private:
+ AudioPortVector mSources;
+ sp<AudioPort> mSink;
+ audio_route_type_t mType;
+
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
new file mode 100644
index 0000000..576822c
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <media/AudioPolicy.h>
+
+namespace android {
+
+class AudioPolicyClientInterface;
+
+class AudioSession : public RefBase
+{
+public:
+ AudioSession(audio_session_t session,
+ audio_source_t inputSource,
+ audio_format_t format,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags,
+ uid_t uid,
+ bool isSoundTrigger,
+ AudioMix* policyMix,
+ AudioPolicyClientInterface *clientInterface);
+
+ 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_format_t format() const { return mFormat; }
+ uint32_t sampleRate() const { return mSampleRate; }
+ audio_channel_mask_t channelMask() const { return mChannelMask; }
+ audio_input_flags_t flags() const { return mFlags; }
+ uid_t uid() const { return mUid; }
+ bool matches(const sp<AudioSession> &other) const;
+ bool isSoundTrigger() const { return mIsSoundTrigger; }
+ uint32_t openCount() const { return mOpenCount; } ;
+ uint32_t activeCount() const { return mActiveCount; } ;
+
+ uint32_t changeOpenCount(int delta);
+ uint32_t changeActiveCount(int delta);
+
+private:
+ const audio_session_t mSession;
+ const audio_source_t mInputSource;
+ const audio_format_t mFormat;
+ const uint32_t mSampleRate;
+ const audio_channel_mask_t mChannelMask;
+ const audio_input_flags_t mFlags;
+ const uid_t mUid;
+ bool mIsSoundTrigger;
+ uint32_t mOpenCount;
+ uint32_t mActiveCount;
+ AudioMix* mPolicyMix; // non NULL when used by a dynamic policy
+ AudioPolicyClientInterface* mClientInterface;
+};
+
+class AudioSessionCollection :
+ public DefaultKeyedVector<audio_session_t, sp<AudioSession> >
+{
+public:
+ status_t addSession(audio_session_t session,
+ const sp<AudioSession>& audioSession);
+
+ status_t removeSession(audio_session_t session);
+
+ uint32_t getOpenCount() const;
+
+ AudioSessionCollection getActiveSessions() const;
+ bool hasActiveSession() const;
+ bool isSourceActive(audio_source_t source) const;
+
+ status_t dump(int fd, int spaces) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
new file mode 100644
index 0000000..7e1e24d
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <RoutingStrategy.h>
+#include <AudioPatch.h>
+
+namespace android {
+
+class SwAudioOutputDescriptor;
+class HwAudioOutputDescriptor;
+class DeviceDescriptor;
+
+class AudioSourceDescriptor: public RefBase
+{
+public:
+ AudioSourceDescriptor(const sp<DeviceDescriptor> device, const audio_attributes_t *attributes,
+ uid_t uid) :
+ mDevice(device), mAttributes(*attributes), mUid(uid) {}
+ virtual ~AudioSourceDescriptor() {}
+
+ audio_patch_handle_t getHandle() const { return mPatchDesc->mHandle; }
+
+ status_t dump(int fd);
+
+ const sp<DeviceDescriptor> mDevice;
+ const audio_attributes_t mAttributes;
+ uid_t mUid;
+ sp<AudioPatch> mPatchDesc;
+ wp<SwAudioOutputDescriptor> mSwOutput;
+ wp<HwAudioOutputDescriptor> mHwOutput;
+};
+
+class AudioSourceCollection :
+ public DefaultKeyedVector< audio_patch_handle_t, sp<AudioSourceDescriptor> >
+{
+public:
+ status_t dump(int fd) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
index 78d2cdf..ee95ceb 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
@@ -16,6 +16,7 @@
#pragma once
+#include "AudioPolicyConfig.h"
#include "DeviceDescriptor.h"
#include "HwModule.h"
#include "audio_policy_conf.h"
@@ -33,243 +34,26 @@
// Definitions for audio_policy.conf file parsing
// ----------------------------------------------------------------------------
-struct StringToEnum {
- const char *name;
- uint32_t value;
-};
-
-// TODO: move to a separate file. Should be in sync with audio.h.
-#define STRING_TO_ENUM(string) { #string, (uint32_t)string } // uint32_t cast removes warning
-#define NAME_TO_ENUM(name, value) { name, value }
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
-const StringToEnum sDeviceTypeToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_EARPIECE),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER_SAFE),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_SCO),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_HDMI),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_USB),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_TELEPHONY_TX),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_LINE),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_HDMI_ARC),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPDIF),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_FM),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_LINE),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_IP),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_AMBIENT),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_ALL_SCO),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_HDMI),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_TELEPHONY_RX),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_FM_TUNER),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_TV_TUNER),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_LINE),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_SPDIF),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_LOOPBACK),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_IP),
-};
-
-const StringToEnum sDeviceNameToEnumTable[] = {
- NAME_TO_ENUM("Earpiece", AUDIO_DEVICE_OUT_EARPIECE),
- NAME_TO_ENUM("Speaker", AUDIO_DEVICE_OUT_SPEAKER),
- NAME_TO_ENUM("Speaker Protected", AUDIO_DEVICE_OUT_SPEAKER_SAFE),
- NAME_TO_ENUM("Wired Headset", AUDIO_DEVICE_OUT_WIRED_HEADSET),
- NAME_TO_ENUM("Wired Headphones", AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
- NAME_TO_ENUM("BT SCO", AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
- NAME_TO_ENUM("BT SCO Headset", AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
- NAME_TO_ENUM("BT SCO Car Kit", AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
- NAME_TO_ENUM("", AUDIO_DEVICE_OUT_ALL_SCO),
- NAME_TO_ENUM("BT A2DP Out", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
- NAME_TO_ENUM("BT A2DP Headphones", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
- NAME_TO_ENUM("BT A2DP Speaker", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
- NAME_TO_ENUM("", AUDIO_DEVICE_OUT_ALL_A2DP),
- NAME_TO_ENUM("HDMI Out", AUDIO_DEVICE_OUT_AUX_DIGITAL),
- NAME_TO_ENUM("HDMI Out", AUDIO_DEVICE_OUT_HDMI),
- NAME_TO_ENUM("Analog Dock Out", AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
- NAME_TO_ENUM("Digital Dock Out", AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
- NAME_TO_ENUM("USB Host Out", AUDIO_DEVICE_OUT_USB_ACCESSORY),
- NAME_TO_ENUM("USB Device Out", AUDIO_DEVICE_OUT_USB_DEVICE),
- NAME_TO_ENUM("", AUDIO_DEVICE_OUT_ALL_USB),
- NAME_TO_ENUM("Reroute Submix Out", AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
- NAME_TO_ENUM("Telephony Tx", AUDIO_DEVICE_OUT_TELEPHONY_TX),
- NAME_TO_ENUM("Line Out", AUDIO_DEVICE_OUT_LINE),
- NAME_TO_ENUM("HDMI ARC Out", AUDIO_DEVICE_OUT_HDMI_ARC),
- NAME_TO_ENUM("S/PDIF Out", AUDIO_DEVICE_OUT_SPDIF),
- NAME_TO_ENUM("FM transceiver Out", AUDIO_DEVICE_OUT_FM),
- NAME_TO_ENUM("Aux Line Out", AUDIO_DEVICE_OUT_AUX_LINE),
- NAME_TO_ENUM("IP Out", AUDIO_DEVICE_OUT_IP),
- NAME_TO_ENUM("Ambient Mic", AUDIO_DEVICE_IN_AMBIENT),
- NAME_TO_ENUM("Built-In Mic", AUDIO_DEVICE_IN_BUILTIN_MIC),
- NAME_TO_ENUM("BT SCO Headset Mic", AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
- NAME_TO_ENUM("", AUDIO_DEVICE_IN_ALL_SCO),
- NAME_TO_ENUM("Wired Headset Mic", AUDIO_DEVICE_IN_WIRED_HEADSET),
- NAME_TO_ENUM("HDMI In", AUDIO_DEVICE_IN_AUX_DIGITAL),
- NAME_TO_ENUM("HDMI In", AUDIO_DEVICE_IN_HDMI),
- NAME_TO_ENUM("Telephony Rx", AUDIO_DEVICE_IN_TELEPHONY_RX),
- NAME_TO_ENUM("Telephony Rx", AUDIO_DEVICE_IN_VOICE_CALL),
- NAME_TO_ENUM("Built-In Back Mic", AUDIO_DEVICE_IN_BACK_MIC),
- NAME_TO_ENUM("Reroute Submix In", AUDIO_DEVICE_IN_REMOTE_SUBMIX),
- NAME_TO_ENUM("Analog Dock In", AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
- NAME_TO_ENUM("Digital Dock In", AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
- NAME_TO_ENUM("USB Host In", AUDIO_DEVICE_IN_USB_ACCESSORY),
- NAME_TO_ENUM("USB Device In", AUDIO_DEVICE_IN_USB_DEVICE),
- NAME_TO_ENUM("FM Tuner In", AUDIO_DEVICE_IN_FM_TUNER),
- NAME_TO_ENUM("TV Tuner In", AUDIO_DEVICE_IN_TV_TUNER),
- NAME_TO_ENUM("Line In", AUDIO_DEVICE_IN_LINE),
- NAME_TO_ENUM("S/PDIF In", AUDIO_DEVICE_IN_SPDIF),
- NAME_TO_ENUM("BT A2DP In", AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
- NAME_TO_ENUM("Loopback In", AUDIO_DEVICE_IN_LOOPBACK),
- NAME_TO_ENUM("IP In", AUDIO_DEVICE_IN_IP),
-};
-
-const StringToEnum sOutputFlagNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_TTS),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_RAW),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_SYNC),
-};
-
-const StringToEnum sInputFlagNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_INPUT_FLAG_FAST),
- STRING_TO_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
- STRING_TO_ENUM(AUDIO_INPUT_FLAG_RAW),
- STRING_TO_ENUM(AUDIO_INPUT_FLAG_SYNC),
-};
-
-const StringToEnum sFormatNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
- STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
- STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
- STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
- STRING_TO_ENUM(AUDIO_FORMAT_PCM_FLOAT),
- STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
- STRING_TO_ENUM(AUDIO_FORMAT_MP3),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_MAIN),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_LC),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_SSR),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_LTP),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_HE_V1),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_SCALABLE),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_ERLC),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_LD),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_HE_V2),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_ELD),
- STRING_TO_ENUM(AUDIO_FORMAT_VORBIS),
- STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V1),
- STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V2),
- STRING_TO_ENUM(AUDIO_FORMAT_OPUS),
- STRING_TO_ENUM(AUDIO_FORMAT_AC3),
- STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
- STRING_TO_ENUM(AUDIO_FORMAT_DTS),
- STRING_TO_ENUM(AUDIO_FORMAT_DTS_HD),
-};
-
-const StringToEnum sOutChannelsNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_CHANNEL_OUT_MONO),
- STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
- STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD),
- STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
- STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
-};
-
-const StringToEnum sInChannelsNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
- STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
- STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
-};
-
-const StringToEnum sIndexChannelsNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_1),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_2),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_3),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_4),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_5),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_6),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_7),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_8),
-};
-
-const StringToEnum sGainModeNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_GAIN_MODE_JOINT),
- STRING_TO_ENUM(AUDIO_GAIN_MODE_CHANNELS),
- STRING_TO_ENUM(AUDIO_GAIN_MODE_RAMP),
-};
-
class ConfigParsingUtils
{
public:
- static uint32_t stringToEnum(const struct StringToEnum *table,
- size_t size,
- const char *name);
- static const char *enumToString(const struct StringToEnum *table,
- size_t size,
- uint32_t value);
- static bool stringToBool(const char *value);
- static uint32_t parseOutputFlagNames(char *name);
- static uint32_t parseInputFlagNames(char *name);
- static audio_devices_t parseDeviceNames(char *name);
-
- static void loadHwModules(cnode *root, HwModuleCollection &hwModules,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnabled);
-
- static void loadGlobalConfig(cnode *root, const sp<HwModule>& module,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnabled);
-
- static status_t loadAudioPolicyConfig(const char *path,
- HwModuleCollection &hwModules,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnabled);
+ static status_t loadConfig(const char *path, AudioPolicyConfig &config);
private:
- static void loadHwModule(cnode *root, HwModuleCollection &hwModules,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnabled);
+ static void loadAudioPortGain(cnode *root, AudioPort &audioPort, int index);
+ static void loadAudioPortGains(cnode *root, AudioPort &audioPort);
+ static void loadDeviceDescriptorGains(cnode *root, sp<DeviceDescriptor> &deviceDesc);
+ static status_t loadHwModuleDevice(cnode *root, DeviceVector &devices);
+ static status_t loadHwModuleProfile(cnode *root, sp<HwModule> &module, audio_port_role_t role);
+ static void loadDevicesFromTag(const char *tag, DeviceVector &devices,
+ const DeviceVector &declaredDevices);
+ static void loadHwModules(cnode *root, HwModuleCollection &hwModules,
+ AudioPolicyConfig &config);
+ static void loadGlobalConfig(cnode *root, AudioPolicyConfig &config,
+ const sp<HwModule> &primaryModule);
+ static void loadModuleGlobalConfig(cnode *root, const sp<HwModule> &module,
+ AudioPolicyConfig &config);
+ static status_t loadHwModule(cnode *root, sp<HwModule> &module, AudioPolicyConfig &config);
};
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index c42ece6..54fcd0b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -29,10 +29,15 @@
class DeviceDescriptor : public AudioPort, public AudioPortConfig
{
public:
- DeviceDescriptor(audio_devices_t type);
+ // Note that empty name refers by convention to a generic device.
+ DeviceDescriptor(audio_devices_t type, const String8 &tagName = String8(""));
virtual ~DeviceDescriptor() {}
+ virtual const String8 getTagName() const { return mTagName; }
+
+ audio_devices_t type() const { return mDeviceType; }
+
bool equals(const sp<DeviceDescriptor>& other) const;
// AudioPortConfig
@@ -42,50 +47,46 @@
// AudioPort
virtual void attach(const sp<HwModule>& module);
- virtual void loadGains(cnode *root);
virtual void toAudioPort(struct audio_port *port) const;
virtual void importAudioPort(const sp<AudioPort> port);
audio_port_handle_t getId() const;
- audio_devices_t type() const { return mDeviceType; }
- status_t dump(int fd, int spaces, int index) const;
+ status_t dump(int fd, int spaces, int index, bool verbose = true) const;
void log() const;
- String8 mTag;
String8 mAddress;
private:
+ String8 mTagName; // Unique human readable identifier for a device port found in conf file.
audio_devices_t mDeviceType;
audio_port_handle_t mId;
friend class DeviceVector;
};
-class DeviceVector : public SortedVector< sp<DeviceDescriptor> >
+class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
{
public:
DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
ssize_t add(const sp<DeviceDescriptor>& item);
+ void add(const DeviceVector &devices);
ssize_t remove(const sp<DeviceDescriptor>& item);
ssize_t indexOf(const sp<DeviceDescriptor>& item) const;
audio_devices_t types() const { return mDeviceTypes; }
- void loadDevicesFromType(audio_devices_t types);
- void loadDevicesFromTag(char *tag, const DeviceVector& declaredDevices);
-
sp<DeviceDescriptor> getDevice(audio_devices_t type, String8 address) const;
DeviceVector getDevicesFromType(audio_devices_t types) const;
sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
- sp<DeviceDescriptor> getDeviceFromTag(const String8& tag) const;
+ sp<DeviceDescriptor> getDeviceFromTagName(const String8 &tagName) const;
DeviceVector getDevicesFromTypeAddr(audio_devices_t type, String8 address) const;
audio_devices_t getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
audio_policy_dev_state_t getDeviceConnectionState(const sp<DeviceDescriptor> &devDesc) const;
- status_t dump(int fd, const String8 &direction) const;
+ status_t dump(int fd, const String8 &tag, int spaces = 0, bool verbose = true) const;
private:
void refreshTypes();
diff --git a/services/audiopolicy/enginedefault/src/Gains.h b/services/audiopolicy/common/managerdefinitions/include/Gains.h
similarity index 87%
rename from services/audiopolicy/enginedefault/src/Gains.h
rename to services/audiopolicy/common/managerdefinitions/include/Gains.h
index 7620b7d..34afc8c 100644
--- a/services/audiopolicy/enginedefault/src/Gains.h
+++ b/services/audiopolicy/common/managerdefinitions/include/Gains.h
@@ -29,12 +29,7 @@
class Gains
{
public :
- static float volIndexToAmpl(Volume::device_category deviceCategory,
- const StreamDescriptor& streamDesc,
- int indexInUi);
-
- static float volIndexToDb(Volume::device_category deviceCategory,
- const StreamDescriptor& streamDesc,
+ static float volIndexToDb(const VolumeCurvePoint *point, int indexMin, int indexMax,
int indexInUi);
// default volume curve
@@ -58,7 +53,7 @@
static const VolumeCurvePoint sSilentVolumeCurve[Volume::VOLCNT];
static const VolumeCurvePoint sFullScaleVolumeCurve[Volume::VOLCNT];
// default volume curves per stream and device category. See initializeVolumeCurves()
- static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][Volume::DEVICE_CATEGORY_CNT];
+ static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][DEVICE_CATEGORY_CNT];
};
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index 92c3ea2..93d03e6 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -17,26 +17,54 @@
#pragma once
#include "DeviceDescriptor.h"
+#include "AudioRoute.h"
+#include <hardware/audio.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/Errors.h>
#include <utils/Vector.h>
#include <system/audio.h>
#include <cutils/config_utils.h>
+#include <string>
namespace android {
class IOProfile;
+class InputProfile;
+class OutputProfile;
+
+typedef Vector<sp<IOProfile> > InputProfileCollection;
+typedef Vector<sp<IOProfile> > OutputProfileCollection;
+typedef Vector<sp<IOProfile> > IOProfileCollection;
class HwModule : public RefBase
{
public:
- HwModule(const char *name);
+ HwModule(const char *name, uint32_t halVersion = AUDIO_DEVICE_API_VERSION_MIN);
~HwModule();
- status_t loadOutput(cnode *root);
- status_t loadInput(cnode *root);
- status_t loadDevice(cnode *root);
+ const char *getName() const { return mName.string(); }
+
+
+ const DeviceVector &getDeclaredDevices() const { return mDeclaredDevices; }
+ void setDeclaredDevices(const DeviceVector &devices);
+
+ const InputProfileCollection &getInputProfiles() const { return mInputProfiles; }
+
+ const OutputProfileCollection &getOutputProfiles() const { return mOutputProfiles; }
+
+ void setProfiles(const IOProfileCollection &profiles);
+
+ void setHalVersion(uint32_t halVersion) { mHalVersion = halVersion; }
+ uint32_t getHalVersion() const { return mHalVersion; }
+
+ sp<DeviceDescriptor> getRouteSinkDevice(const sp<AudioRoute> &route) const;
+ DeviceVector getRouteSourceDevices(const sp<AudioRoute> &route) const;
+ void setRoutes(const AudioRouteVector &routes);
+
+ status_t addOutputProfile(const sp<IOProfile> &profile);
+ status_t addInputProfile(const sp<IOProfile> &profile);
+ status_t addProfile(const sp<IOProfile> &profile);
status_t addOutputProfile(String8 name, const audio_config_t *config,
audio_devices_t device, String8 address);
@@ -47,26 +75,38 @@
audio_module_handle_t getHandle() const { return mHandle; }
+ sp<AudioPort> findPortByTagName(const String8 &tagName) const
+ {
+ return mPorts.findByTagName(tagName);
+ }
+
+ // TODO remove from here (split serialization)
void dump(int fd);
- const char *const mName; // base name of the audio HW module (primary, a2dp ...)
- uint32_t mHalVersion; // audio HAL API version
- audio_module_handle_t mHandle;
- Vector < sp<IOProfile> > mOutputProfiles; // output profiles exposed by this module
- Vector < sp<IOProfile> > mInputProfiles; // input profiles exposed by this module
- DeviceVector mDeclaredDevices; // devices declared in audio_policy.conf
+ const String8 mName; // base name of the audio HW module (primary, a2dp ...)
+ audio_module_handle_t mHandle;
+ OutputProfileCollection mOutputProfiles; // output profiles exposed by this module
+ InputProfileCollection mInputProfiles; // input profiles exposed by this module
+
+private:
+ void refreshSupportedDevices();
+
+ uint32_t mHalVersion; // audio HAL API version
+ DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
+ AudioRouteVector mRoutes;
+ AudioPortVector mPorts;
};
-class HwModuleCollection : public Vector< sp<HwModule> >
+class HwModuleCollection : public Vector<sp<HwModule> >
{
public:
sp<HwModule> getModuleFromName(const char *name) const;
- sp <HwModule> getModuleForDevice(audio_devices_t device) const;
+ sp<HwModule> getModuleForDevice(audio_devices_t device) const;
- sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
- const char *device_address,
- const char *device_name) const;
+ sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
+ const char *device_address,
+ const char *device_name) const;
status_t dump(int fd) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index ab6fcc1..eae9586 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -33,8 +33,11 @@
class IOProfile : public AudioPort
{
public:
- IOProfile(const String8& name, audio_port_role_t role);
- virtual ~IOProfile();
+ IOProfile(const String8 &name, audio_port_role_t role)
+ : AudioPort(name, AUDIO_PORT_TYPE_MIX, role) {}
+
+ // For a Profile aka MixPort, tag name and name are equivalent.
+ virtual const String8 getTagName() const { return getName(); }
// This method is used for both output and input.
// If parameter updatedSamplingRate is non-NULL, it is assigned the actual sample rate.
@@ -53,8 +56,67 @@
void dump(int fd);
void log();
- DeviceVector mSupportedDevices; // supported devices
- // (devices this output can be routed to)
+ bool hasSupportedDevices() const { return !mSupportedDevices.isEmpty(); }
+
+ bool supportDevice(audio_devices_t device) const
+ {
+ if (audio_is_output_devices(device)) {
+ return mSupportedDevices.types() & device;
+ }
+ return mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN);
+ }
+
+ bool supportDeviceAddress(const String8 &address) const
+ {
+ return mSupportedDevices[0]->mAddress == address;
+ }
+
+ // chose first device present in mSupportedDevices also part of deviceType
+ audio_devices_t getSupportedDeviceForType(audio_devices_t deviceType) const
+ {
+ for (size_t k = 0; k < mSupportedDevices.size(); k++) {
+ audio_devices_t profileType = mSupportedDevices[k]->type();
+ if (profileType & deviceType) {
+ return profileType;
+ }
+ }
+ return AUDIO_DEVICE_NONE;
+ }
+
+ audio_devices_t getSupportedDevicesType() const { return mSupportedDevices.types(); }
+
+ void clearSupportedDevices() { mSupportedDevices.clear(); }
+ void addSupportedDevice(const sp<DeviceDescriptor> &device)
+ {
+ mSupportedDevices.add(device);
+ }
+
+ void setSupportedDevices(const DeviceVector &devices)
+ {
+ mSupportedDevices = devices;
+ }
+
+ sp<DeviceDescriptor> getSupportedDeviceByAddress(audio_devices_t type, String8 address) const
+ {
+ return mSupportedDevices.getDevice(type, address);
+ }
+
+ const DeviceVector &getSupportedDevices() const { return mSupportedDevices; }
+
+private:
+ DeviceVector mSupportedDevices; // supported devices: this input/output can be routed from/to
+};
+
+class InputProfile : public IOProfile
+{
+public:
+ InputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SINK) {}
+};
+
+class OutputProfile : public IOProfile
+{
+public:
+ OutputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SOURCE) {}
};
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
new file mode 100644
index 0000000..8dc3eda
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+#include <Volume.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class IVolumeCurvesCollection
+{
+public:
+ virtual void clearCurrentVolumeIndex(audio_stream_type_t stream) = 0;
+ virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device,
+ int index) = 0;
+ virtual bool canBeMuted(audio_stream_type_t stream) = 0;
+ virtual int getVolumeIndexMin(audio_stream_type_t stream) const = 0;
+ virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device) = 0;
+ virtual int getVolumeIndexMax(audio_stream_type_t stream) const = 0;
+ virtual float volIndexToDb(audio_stream_type_t stream, device_category device,
+ int indexInUi) const = 0;
+ virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax) = 0;
+
+ virtual void initializeVolumeCurves(bool /*isSpeakerDrcEnabled*/) {}
+ virtual void switchVolumeCurve(audio_stream_type_t src, audio_stream_type_t dst) = 0;
+ virtual void restoreOriginVolumeCurve(audio_stream_type_t stream)
+ {
+ switchVolumeCurve(stream, stream);
+ }
+
+ virtual status_t dump(int fd) const = 0;
+
+protected:
+ virtual ~IVolumeCurvesCollection() {}
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/Serializer.h b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
new file mode 100644
index 0000000..078b582
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
@@ -0,0 +1,237 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AudioPolicyConfig.h"
+#include <utils/StrongPointer.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <string>
+#include <sstream>
+#include <fstream>
+
+struct _xmlNode;
+struct _xmlDoc;
+
+namespace android {
+
+struct AudioGainTraits
+{
+ static const char *const tag;
+ static const char *const collectionTag;
+
+ struct Attributes
+ {
+ static const char mode[]; /**< gain modes supported, e.g. AUDIO_GAIN_MODE_CHANNELS. */
+ /** controlled channels, needed if mode AUDIO_GAIN_MODE_CHANNELS. */
+ static const char channelMask[];
+ static const char minValueMB[]; /**< min value in millibel. */
+ static const char maxValueMB[]; /**< max value in millibel. */
+ static const char defaultValueMB[]; /**< default value in millibel. */
+ static const char stepValueMB[]; /**< step value in millibel. */
+ static const char minRampMs[]; /**< needed if mode AUDIO_GAIN_MODE_RAMP. */
+ static const char maxRampMs[]; /**< .needed if mode AUDIO_GAIN_MODE_RAMP */
+ };
+
+ typedef AudioGain Element;
+ typedef sp<Element> PtrElement;
+ typedef AudioGainCollection Collection;
+ typedef void *PtrSerializingCtx;
+
+ static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+ PtrSerializingCtx serializingContext);
+
+ // Gain has no child
+};
+
+// A profile section contains a name, one audio format and the list of supported sampling rates
+// and channel masks for this format
+struct AudioProfileTraits
+{
+ static const char *const tag;
+ static const char *const collectionTag;
+
+ struct Attributes
+ {
+ static const char name[];
+ static const char samplingRates[];
+ static const char format[];
+ static const char channelMasks[];
+ };
+
+ typedef AudioProfile Element;
+ typedef sp<AudioProfile> PtrElement;
+ typedef AudioProfileVector Collection;
+ typedef void *PtrSerializingCtx;
+
+ static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+ PtrSerializingCtx serializingContext);
+};
+
+struct MixPortTraits
+{
+ static const char *const tag;
+ static const char *const collectionTag;
+
+ struct Attributes
+ {
+ static const char name[];
+ static const char role[];
+ static const char flags[];
+ };
+
+ typedef IOProfile Element;
+ typedef sp<Element> PtrElement;
+ typedef IOProfileCollection Collection;
+ typedef void *PtrSerializingCtx;
+
+ static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+ PtrSerializingCtx serializingContext);
+
+ // Children are: GainTraits
+};
+
+struct DevicePortTraits
+{
+ static const char *const tag;
+ static const char *const collectionTag;
+
+ struct Attributes
+ {
+ static const char tagName[]; /**< <device tag name>: any string without space. */
+ static const char type[]; /**< <device type>. */
+ static const char role[]; /**< <device role: sink or source>. */
+ static const char roleSource[]; /**< <attribute role source value>. */
+ static const char address[]; /**< optional: device address, char string less than 64. */
+ };
+ typedef DeviceDescriptor Element;
+ typedef sp<DeviceDescriptor> PtrElement;
+ typedef DeviceVector Collection;
+ typedef void *PtrSerializingCtx;
+
+ static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+ PtrSerializingCtx serializingContext);
+ // Children are: GainTraits (optionnal)
+};
+
+struct RouteTraits
+{
+ static const char *const tag;
+ static const char *const collectionTag;
+
+ struct Attributes
+ {
+ static const char type[]; /**< <route type>: mix or mux. */
+ static const char typeMix[]; /**< type attribute mix value. */
+ static const char sink[]; /**< <sink: involved in this route>. */
+ static const char sources[]; /**< sources: all source that can be involved in this route. */
+ };
+ typedef AudioRoute Element;
+ typedef sp<AudioRoute> PtrElement;
+ typedef AudioRouteVector Collection;
+ typedef HwModule *PtrSerializingCtx;
+
+ static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+ PtrSerializingCtx ctx);
+};
+
+struct ModuleTraits
+{
+ static const char *const tag;
+ static const char *const collectionTag;
+
+ static const char *const childAttachedDevicesTag;
+ static const char *const childAttachedDeviceTag;
+ static const char *const childDefaultOutputDeviceTag;
+
+ struct Attributes
+ {
+ static const char name[];
+ static const char version[];
+ };
+
+ typedef HwModule Element;
+ typedef sp<Element> PtrElement;
+ typedef HwModuleCollection Collection;
+ typedef AudioPolicyConfig *PtrSerializingCtx;
+
+ static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+ PtrSerializingCtx serializingContext);
+
+ // Children are: mixPortTraits, devicePortTraits and routeTraits
+ // Need to call deserialize on each child
+};
+
+struct GlobalConfigTraits
+{
+ static const char *const tag;
+
+ struct Attributes
+ {
+ static const char speakerDrcEnabled[];
+ };
+
+ static status_t deserialize(const _xmlNode *root, AudioPolicyConfig &config);
+};
+
+struct VolumeTraits
+{
+ static const char *const tag;
+ static const char *const collectionTag;
+ static const char *const volumePointTag;
+
+ struct Attributes
+ {
+ static const char stream[];
+ static const char deviceCategory[];
+ static const char reference[];
+ };
+
+ typedef VolumeCurve Element;
+ typedef sp<VolumeCurve> PtrElement;
+ typedef VolumeCurvesCollection Collection;
+ typedef void *PtrSerializingCtx;
+
+ static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+ PtrSerializingCtx serializingContext);
+
+ // No Child
+};
+
+class PolicySerializer
+{
+private:
+ static const char *const rootName;
+
+ static const char *const versionAttribute;
+ static const uint32_t gMajor; /**< the major number of the policy xml format version. */
+ static const uint32_t gMinor; /**< the minor number of the policy xml format version. */
+
+public:
+ PolicySerializer();
+ status_t deserialize(const char *str, AudioPolicyConfig &config);
+
+private:
+ typedef AudioPolicyConfig Element;
+
+ std::string mRootElementName;
+ std::string mVersion;
+
+ // Children are: ModulesTraits, VolumeTraits
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
index 84db5ab..af178f9 100644
--- a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
@@ -16,7 +16,7 @@
#pragma once
-#include <Volume.h>
+#include "IVolumeCurvesCollection.h"
#include <utils/KeyedVector.h>
#include <utils/StrongPointer.h>
#include <utils/SortedVector.h>
@@ -41,14 +41,14 @@
void dump(int fd) const;
- void setVolumeCurvePoint(Volume::device_category deviceCategory, const VolumeCurvePoint *point);
- const VolumeCurvePoint *getVolumeCurvePoint(Volume::device_category deviceCategory) const
+ void setVolumeCurvePoint(device_category deviceCategory, const VolumeCurvePoint *point);
+ const VolumeCurvePoint *getVolumeCurvePoint(device_category deviceCategory) const
{
return mVolumeCurve[deviceCategory];
}
private:
- const VolumeCurvePoint *mVolumeCurve[Volume::DEVICE_CATEGORY_CNT];
+ const VolumeCurvePoint *mVolumeCurve[DEVICE_CATEGORY_CNT];
KeyedVector<audio_devices_t, int> mIndexCur; /**< current volume index per device. */
int mIndexMin; /**< min volume index. */
int mIndexMax; /**< max volume index. */
@@ -58,28 +58,43 @@
/**
* stream descriptors collection for volume control
*/
-class StreamDescriptorCollection : public DefaultKeyedVector<audio_stream_type_t, StreamDescriptor>
+class StreamDescriptorCollection : public DefaultKeyedVector<audio_stream_type_t, StreamDescriptor>,
+ public IVolumeCurvesCollection
{
public:
StreamDescriptorCollection();
- void clearCurrentVolumeIndex(audio_stream_type_t stream);
- void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index);
+ virtual void clearCurrentVolumeIndex(audio_stream_type_t stream);
+ virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device,
+ int index);
+ virtual bool canBeMuted(audio_stream_type_t stream);
+ virtual int getVolumeIndexMin(audio_stream_type_t stream) const
+ {
+ return valueFor(stream).getVolumeIndexMin();
+ }
+ virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device)
+ {
+ return valueFor(stream).getVolumeIndex(device);
+ }
+ virtual int getVolumeIndexMax(audio_stream_type_t stream) const
+ {
+ return valueFor(stream).getVolumeIndexMax();
+ }
+ virtual float volIndexToDb(audio_stream_type_t stream, device_category device,
+ int indexInUi) const;
+ virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
+ virtual void initializeVolumeCurves(bool isSpeakerDrcEnabled);
+ virtual void switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst);
- bool canBeMuted(audio_stream_type_t stream);
+ virtual status_t dump(int fd) const;
- status_t dump(int fd) const;
-
- void setVolumeCurvePoint(audio_stream_type_t stream,
- Volume::device_category deviceCategory,
+private:
+ void setVolumeCurvePoint(audio_stream_type_t stream, device_category deviceCategory,
const VolumeCurvePoint *point);
-
const VolumeCurvePoint *getVolumeCurvePoint(audio_stream_type_t stream,
- Volume::device_category deviceCategory) const;
-
+ device_category deviceCategory) const;
void setVolumeIndexMin(audio_stream_type_t stream,int volIndexMin);
void setVolumeIndexMax(audio_stream_type_t stream,int volIndexMax);
-
};
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
new file mode 100644
index 0000000..b828f81
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "policy.h"
+#include <Volume.h>
+#include <system/audio.h>
+#include <convert/convert.h>
+#include <utils/Log.h>
+#include <string>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+
+struct SampleRateTraits
+{
+ typedef uint32_t Type;
+ typedef SortedVector<Type> Collection;
+};
+struct DeviceTraits
+{
+ typedef audio_devices_t Type;
+ typedef Vector<Type> Collection;
+};
+struct OutputFlagTraits
+{
+ typedef audio_output_flags_t Type;
+ typedef Vector<Type> Collection;
+};
+struct InputFlagTraits
+{
+ typedef audio_input_flags_t Type;
+ typedef Vector<Type> Collection;
+};
+struct FormatTraits
+{
+ typedef audio_format_t Type;
+ typedef Vector<Type> Collection;
+};
+struct ChannelTraits
+{
+ typedef audio_channel_mask_t Type;
+ typedef SortedVector<Type> Collection;
+};
+struct OutputChannelTraits : public ChannelTraits {};
+struct InputChannelTraits : public ChannelTraits {};
+struct ChannelIndexTraits : public ChannelTraits {};
+struct GainModeTraits
+{
+ typedef audio_gain_mode_t Type;
+ typedef Vector<Type> Collection;
+};
+struct StreamTraits
+{
+ typedef audio_stream_type_t Type;
+ typedef Vector<Type> Collection;
+};
+struct DeviceCategoryTraits
+{
+ typedef device_category Type;
+ typedef Vector<Type> Collection;
+};
+template <typename T>
+struct DefaultTraits
+{
+ typedef T Type;
+ typedef Vector<Type> Collection;
+};
+
+template <class Traits>
+static void collectionFromString(const std::string &str, typename Traits::Collection &collection,
+ const char *del = "|")
+{
+ char *literal = strdup(str.c_str());
+ for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+ typename Traits::Type value;
+ if (utilities::convertTo<std::string, typename Traits::Type >(cstr, value)) {
+ collection.add(value);
+ }
+ }
+ free(literal);
+}
+
+template <class Traits>
+class TypeConverter
+{
+public:
+ static bool toString(const typename Traits::Type &value, std::string &str);
+
+ static bool fromString(const std::string &str, typename Traits::Type &result);
+
+ static void collectionFromString(const std::string &str,
+ typename Traits::Collection &collection,
+ const char *del = "|");
+
+ static uint32_t maskFromString(const std::string &str, const char *del = "|");
+
+protected:
+ struct Table {
+ const char *literal;
+ typename Traits::Type value;
+ };
+
+ static const Table mTable[];
+ static const size_t mSize;
+};
+
+typedef TypeConverter<DeviceTraits> DeviceConverter;
+typedef TypeConverter<OutputFlagTraits> OutputFlagConverter;
+typedef TypeConverter<InputFlagTraits> InputFlagConverter;
+typedef TypeConverter<FormatTraits> FormatConverter;
+typedef TypeConverter<OutputChannelTraits> OutputChannelConverter;
+typedef TypeConverter<InputChannelTraits> InputChannelConverter;
+typedef TypeConverter<ChannelIndexTraits> ChannelIndexConverter;
+typedef TypeConverter<GainModeTraits> GainModeConverter;
+typedef TypeConverter<StreamTraits> StreamTypeConverter;
+typedef TypeConverter<DeviceCategoryTraits> DeviceCategoryConverter;
+
+static SampleRateTraits::Collection samplingRatesFromString(const std::string &samplingRates,
+ const char *del = "|")
+{
+ SampleRateTraits::Collection samplingRateCollection;
+ collectionFromString<SampleRateTraits>(samplingRates, samplingRateCollection, del);
+ return samplingRateCollection;
+}
+
+static FormatTraits::Collection formatsFromString(const std::string &formats, const char *del = "|")
+{
+ FormatTraits::Collection formatCollection;
+ FormatConverter::collectionFromString(formats, formatCollection, del);
+ return formatCollection;
+}
+
+static audio_format_t formatFromString(const std::string &literalFormat)
+{
+ audio_format_t format;
+ if (literalFormat.empty()) {
+ return gDynamicFormat;
+ }
+ FormatConverter::fromString(literalFormat, format);
+ return format;
+}
+
+static audio_channel_mask_t channelMaskFromString(const std::string &literalChannels)
+{
+ audio_channel_mask_t channels;
+ if (!OutputChannelConverter::fromString(literalChannels, channels) ||
+ !InputChannelConverter::fromString(literalChannels, channels)) {
+ return AUDIO_CHANNEL_INVALID;
+ }
+ return channels;
+}
+
+static ChannelTraits::Collection channelMasksFromString(const std::string &channels,
+ const char *del = "|")
+{
+ ChannelTraits::Collection channelMaskCollection;
+ OutputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+ InputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+ ChannelIndexConverter::collectionFromString(channels, channelMaskCollection, del);
+ return channelMaskCollection;
+}
+
+static InputChannelTraits::Collection inputChannelMasksFromString(const std::string &inChannels,
+ const char *del = "|")
+{
+ InputChannelTraits::Collection inputChannelMaskCollection;
+ InputChannelConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
+ ChannelIndexConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
+ return inputChannelMaskCollection;
+}
+
+static OutputChannelTraits::Collection outputChannelMasksFromString(const std::string &outChannels,
+ const char *del = "|")
+{
+ OutputChannelTraits::Collection outputChannelMaskCollection;
+ OutputChannelConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
+ ChannelIndexConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
+ return outputChannelMaskCollection;
+}
+
+}; // namespace android
+
diff --git a/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
new file mode 100644
index 0000000..009a26f
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "IVolumeCurvesCollection.h"
+#include <policy.h>
+#include <hardware/audio.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+#include <string>
+#include <utility>
+
+namespace android {
+
+struct CurvePoint
+{
+ CurvePoint() {}
+ CurvePoint(int index, int attenuationInMb) :
+ mIndex(index), mAttenuationInMb(attenuationInMb) {}
+ uint32_t mIndex;
+ int mAttenuationInMb;
+};
+
+inline bool operator< (const CurvePoint &lhs, const CurvePoint &rhs)
+{
+ return lhs.mIndex < rhs.mIndex;
+}
+
+// A volume curve for a given use case and device cateory
+// It contains of list of points of this cuive expressing the atteunation in Millibels for
+// a given volume index from 0 to 100
+class VolumeCurve : public RefBase
+{
+public:
+ VolumeCurve(device_category device, audio_stream_type_t stream) :
+ mDeviceCategory(device), mStreamType(stream) {}
+
+ device_category getDeviceCategory() const { return mDeviceCategory; }
+ audio_stream_type_t getStreamType() const { return mStreamType; }
+
+ void add(const CurvePoint &point) { mCurvePoints.add(point); }
+
+ float volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const;
+
+ void dump(int fd) const;
+
+private:
+ SortedVector<CurvePoint> mCurvePoints;
+ device_category mDeviceCategory;
+ audio_stream_type_t mStreamType;
+};
+
+// Volume Curves for a given use case indexed by device category
+class VolumeCurvesForStream : public KeyedVector<device_category, sp<VolumeCurve> >
+{
+public:
+ VolumeCurvesForStream() : mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
+ {
+ mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0);
+ }
+
+ sp<VolumeCurve> getCurvesFor(device_category device) const
+ {
+ if (indexOfKey(device) < 0) {
+ return 0;
+ }
+ return valueFor(device);
+ }
+
+ int getVolumeIndex(audio_devices_t device) const
+ {
+ device = Volume::getDeviceForVolume(device);
+ // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT
+ if (mIndexCur.indexOfKey(device) < 0) {
+ device = AUDIO_DEVICE_OUT_DEFAULT;
+ }
+ return mIndexCur.valueFor(device);
+ }
+
+ bool canBeMuted() const { return mCanBeMuted; }
+ void clearCurrentVolumeIndex() { mIndexCur.clear(); }
+ void addCurrentVolumeIndex(audio_devices_t device, int index) { mIndexCur.add(device, index); }
+
+ void setVolumeIndexMin(int volIndexMin) { mIndexMin = volIndexMin; }
+ int getVolumeIndexMin() const { return mIndexMin; }
+
+ void setVolumeIndexMax(int volIndexMax) { mIndexMax = volIndexMax; }
+ int getVolumeIndexMax() const { return mIndexMax; }
+
+ const sp<VolumeCurve> getOriginVolumeCurve(device_category deviceCategory) const
+ {
+ ALOG_ASSERT(mOriginVolumeCurves.indexOfKey(deviceCategory) >= 0, "Invalid device category");
+ return mOriginVolumeCurves.valueFor(deviceCategory);
+ }
+ void setVolumeCurve(device_category deviceCategory, const sp<VolumeCurve> &volumeCurve)
+ {
+ ALOG_ASSERT(indexOfKey(deviceCategory) >= 0, "Invalid device category for Volume Curve");
+ replaceValueFor(deviceCategory, volumeCurve);
+ }
+
+ ssize_t add(const sp<VolumeCurve> &volumeCurve)
+ {
+ device_category deviceCategory = volumeCurve->getDeviceCategory();
+ ssize_t index = indexOfKey(deviceCategory);
+ if (index < 0) {
+ // Keep track of original Volume Curves per device category in order to switch curves.
+ mOriginVolumeCurves.add(deviceCategory, volumeCurve);
+ return KeyedVector::add(deviceCategory, volumeCurve);
+ }
+ return index;
+ }
+
+ float volIndexToDb(device_category deviceCat, int indexInUi) const
+ {
+ return getCurvesFor(deviceCat)->volIndexToDb(indexInUi, mIndexMin, mIndexMax);
+ }
+
+ void dump(int fd, int spaces, bool curvePoints = false) const;
+
+private:
+ KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves;
+ KeyedVector<audio_devices_t, int> mIndexCur; /**< current volume index per device. */
+ int mIndexMin; /**< min volume index. */
+ int mIndexMax; /**< max volume index. */
+ bool mCanBeMuted; /**< true is the stream can be muted. */
+};
+
+// Collection of Volume Curves indexed by use case
+class VolumeCurvesCollection : public KeyedVector<audio_stream_type_t, VolumeCurvesForStream>,
+ public IVolumeCurvesCollection
+{
+public:
+ VolumeCurvesCollection()
+ {
+ // Create an empty collection of curves
+ for (ssize_t i = 0 ; i < AUDIO_STREAM_CNT; i++) {
+ audio_stream_type_t stream = static_cast<audio_stream_type_t>(i);
+ KeyedVector::add(stream, VolumeCurvesForStream());
+ }
+ }
+
+ // Once XML has been parsed, must be call first to sanity check table and initialize indexes
+ virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax)
+ {
+ editValueAt(stream).setVolumeIndexMin(indexMin);
+ editValueAt(stream).setVolumeIndexMax(indexMax);
+ return NO_ERROR;
+ }
+ virtual void clearCurrentVolumeIndex(audio_stream_type_t stream)
+ {
+ editCurvesFor(stream).clearCurrentVolumeIndex();
+ }
+ virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index)
+ {
+ editCurvesFor(stream).addCurrentVolumeIndex(device, index);
+ }
+ virtual bool canBeMuted(audio_stream_type_t stream) { return getCurvesFor(stream).canBeMuted(); }
+
+ virtual int getVolumeIndexMin(audio_stream_type_t stream) const
+ {
+ return getCurvesFor(stream).getVolumeIndexMin();
+ }
+ virtual int getVolumeIndexMax(audio_stream_type_t stream) const
+ {
+ return getCurvesFor(stream).getVolumeIndexMax();
+ }
+ virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device)
+ {
+ return getCurvesFor(stream).getVolumeIndex(device);
+ }
+ virtual void switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst)
+ {
+ const VolumeCurvesForStream &sourceCurves = getCurvesFor(streamSrc);
+ VolumeCurvesForStream &dstCurves = editCurvesFor(streamDst);
+ ALOG_ASSERT(sourceCurves.size() == dstCurves.size(), "device category not aligned");
+ for (size_t index = 0; index < sourceCurves.size(); index++) {
+ device_category cat = sourceCurves.keyAt(index);
+ dstCurves.setVolumeCurve(cat, sourceCurves.getOriginVolumeCurve(cat));
+ }
+ }
+ virtual float volIndexToDb(audio_stream_type_t stream, device_category cat, int indexInUi) const
+ {
+ return getCurvesFor(stream).volIndexToDb(cat, indexInUi);
+ }
+
+ virtual status_t dump(int fd) const;
+
+ ssize_t add(const sp<VolumeCurve> &volumeCurve)
+ {
+ audio_stream_type_t streamType = volumeCurve->getStreamType();
+ return editCurvesFor(streamType).add(volumeCurve);
+ }
+ VolumeCurvesForStream &editCurvesFor(audio_stream_type_t stream)
+ {
+ ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve");
+ return editValueAt(stream);
+ }
+ const VolumeCurvesForStream &getCurvesFor(audio_stream_type_t stream) const
+ {
+ ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve");
+ return valueFor(stream);
+ }
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h b/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
index a393e3b..0a27947 100644
--- a/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
+++ b/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
@@ -47,10 +47,6 @@
#define DEVICES_TAG "devices"
#define FLAGS_TAG "flags"
-#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
- // "formats" in outputs descriptors indicating that supported
- // values should be queried after opening the output.
-
#define APM_DEVICES_TAG "devices"
#define APM_DEVICE_TYPE "type"
#define APM_DEVICE_ADDRESS "address"
@@ -69,3 +65,7 @@
#define GAIN_STEP_VALUE "step_value_mB"
#define GAIN_MIN_RAMP_MS "min_ramp_ms"
#define GAIN_MAX_RAMP_MS "max_ramp_ms"
+
+#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
+ // "formats" in outputs descriptors indicating that supported
+ // values should be queried after opening the output.
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
new file mode 100644
index 0000000..635fe4d
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "APM::AudioCollections"
+//#define LOG_NDEBUG 0
+
+#include "AudioCollections.h"
+#include "AudioPort.h"
+#include "AudioRoute.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+
+namespace android {
+
+sp<AudioPort> AudioPortVector::findByTagName(const String8 &tagName) const
+{
+ sp<AudioPort> port = 0;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->getTagName() == tagName) {
+ port = itemAt(i);
+ break;
+ }
+ }
+ return port;
+}
+
+status_t AudioRouteVector::dump(int fd, int spaces) const
+{
+ if (isEmpty()) {
+ return NO_ERROR;
+ }
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\n%*sAudio Routes (%zu):\n", spaces, "", size());
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "%*s- Route %zu:\n", spaces, "", i + 1);
+ write(fd, buffer, strlen(buffer));
+ itemAt(i)->dump(fd, 4);
+ }
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
index fc7b0cc..e454941 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
@@ -25,7 +25,6 @@
#endif
#include "AudioGain.h"
-#include "StreamDescriptor.h"
#include <utils/Log.h>
#include <utils/String8.h>
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 626fdae..9b6469c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -28,13 +28,11 @@
AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
: mIoHandle(0),
- mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mRefCount(0),
- mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false), mId(0)
+ mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0),
+ mProfile(profile), mId(0)
{
if (profile != NULL) {
- mSamplingRate = profile->pickSamplingRate();
- mFormat = profile->pickFormat();
- mChannelMask = profile->pickChannelMask();
+ profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
if (profile->mGains.size() > 0) {
profile->mGains[0]->getDefaultConfig(&mGain);
}
@@ -55,11 +53,23 @@
return mProfile->getModuleHandle();
}
+uint32_t AudioInputDescriptor::getOpenRefCount() const
+{
+ return mSessions.getOpenCount();
+}
+
audio_port_handle_t AudioInputDescriptor::getId() const
{
return mId;
}
+audio_source_t AudioInputDescriptor::inputSource() const
+{
+ // TODO: return highest priority input source
+ return mSessions.size() > 0 ? mSessions.valueAt(0)->inputSource() :
+ AUDIO_SOURCE_DEFAULT;
+}
+
void AudioInputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig) const
{
@@ -78,7 +88,7 @@
dstConfig->type = AUDIO_PORT_TYPE_MIX;
dstConfig->ext.mix.hw_module = getModuleHandle();
dstConfig->ext.mix.handle = mIoHandle;
- dstConfig->ext.mix.usecase.source = mInputSource;
+ dstConfig->ext.mix.usecase.source = inputSource();
}
void AudioInputDescriptor::toAudioPort(struct audio_port *port) const
@@ -113,6 +123,40 @@
mPreemptedSessions.clear();
}
+bool AudioInputDescriptor::isActive() const {
+ return mSessions.hasActiveSession();
+}
+
+bool AudioInputDescriptor::isSourceActive(audio_source_t source) const
+{
+ return mSessions.isSourceActive(source);
+}
+
+bool AudioInputDescriptor::isSoundTrigger() const {
+ // sound trigger and non sound trigger sessions are not mixed
+ // on a given input
+ return mSessions.valueAt(0)->isSoundTrigger();
+}
+
+sp<AudioSession> AudioInputDescriptor::getAudioSession(
+ audio_session_t session) const {
+ return mSessions.valueFor(session);
+}
+
+AudioSessionCollection AudioInputDescriptor::getActiveAudioSessions() const
+{
+ return mSessions.getActiveSessions();
+}
+
+status_t AudioInputDescriptor::addAudioSession(audio_session_t session,
+ const sp<AudioSession>& audioSession) {
+ return mSessions.addSession(session, audioSession);
+}
+
+status_t AudioInputDescriptor::removeAudioSession(audio_session_t session) {
+ return mSessions.removeSession(session);
+}
+
status_t AudioInputDescriptor::dump(int fd)
{
const size_t SIZE = 256;
@@ -129,13 +173,11 @@
result.append(buffer);
snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
result.append(buffer);
- snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount);
- result.append(buffer);
- snprintf(buffer, SIZE, " Open Ref Count %d\n", mOpenRefCount);
- result.append(buffer);
write(fd, result.string(), result.size());
+ mSessions.dump(fd, 1);
+
return NO_ERROR;
}
@@ -143,10 +185,7 @@
{
for (size_t i = 0; i < size(); i++) {
const sp<AudioInputDescriptor> inputDescriptor = valueAt(i);
- if (inputDescriptor->mRefCount == 0) {
- continue;
- }
- if (inputDescriptor->mInputSource == (int)source) {
+ if (inputDescriptor->isSourceActive(source)) {
return true;
}
}
@@ -169,8 +208,8 @@
{
uint32_t count = 0;
for (size_t i = 0; i < size(); i++) {
- const sp<AudioInputDescriptor> desc = valueAt(i);
- if (desc->mRefCount > 0) {
+ const sp<AudioInputDescriptor> inputDescriptor = valueAt(i);
+ if (inputDescriptor->isActive()) {
count++;
}
}
@@ -180,9 +219,10 @@
audio_io_handle_t AudioInputCollection::getActiveInput(bool ignoreVirtualInputs)
{
for (size_t i = 0; i < size(); i++) {
- const sp<AudioInputDescriptor> input_descriptor = valueAt(i);
- if ((input_descriptor->mRefCount > 0)
- && (!ignoreVirtualInputs || !is_virtual_input_device(input_descriptor->mDevice))) {
+ const sp<AudioInputDescriptor> inputDescriptor = valueAt(i);
+ if ((inputDescriptor->isActive())
+ && (!ignoreVirtualInputs ||
+ !is_virtual_input_device(inputDescriptor->mDevice))) {
return keyAt(i);
}
}
@@ -192,7 +232,7 @@
audio_devices_t AudioInputCollection::getSupportedDevices(audio_io_handle_t handle) const
{
sp<AudioInputDescriptor> inputDesc = valueFor(handle);
- audio_devices_t devices = inputDesc->mProfile->mSupportedDevices.types();
+ audio_devices_t devices = inputDesc->mProfile->getSupportedDevicesType();
return devices;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index a278375..5d0f03f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -47,9 +47,7 @@
mStrategyMutedByDevice[i] = false;
}
if (port != NULL) {
- mSamplingRate = port->pickSamplingRate();
- mFormat = port->pickFormat();
- mChannelMask = port->pickChannelMask();
+ port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
if (port->mGains.size() > 0) {
port->mGains[0]->getDefaultConfig(&mGain);
}
@@ -220,15 +218,15 @@
}
// SwAudioOutputDescriptor implementation
-SwAudioOutputDescriptor::SwAudioOutputDescriptor(
- const sp<IOProfile>& profile, AudioPolicyClientInterface *clientInterface)
+SwAudioOutputDescriptor::SwAudioOutputDescriptor(const sp<IOProfile>& profile,
+ AudioPolicyClientInterface *clientInterface)
: AudioOutputDescriptor(profile, clientInterface),
mProfile(profile), mIoHandle(0), mLatency(0),
mFlags((audio_output_flags_t)0), mPolicyMix(NULL),
mOutput1(0), mOutput2(0), mDirectOpenCount(0), mGlobalRefCount(0)
{
if (profile != NULL) {
- mFlags = (audio_output_flags_t)profile->mFlags;
+ mFlags = (audio_output_flags_t)profile->getFlags();
}
}
@@ -283,7 +281,7 @@
if (isDuplicated()) {
return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices());
} else {
- return mProfile->mSupportedDevices.types() ;
+ return mProfile->getSupportedDevicesType();
}
}
@@ -388,8 +386,64 @@
return changed;
}
-// SwAudioOutputCollection implementation
+// HwAudioOutputDescriptor implementation
+HwAudioOutputDescriptor::HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+ AudioPolicyClientInterface *clientInterface)
+ : AudioOutputDescriptor(source->mDevice, clientInterface),
+ mSource(source)
+{
+}
+status_t HwAudioOutputDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ AudioOutputDescriptor::dump(fd);
+
+ snprintf(buffer, SIZE, "Source:\n");
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ mSource->dump(fd);
+
+ return NO_ERROR;
+}
+
+audio_devices_t HwAudioOutputDescriptor::supportedDevices()
+{
+ return mDevice;
+}
+
+void HwAudioOutputDescriptor::toAudioPortConfig(
+ struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig) const
+{
+ mSource->mDevice->toAudioPortConfig(dstConfig, srcConfig);
+}
+
+void HwAudioOutputDescriptor::toAudioPort(
+ struct audio_port *port) const
+{
+ mSource->mDevice->toAudioPort(port);
+}
+
+
+bool HwAudioOutputDescriptor::setVolume(float volume,
+ audio_stream_type_t stream,
+ audio_devices_t device,
+ uint32_t delayMs,
+ bool force)
+{
+ bool changed = AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force);
+
+ if (changed) {
+ // TODO: use gain controller on source device if any to adjust volume
+ }
+ return changed;
+}
+
+// SwAudioOutputCollection implementation
bool SwAudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
{
nsecs_t sysTime = systemTime();
@@ -473,7 +527,7 @@
audio_devices_t SwAudioOutputCollection::getSupportedDevices(audio_io_handle_t handle) const
{
sp<SwAudioOutputDescriptor> outputDesc = valueFor(handle);
- audio_devices_t devices = outputDesc->mProfile->mSupportedDevices.types();
+ audio_devices_t devices = outputDesc->mProfile->getSupportedDevicesType();
return devices;
}
@@ -494,4 +548,49 @@
return NO_ERROR;
}
+// HwAudioOutputCollection implementation
+bool HwAudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
+{
+ nsecs_t sysTime = systemTime();
+ for (size_t i = 0; i < this->size(); i++) {
+ const sp<HwAudioOutputDescriptor> outputDesc = this->valueAt(i);
+ if (outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool HwAudioOutputCollection::isAnyOutputActive(audio_stream_type_t streamToIgnore) const
+{
+ for (size_t s = 0 ; s < AUDIO_STREAM_CNT ; s++) {
+ if (s == (size_t) streamToIgnore) {
+ continue;
+ }
+ for (size_t i = 0; i < size(); i++) {
+ const sp<HwAudioOutputDescriptor> outputDesc = valueAt(i);
+ if (outputDesc->mRefCount[s] != 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+status_t HwAudioOutputCollection::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\nOutputs dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "- Output %d dump:\n", keyAt(i));
+ write(fd, buffer, strlen(buffer));
+ valueAt(i)->dump(fd);
+ }
+
+ return NO_ERROR;
+}
+
}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
index a06d867..9c28e8f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -19,7 +19,7 @@
#include "AudioPatch.h"
#include "AudioGain.h"
-#include "ConfigParsingUtils.h"
+#include "TypeConverter.h"
#include <cutils/log.h>
#include <utils/String8.h>
@@ -53,10 +53,11 @@
result.append(buffer);
for (size_t i = 0; i < mPatch.num_sources; i++) {
if (mPatch.sources[i].type == AUDIO_PORT_TYPE_DEVICE) {
+ std::string device;
+ DeviceConverter::toString(mPatch.sources[i].ext.device.type, device);
snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
- mPatch.sources[i].id, ConfigParsingUtils::enumToString(sDeviceTypeToEnumTable,
- ARRAY_SIZE(sDeviceTypeToEnumTable),
- mPatch.sources[i].ext.device.type));
+ mPatch.sources[i].id,
+ device.c_str());
} else {
snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
mPatch.sources[i].id, mPatch.sources[i].ext.mix.handle);
@@ -67,10 +68,11 @@
result.append(buffer);
for (size_t i = 0; i < mPatch.num_sinks; i++) {
if (mPatch.sinks[i].type == AUDIO_PORT_TYPE_DEVICE) {
+ std::string device;
+ DeviceConverter::toString(mPatch.sinks[i].ext.device.type, device);
snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
- mPatch.sinks[i].id, ConfigParsingUtils::enumToString(sDeviceTypeToEnumTable,
- ARRAY_SIZE(sDeviceTypeToEnumTable),
- mPatch.sinks[i].ext.device.type));
+ mPatch.sinks[i].id,
+ device.c_str());
} else {
snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
mPatch.sinks[i].id, mPatch.sinks[i].ext.mix.handle);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 6f1998c..3735c05 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -98,30 +98,111 @@
}
}
-status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes,
+status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes, uid_t uid,
sp<SwAudioOutputDescriptor> &desc)
{
+ desc = 0;
for (size_t i = 0; i < size(); i++) {
sp<AudioPolicyMix> policyMix = valueAt(i);
AudioMix *mix = policyMix->getMix();
if (mix->mMixType == MIX_TYPE_PLAYERS) {
+ // TODO if adding more player rules (currently only 2), make rule handling "generic"
+ // as there is no difference in the treatment of usage- or uid-based rules
+ bool hasUsageMatchRules = false;
+ bool hasUsageExcludeRules = false;
+ bool usageMatchFound = false;
+ bool usageExclusionFound = false;
+
+ bool hasUidMatchRules = false;
+ bool hasUidExcludeRules = false;
+ bool uidMatchFound = false;
+ bool uidExclusionFound = false;
+
+ bool hasAddrMatch = false;
+
+ // iterate over all mix criteria to list what rules this mix contains
for (size_t j = 0; j < mix->mCriteria.size(); j++) {
- if ((RULE_MATCH_ATTRIBUTE_USAGE == mix->mCriteria[j].mRule &&
- mix->mCriteria[j].mAttr.mUsage == attributes.usage) ||
- (RULE_EXCLUDE_ATTRIBUTE_USAGE == mix->mCriteria[j].mRule &&
- mix->mCriteria[j].mAttr.mUsage != attributes.usage)) {
- desc = policyMix->getOutput();
- break;
- }
+ ALOGV("getOutputForAttr: inspecting mix %zu of %zu", i, mix->mCriteria.size());
+
+ // if there is an address match, prioritize that match
if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
strncmp(attributes.tags + strlen("addr="),
mix->mRegistrationId.string(),
AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
- desc = policyMix->getOutput();
+ hasAddrMatch = true;
break;
}
+
+ switch (mix->mCriteria[j].mRule) {
+ case RULE_MATCH_ATTRIBUTE_USAGE:
+ ALOGV("\tmix has RULE_MATCH_ATTRIBUTE_USAGE for usage %d",
+ mix->mCriteria[j].mValue.mUsage);
+ hasUsageMatchRules = true;
+ if (mix->mCriteria[j].mValue.mUsage == attributes.usage) {
+ // found one match against all allowed usages
+ usageMatchFound = true;
+ }
+ break;
+ case RULE_EXCLUDE_ATTRIBUTE_USAGE:
+ ALOGV("\tmix has RULE_EXCLUDE_ATTRIBUTE_USAGE for usage %d",
+ mix->mCriteria[j].mValue.mUsage);
+ hasUsageExcludeRules = true;
+ if (mix->mCriteria[j].mValue.mUsage == attributes.usage) {
+ // found this usage is to be excluded
+ usageExclusionFound = true;
+ }
+ break;
+ case RULE_MATCH_UID:
+ ALOGV("\tmix has RULE_MATCH_UID for uid %d", mix->mCriteria[j].mValue.mUid);
+ hasUidMatchRules = true;
+ if (mix->mCriteria[j].mValue.mUid == uid) {
+ // found one UID match against all allowed UIDs
+ uidMatchFound = true;
+ }
+ break;
+ case RULE_EXCLUDE_UID:
+ ALOGV("\tmix has RULE_EXCLUDE_UID for uid %d", mix->mCriteria[j].mValue.mUid);
+ hasUidExcludeRules = true;
+ if (mix->mCriteria[j].mValue.mUid == uid) {
+ // found this UID is to be excluded
+ uidExclusionFound = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ // consistency checks: for each "dimension" of rules (usage, uid...), we can
+ // only have MATCH rules, or EXCLUDE rules in each dimension, not a combination
+ if (hasUsageMatchRules && hasUsageExcludeRules) {
+ ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_ATTRIBUTE_USAGE"
+ " and RULE_EXCLUDE_ATTRIBUTE_USAGE in mix %zu", i);
+ return BAD_VALUE;
+ }
+ if (hasUidMatchRules && hasUidExcludeRules) {
+ ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_UID"
+ " and RULE_EXCLUDE_UID in mix %zu", i);
+ return BAD_VALUE;
+ }
+
+ if ((hasUsageExcludeRules && usageExclusionFound)
+ || (hasUidExcludeRules && uidExclusionFound)) {
+ break; // stop iterating on criteria because an exclusion was found (will fail)
+ }
+
+ }//iterate on mix criteria
+
+ // determine if exiting on success (or implicit failure as desc is 0)
+ if (hasAddrMatch ||
+ !((hasUsageExcludeRules && usageExclusionFound) ||
+ (hasUsageMatchRules && !usageMatchFound) ||
+ (hasUidExcludeRules && uidExclusionFound) ||
+ (hasUidMatchRules && !uidMatchFound))) {
+ ALOGV("\tgetOutputForAttr will use mix %zu", i);
+ desc = policyMix->getOutput();
}
+
} else if (mix->mMixType == MIX_TYPE_RECORDERS) {
if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE &&
strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
@@ -151,9 +232,9 @@
}
for (size_t j = 0; j < mix->mCriteria.size(); j++) {
if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule &&
- mix->mCriteria[j].mAttr.mSource == inputSource) ||
+ mix->mCriteria[j].mValue.mSource == inputSource) ||
(RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule &&
- mix->mCriteria[j].mAttr.mSource != inputSource)) {
+ mix->mCriteria[j].mValue.mSource != inputSource)) {
if (availDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
if (policyMix != NULL) {
*policyMix = mix;
@@ -174,6 +255,15 @@
}
String8 address(attr.tags + strlen("addr="));
+#ifdef LOG_NDEBUG
+ ALOGV("getInputMixForAttr looking for address %s\n mixes available:", address.string());
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioPolicyMix> policyMix = valueAt(i);
+ AudioMix *mix = policyMix->getMix();
+ ALOGV("\tmix %zu address=%s", i, mix->mRegistrationId.string());
+ }
+#endif
+
ssize_t index = indexOfKey(address);
if (index < 0) {
ALOGW("getInputMixForAttr() no policy for address %s", address.string());
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 4e24f19..bda59ad 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -16,28 +16,21 @@
#define LOG_TAG "APM::AudioPort"
//#define LOG_NDEBUG 0
-#include <media/AudioResamplerPublic.h>
+#include "TypeConverter.h"
#include "AudioPort.h"
#include "HwModule.h"
#include "AudioGain.h"
-#include "ConfigParsingUtils.h"
-#include "audio_policy_conf.h"
#include <policy.h>
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
namespace android {
int32_t volatile AudioPort::mNextUniqueId = 1;
// --- AudioPort class implementation
-
-AudioPort::AudioPort(const String8& name, audio_port_type_t type,
- audio_port_role_t role) :
- mName(name), mType(type), mRole(role), mFlags(0)
-{
- mUseInChannelMask = ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
- ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
-}
-
void AudioPort::attach(const sp<HwModule>& module)
{
mModule = module;
@@ -61,605 +54,178 @@
if (mModule == 0) {
return 0;
}
- return mModule->mHalVersion;
+ return mModule->getHalVersion();
}
const char *AudioPort::getModuleName() const
{
if (mModule == 0) {
- return "";
+ return "invalid module";
}
- return mModule->mName;
+ return mModule->getName();
}
void AudioPort::toAudioPort(struct audio_port *port) const
{
+ // TODO: update this function once audio_port structure reflects the new profile definition.
+ // For compatibility reason: flatening the AudioProfile into audio_port structure.
+ SortedVector<audio_format_t> flatenedFormats;
+ SampleRateVector flatenedRates;
+ ChannelsVector flatenedChannels;
+ for (size_t profileIndex = 0; profileIndex < mProfiles.size(); profileIndex++) {
+ if (mProfiles[profileIndex]->isValid()) {
+ audio_format_t formatToExport = mProfiles[profileIndex]->getFormat();
+ const SampleRateVector &ratesToExport = mProfiles[profileIndex]->getSampleRates();
+ const ChannelsVector &channelsToExport = mProfiles[profileIndex]->getChannels();
+
+ if (flatenedFormats.indexOf(formatToExport) < 0) {
+ flatenedFormats.add(formatToExport);
+ }
+ for (size_t rateIndex = 0; rateIndex < ratesToExport.size(); rateIndex++) {
+ uint32_t rate = ratesToExport[rateIndex];
+ if (flatenedRates.indexOf(rate) < 0) {
+ flatenedRates.add(rate);
+ }
+ }
+ for (size_t chanIndex = 0; chanIndex < channelsToExport.size(); chanIndex++) {
+ audio_channel_mask_t channels = channelsToExport[chanIndex];
+ if (flatenedChannels.indexOf(channels) < 0) {
+ flatenedChannels.add(channels);
+ }
+ }
+ if (flatenedRates.size() > AUDIO_PORT_MAX_SAMPLING_RATES ||
+ flatenedChannels.size() > AUDIO_PORT_MAX_CHANNEL_MASKS ||
+ flatenedFormats.size() > AUDIO_PORT_MAX_FORMATS) {
+ ALOGE("%s: bailing out: cannot export profiles to port config", __FUNCTION__);
+ return;
+ }
+ }
+ }
port->role = mRole;
port->type = mType;
strlcpy(port->name, mName, AUDIO_PORT_MAX_NAME_LEN);
- unsigned int i;
- for (i = 0; i < mSamplingRates.size() && i < AUDIO_PORT_MAX_SAMPLING_RATES; i++) {
- if (mSamplingRates[i] != 0) {
- port->sample_rates[i] = mSamplingRates[i];
- }
+ port->num_sample_rates = flatenedRates.size();
+ port->num_channel_masks = flatenedChannels.size();
+ port->num_formats = flatenedFormats.size();
+ for (size_t i = 0; i < flatenedRates.size(); i++) {
+ port->sample_rates[i] = flatenedRates[i];
}
- port->num_sample_rates = i;
- for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) {
- if (mChannelMasks[i] != 0) {
- port->channel_masks[i] = mChannelMasks[i];
- }
+ for (size_t i = 0; i < flatenedChannels.size(); i++) {
+ port->channel_masks[i] = flatenedChannels[i];
}
- port->num_channel_masks = i;
- for (i = 0; i < mFormats.size() && i < AUDIO_PORT_MAX_FORMATS; i++) {
- if (mFormats[i] != 0) {
- port->formats[i] = mFormats[i];
- }
+ for (size_t i = 0; i < flatenedFormats.size(); i++) {
+ port->formats[i] = flatenedFormats[i];
}
- port->num_formats = i;
ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
+ uint32_t i;
for (i = 0; i < mGains.size() && i < AUDIO_PORT_MAX_GAINS; i++) {
- port->gains[i] = mGains[i]->mGain;
+ port->gains[i] = mGains[i]->getGain();
}
port->num_gains = i;
}
-void AudioPort::importAudioPort(const sp<AudioPort> port) {
- for (size_t k = 0 ; k < port->mSamplingRates.size() ; k++) {
- const uint32_t rate = port->mSamplingRates.itemAt(k);
- if (rate != 0) { // skip "dynamic" rates
- bool hasRate = false;
- for (size_t l = 0 ; l < mSamplingRates.size() ; l++) {
- if (rate == mSamplingRates.itemAt(l)) {
- hasRate = true;
+void AudioPort::importAudioPort(const sp<AudioPort> port)
+{
+ size_t indexToImport;
+ for (indexToImport = 0; indexToImport < port->mProfiles.size(); indexToImport++) {
+ const sp<AudioProfile> &profileToImport = port->mProfiles[indexToImport];
+ if (profileToImport->isValid()) {
+ // Import only valid port, i.e. valid format, non empty rates and channels masks
+ bool hasSameProfile = false;
+ for (size_t profileIndex = 0; profileIndex < mProfiles.size(); profileIndex++) {
+ if (*mProfiles[profileIndex] == *profileToImport) {
+ // never import a profile twice
+ hasSameProfile = true;
break;
}
}
- if (!hasRate) { // never import a sampling rate twice
- mSamplingRates.add(rate);
+ if (hasSameProfile) { // never import a same profile twice
+ continue;
}
- }
- }
- for (size_t k = 0 ; k < port->mChannelMasks.size() ; k++) {
- const audio_channel_mask_t mask = port->mChannelMasks.itemAt(k);
- if (mask != 0) { // skip "dynamic" masks
- bool hasMask = false;
- for (size_t l = 0 ; l < mChannelMasks.size() ; l++) {
- if (mask == mChannelMasks.itemAt(l)) {
- hasMask = true;
- break;
- }
- }
- if (!hasMask) { // never import a channel mask twice
- mChannelMasks.add(mask);
- }
- }
- }
- for (size_t k = 0 ; k < port->mFormats.size() ; k++) {
- const audio_format_t format = port->mFormats.itemAt(k);
- if (format != 0) { // skip "dynamic" formats
- bool hasFormat = false;
- for (size_t l = 0 ; l < mFormats.size() ; l++) {
- if (format == mFormats.itemAt(l)) {
- hasFormat = true;
- break;
- }
- }
- if (!hasFormat) { // never import a format twice
- mFormats.add(format);
- }
+ addAudioProfile(profileToImport);
}
}
}
-void AudioPort::clearCapabilities() {
- mChannelMasks.clear();
- mFormats.clear();
- mSamplingRates.clear();
-}
-
-void AudioPort::loadSamplingRates(char *name)
+void AudioPort::pickSamplingRate(uint32_t &pickedRate,const SampleRateVector &samplingRates) const
{
- char *str = strtok(name, "|");
-
- // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
- // rates should be read from the output stream after it is opened for the first time
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- mSamplingRates.add(0);
- return;
- }
-
- while (str != NULL) {
- uint32_t rate = atoi(str);
- if (rate != 0) {
- ALOGV("loadSamplingRates() adding rate %d", rate);
- mSamplingRates.add(rate);
- }
- str = strtok(NULL, "|");
- }
-}
-
-void AudioPort::loadFormats(char *name)
-{
- char *str = strtok(name, "|");
-
- // by convention, "0' in the first entry in mFormats indicates the supported formats
- // should be read from the output stream after it is opened for the first time
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- mFormats.add(AUDIO_FORMAT_DEFAULT);
- return;
- }
-
- while (str != NULL) {
- audio_format_t format = (audio_format_t)ConfigParsingUtils::stringToEnum(sFormatNameToEnumTable,
- ARRAY_SIZE(sFormatNameToEnumTable),
- str);
- if (format != AUDIO_FORMAT_DEFAULT) {
- mFormats.add(format);
- }
- str = strtok(NULL, "|");
- }
- // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
- // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
- // [](const audio_format_t *format1, const audio_format_t *format2) {
- // return compareFormats(*format1, *format2);
- // }
- mFormats.sort(compareFormats);
-}
-
-void AudioPort::loadInChannels(char *name)
-{
- const char *str = strtok(name, "|");
-
- ALOGV("loadInChannels() %s", name);
-
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- mChannelMasks.add(0);
- return;
- }
-
- while (str != NULL) {
- audio_channel_mask_t channelMask =
- (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sInChannelsNameToEnumTable,
- ARRAY_SIZE(sInChannelsNameToEnumTable),
- str);
- if (channelMask == 0) { // if not found, check the channel index table
- channelMask = (audio_channel_mask_t)
- ConfigParsingUtils::stringToEnum(sIndexChannelsNameToEnumTable,
- ARRAY_SIZE(sIndexChannelsNameToEnumTable),
- str);
- }
- if (channelMask != 0) {
- ALOGV("loadInChannels() adding channelMask %#x", channelMask);
- mChannelMasks.add(channelMask);
- }
- str = strtok(NULL, "|");
- }
-}
-
-void AudioPort::loadOutChannels(char *name)
-{
- const char *str = strtok(name, "|");
-
- ALOGV("loadOutChannels() %s", name);
-
- // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
- // masks should be read from the output stream after it is opened for the first time
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- mChannelMasks.add(0);
- return;
- }
-
- while (str != NULL) {
- audio_channel_mask_t channelMask =
- (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sOutChannelsNameToEnumTable,
- ARRAY_SIZE(sOutChannelsNameToEnumTable),
- str);
- if (channelMask == 0) { // if not found, check the channel index table
- channelMask = (audio_channel_mask_t)
- ConfigParsingUtils::stringToEnum(sIndexChannelsNameToEnumTable,
- ARRAY_SIZE(sIndexChannelsNameToEnumTable),
- str);
- }
- if (channelMask != 0) {
- mChannelMasks.add(channelMask);
- }
- str = strtok(NULL, "|");
- }
- return;
-}
-
-audio_gain_mode_t AudioPort::loadGainMode(char *name)
-{
- const char *str = strtok(name, "|");
-
- ALOGV("loadGainMode() %s", name);
- audio_gain_mode_t mode = 0;
- while (str != NULL) {
- mode |= (audio_gain_mode_t)ConfigParsingUtils::stringToEnum(sGainModeNameToEnumTable,
- ARRAY_SIZE(sGainModeNameToEnumTable),
- str);
- str = strtok(NULL, "|");
- }
- return mode;
-}
-
-void AudioPort::loadGain(cnode *root, int index)
-{
- cnode *node = root->first_child;
-
- sp<AudioGain> gain = new AudioGain(index, mUseInChannelMask);
-
- while (node) {
- if (strcmp(node->name, GAIN_MODE) == 0) {
- gain->mGain.mode = loadGainMode((char *)node->value);
- } else if (strcmp(node->name, GAIN_CHANNELS) == 0) {
- if (mUseInChannelMask) {
- gain->mGain.channel_mask =
- (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sInChannelsNameToEnumTable,
- ARRAY_SIZE(sInChannelsNameToEnumTable),
- (char *)node->value);
- } else {
- gain->mGain.channel_mask =
- (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sOutChannelsNameToEnumTable,
- ARRAY_SIZE(sOutChannelsNameToEnumTable),
- (char *)node->value);
- }
- } else if (strcmp(node->name, GAIN_MIN_VALUE) == 0) {
- gain->mGain.min_value = atoi((char *)node->value);
- } else if (strcmp(node->name, GAIN_MAX_VALUE) == 0) {
- gain->mGain.max_value = atoi((char *)node->value);
- } else if (strcmp(node->name, GAIN_DEFAULT_VALUE) == 0) {
- gain->mGain.default_value = atoi((char *)node->value);
- } else if (strcmp(node->name, GAIN_STEP_VALUE) == 0) {
- gain->mGain.step_value = atoi((char *)node->value);
- } else if (strcmp(node->name, GAIN_MIN_RAMP_MS) == 0) {
- gain->mGain.min_ramp_ms = atoi((char *)node->value);
- } else if (strcmp(node->name, GAIN_MAX_RAMP_MS) == 0) {
- gain->mGain.max_ramp_ms = atoi((char *)node->value);
- }
- node = node->next;
- }
-
- ALOGV("loadGain() adding new gain mode %08x channel mask %08x min mB %d max mB %d",
- gain->mGain.mode, gain->mGain.channel_mask, gain->mGain.min_value, gain->mGain.max_value);
-
- if (gain->mGain.mode == 0) {
- return;
- }
- mGains.add(gain);
-}
-
-void AudioPort::loadGains(cnode *root)
-{
- cnode *node = root->first_child;
- int index = 0;
- while (node) {
- ALOGV("loadGains() loading gain %s", node->name);
- loadGain(node, index++);
- node = node->next;
- }
-}
-
-status_t AudioPort::checkExactSamplingRate(uint32_t samplingRate) const
-{
- if (mSamplingRates.isEmpty()) {
- return NO_ERROR;
- }
-
- for (size_t i = 0; i < mSamplingRates.size(); i ++) {
- if (mSamplingRates[i] == samplingRate) {
- return NO_ERROR;
- }
- }
- return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
- uint32_t *updatedSamplingRate) const
-{
- if (mSamplingRates.isEmpty()) {
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = samplingRate;
- }
- return NO_ERROR;
- }
-
- // Search for the closest supported sampling rate that is above (preferred)
- // or below (acceptable) the desired sampling rate, within a permitted ratio.
- // The sampling rates do not need to be sorted in ascending order.
- ssize_t maxBelow = -1;
- ssize_t minAbove = -1;
- uint32_t candidate;
- for (size_t i = 0; i < mSamplingRates.size(); i++) {
- candidate = mSamplingRates[i];
- if (candidate == samplingRate) {
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = candidate;
- }
- return NO_ERROR;
- }
- // candidate < desired
- if (candidate < samplingRate) {
- if (maxBelow < 0 || candidate > mSamplingRates[maxBelow]) {
- maxBelow = i;
- }
- // candidate > desired
- } else {
- if (minAbove < 0 || candidate < mSamplingRates[minAbove]) {
- minAbove = i;
- }
- }
- }
-
- // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
- if (minAbove >= 0) {
- candidate = mSamplingRates[minAbove];
- if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = candidate;
- }
- return NO_ERROR;
- }
- }
- // But if we have to up-sample from a lower sampling rate, that's OK.
- if (maxBelow >= 0) {
- candidate = mSamplingRates[maxBelow];
- if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = candidate;
- }
- return NO_ERROR;
- }
- }
- // leave updatedSamplingRate unmodified
- return BAD_VALUE;
-}
-
-status_t AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) const
-{
- if (mChannelMasks.isEmpty()) {
- return NO_ERROR;
- }
-
- for (size_t i = 0; i < mChannelMasks.size(); i++) {
- if (mChannelMasks[i] == channelMask) {
- return NO_ERROR;
- }
- }
- return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
- audio_channel_mask_t *updatedChannelMask) const
-{
- if (mChannelMasks.isEmpty()) {
- if (updatedChannelMask != NULL) {
- *updatedChannelMask = channelMask;
- }
- return NO_ERROR;
- }
-
- const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
- const bool isIndex = audio_channel_mask_get_representation(channelMask)
- == AUDIO_CHANNEL_REPRESENTATION_INDEX;
- int bestMatch = 0;
- for (size_t i = 0; i < mChannelMasks.size(); i ++) {
- audio_channel_mask_t supported = mChannelMasks[i];
- if (supported == channelMask) {
- // Exact matches always taken.
- if (updatedChannelMask != NULL) {
- *updatedChannelMask = channelMask;
- }
- return NO_ERROR;
- }
-
- // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
- if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
- // Approximate (best) match:
- // The match score measures how well the supported channel mask matches the
- // desired mask, where increasing-is-better.
- //
- // TODO: Some tweaks may be needed.
- // Should be a static function of the data processing library.
- //
- // In priority:
- // match score = 1000 if legacy channel conversion equivalent (always prefer this)
- // OR
- // match score += 100 if the channel mask representations match
- // match score += number of channels matched.
- //
- // If there are no matched channels, the mask may still be accepted
- // but the playback or record will be silent.
- const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
- == AUDIO_CHANNEL_REPRESENTATION_INDEX);
- int match;
- if (isIndex && isSupportedIndex) {
- // index equivalence
- match = 100 + __builtin_popcount(
- audio_channel_mask_get_bits(channelMask)
- & audio_channel_mask_get_bits(supported));
- } else if (isIndex && !isSupportedIndex) {
- const uint32_t equivalentBits =
- (1 << audio_channel_count_from_in_mask(supported)) - 1 ;
- match = __builtin_popcount(
- audio_channel_mask_get_bits(channelMask) & equivalentBits);
- } else if (!isIndex && isSupportedIndex) {
- const uint32_t equivalentBits =
- (1 << audio_channel_count_from_in_mask(channelMask)) - 1;
- match = __builtin_popcount(
- equivalentBits & audio_channel_mask_get_bits(supported));
- } else {
- // positional equivalence
- match = 100 + __builtin_popcount(
- audio_channel_mask_get_bits(channelMask)
- & audio_channel_mask_get_bits(supported));
- switch (supported) {
- case AUDIO_CHANNEL_IN_FRONT_BACK:
- case AUDIO_CHANNEL_IN_STEREO:
- if (channelMask == AUDIO_CHANNEL_IN_MONO) {
- match = 1000;
- }
- break;
- case AUDIO_CHANNEL_IN_MONO:
- if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
- || channelMask == AUDIO_CHANNEL_IN_STEREO) {
- match = 1000;
- }
- break;
- default:
- break;
- }
- }
- if (match > bestMatch) {
- bestMatch = match;
- if (updatedChannelMask != NULL) {
- *updatedChannelMask = supported;
- } else {
- return NO_ERROR; // any match will do in this case.
- }
- }
- }
- }
- return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
-}
-
-status_t AudioPort::checkExactFormat(audio_format_t format) const
-{
- if (mFormats.isEmpty()) {
- return NO_ERROR;
- }
-
- for (size_t i = 0; i < mFormats.size(); i ++) {
- if (mFormats[i] == format) {
- return NO_ERROR;
- }
- }
- return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat)
- const
-{
- if (mFormats.isEmpty()) {
- if (updatedFormat != NULL) {
- *updatedFormat = format;
- }
- return NO_ERROR;
- }
-
- const bool checkInexact = // when port is input and format is linear pcm
- mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK
- && audio_is_linear_pcm(format);
-
- // iterate from best format to worst format (reverse order)
- for (ssize_t i = mFormats.size() - 1; i >= 0 ; --i) {
- if (mFormats[i] == format ||
- (checkInexact
- && mFormats[i] != AUDIO_FORMAT_DEFAULT
- && audio_is_linear_pcm(mFormats[i]))) {
- // for inexact checks we take the first linear pcm format due to sorting.
- if (updatedFormat != NULL) {
- *updatedFormat = mFormats[i];
- }
- return NO_ERROR;
- }
- }
- return BAD_VALUE;
-}
-
-uint32_t AudioPort::pickSamplingRate() const
-{
- // special case for uninitialized dynamic profile
- if (mSamplingRates.size() == 1 && mSamplingRates[0] == 0) {
- return 0;
- }
-
+ pickedRate = 0;
// For direct outputs, pick minimum sampling rate: this helps ensuring that the
// channel count / sampling rate combination chosen will be supported by the connected
// sink
- if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
- (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) {
+ if (isDirectOutput()) {
uint32_t samplingRate = UINT_MAX;
- for (size_t i = 0; i < mSamplingRates.size(); i ++) {
- if ((mSamplingRates[i] < samplingRate) && (mSamplingRates[i] > 0)) {
- samplingRate = mSamplingRates[i];
+ for (size_t i = 0; i < samplingRates.size(); i ++) {
+ if ((samplingRates[i] < samplingRate) && (samplingRates[i] > 0)) {
+ samplingRate = samplingRates[i];
}
}
- return (samplingRate == UINT_MAX) ? 0 : samplingRate;
- }
+ pickedRate = (samplingRate == UINT_MAX) ? 0 : samplingRate;
+ } else {
+ uint32_t maxRate = MAX_MIXER_SAMPLING_RATE;
- uint32_t samplingRate = 0;
- uint32_t maxRate = MAX_MIXER_SAMPLING_RATE;
-
- // For mixed output and inputs, use max mixer sampling rates. Do not
- // limit sampling rate otherwise
- // For inputs, also see checkCompatibleSamplingRate().
- if (mType != AUDIO_PORT_TYPE_MIX) {
- maxRate = UINT_MAX;
- }
- // TODO: should mSamplingRates[] be ordered in terms of our preference
- // and we return the first (and hence most preferred) match? This is of concern if
- // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
- for (size_t i = 0; i < mSamplingRates.size(); i ++) {
- if ((mSamplingRates[i] > samplingRate) && (mSamplingRates[i] <= maxRate)) {
- samplingRate = mSamplingRates[i];
+ // For mixed output and inputs, use max mixer sampling rates. Do not
+ // limit sampling rate otherwise
+ // For inputs, also see checkCompatibleSamplingRate().
+ if (mType != AUDIO_PORT_TYPE_MIX) {
+ maxRate = UINT_MAX;
+ }
+ // TODO: should mSamplingRates[] be ordered in terms of our preference
+ // and we return the first (and hence most preferred) match? This is of concern if
+ // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
+ for (size_t i = 0; i < samplingRates.size(); i ++) {
+ if ((samplingRates[i] > pickedRate) && (samplingRates[i] <= maxRate)) {
+ pickedRate = samplingRates[i];
+ }
}
}
- return samplingRate;
}
-audio_channel_mask_t AudioPort::pickChannelMask() const
+void AudioPort::pickChannelMask(audio_channel_mask_t &pickedChannelMask,
+ const ChannelsVector &channelMasks) const
{
- // special case for uninitialized dynamic profile
- if (mChannelMasks.size() == 1 && mChannelMasks[0] == 0) {
- return AUDIO_CHANNEL_NONE;
- }
- audio_channel_mask_t channelMask = AUDIO_CHANNEL_NONE;
-
+ pickedChannelMask = AUDIO_CHANNEL_NONE;
// For direct outputs, pick minimum channel count: this helps ensuring that the
// channel count / sampling rate combination chosen will be supported by the connected
// sink
- if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
- (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) {
+ if (isDirectOutput()) {
uint32_t channelCount = UINT_MAX;
- for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+ for (size_t i = 0; i < channelMasks.size(); i ++) {
uint32_t cnlCount;
- if (mUseInChannelMask) {
- cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]);
+ if (useInputChannelMask()) {
+ cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
} else {
- cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]);
+ cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
}
if ((cnlCount < channelCount) && (cnlCount > 0)) {
- channelMask = mChannelMasks[i];
+ pickedChannelMask = channelMasks[i];
channelCount = cnlCount;
}
}
- return channelMask;
- }
+ } else {
+ uint32_t channelCount = 0;
+ uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
- uint32_t channelCount = 0;
- uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
-
- // For mixed output and inputs, use max mixer channel count. Do not
- // limit channel count otherwise
- if (mType != AUDIO_PORT_TYPE_MIX) {
- maxCount = UINT_MAX;
- }
- for (size_t i = 0; i < mChannelMasks.size(); i ++) {
- uint32_t cnlCount;
- if (mUseInChannelMask) {
- cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]);
- } else {
- cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]);
+ // For mixed output and inputs, use max mixer channel count. Do not
+ // limit channel count otherwise
+ if (mType != AUDIO_PORT_TYPE_MIX) {
+ maxCount = UINT_MAX;
}
- if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
- channelMask = mChannelMasks[i];
- channelCount = cnlCount;
+ for (size_t i = 0; i < channelMasks.size(); i ++) {
+ uint32_t cnlCount;
+ if (useInputChannelMask()) {
+ cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
+ } else {
+ cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
+ }
+ if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
+ pickedChannelMask = channelMasks[i];
+ channelCount = cnlCount;
+ }
}
}
- return channelMask;
}
/* format in order of increasing preference */
@@ -672,8 +238,7 @@
AUDIO_FORMAT_PCM_FLOAT,
};
-int AudioPort::compareFormats(audio_format_t format1,
- audio_format_t format2)
+int AudioPort::compareFormats(audio_format_t format1, audio_format_t format2)
{
// NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any
// compressed format and better than any PCM format. This is by design of pickFormat()
@@ -703,36 +268,77 @@
return index1 - index2;
}
-audio_format_t AudioPort::pickFormat() const
+bool AudioPort::isBetterFormatMatch(audio_format_t newFormat,
+ audio_format_t currentFormat,
+ audio_format_t targetFormat)
{
- // special case for uninitialized dynamic profile
- if (mFormats.size() == 1 && mFormats[0] == 0) {
- return AUDIO_FORMAT_DEFAULT;
+ if (newFormat == currentFormat) {
+ return false;
}
+ if (currentFormat == AUDIO_FORMAT_INVALID) {
+ return true;
+ }
+ if (newFormat == targetFormat) {
+ return true;
+ }
+ int currentDiffBytes = (int)audio_bytes_per_sample(targetFormat) -
+ audio_bytes_per_sample(currentFormat);
+ int newDiffBytes = (int)audio_bytes_per_sample(targetFormat) -
+ audio_bytes_per_sample(newFormat);
- audio_format_t format = AUDIO_FORMAT_DEFAULT;
- audio_format_t bestFormat =
- AudioPort::sPcmFormatCompareTable[
- ARRAY_SIZE(AudioPort::sPcmFormatCompareTable) - 1];
- // For mixed output and inputs, use best mixer output format. Do not
- // limit format otherwise
- if ((mType != AUDIO_PORT_TYPE_MIX) ||
- ((mRole == AUDIO_PORT_ROLE_SOURCE) &&
- (((mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) != 0)))) {
+ if (abs(newDiffBytes) < abs(currentDiffBytes)) {
+ return true;
+ } else if (abs(newDiffBytes) == abs(currentDiffBytes)) {
+ return (newDiffBytes >= 0);
+ }
+ return false;
+}
+
+void AudioPort::pickAudioProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format) const
+{
+ format = AUDIO_FORMAT_DEFAULT;
+ samplingRate = 0;
+ channelMask = AUDIO_CHANNEL_NONE;
+
+ // special case for uninitialized dynamic profile
+ if (!mProfiles.hasValidProfile()) {
+ return;
+ }
+ audio_format_t bestFormat = sPcmFormatCompareTable[ARRAY_SIZE(sPcmFormatCompareTable) - 1];
+ // For mixed output and inputs, use best mixer output format.
+ // Do not limit format otherwise
+ if ((mType != AUDIO_PORT_TYPE_MIX) || isDirectOutput()) {
bestFormat = AUDIO_FORMAT_INVALID;
}
- for (size_t i = 0; i < mFormats.size(); i ++) {
- if ((compareFormats(mFormats[i], format) > 0) &&
- (compareFormats(mFormats[i], bestFormat) <= 0)) {
- format = mFormats[i];
+ for (size_t i = 0; i < mProfiles.size(); i ++) {
+ if (!mProfiles[i]->isValid()) {
+ continue;
+ }
+ audio_format_t formatToCompare = mProfiles[i]->getFormat();
+ if ((compareFormats(formatToCompare, format) > 0) &&
+ (compareFormats(formatToCompare, bestFormat) <= 0)) {
+ uint32_t pickedSamplingRate = 0;
+ audio_channel_mask_t pickedChannelMask = AUDIO_CHANNEL_NONE;
+ pickChannelMask(pickedChannelMask, mProfiles[i]->getChannels());
+ pickSamplingRate(pickedSamplingRate, mProfiles[i]->getSampleRates());
+
+ if (formatToCompare != AUDIO_FORMAT_DEFAULT && pickedChannelMask != AUDIO_CHANNEL_NONE
+ && pickedSamplingRate != 0) {
+ format = formatToCompare;
+ channelMask = pickedChannelMask;
+ samplingRate = pickedSamplingRate;
+ // TODO: shall we return on the first one or still trying to pick a better Profile?
+ }
}
}
- return format;
+ ALOGV("%s Port[nm:%s] profile rate=%d, format=%d, channels=%d", __FUNCTION__, mName.string(),
+ samplingRate, channelMask, format);
}
-status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig,
- int index) const
+status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig, int index) const
{
if (index < 0 || (size_t)index >= mGains.size()) {
return BAD_VALUE;
@@ -740,77 +346,27 @@
return mGains[index]->checkConfig(gainConfig);
}
-void AudioPort::dump(int fd, int spaces) const
+void AudioPort::dump(int fd, int spaces, bool verbose) const
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
- if (mName.length() != 0) {
+ if (!mName.isEmpty()) {
snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
result.append(buffer);
+ write(fd, result.string(), result.size());
}
+ if (verbose) {
+ mProfiles.dump(fd, spaces);
- if (mSamplingRates.size() != 0) {
- snprintf(buffer, SIZE, "%*s- sampling rates: ", spaces, "");
- result.append(buffer);
- for (size_t i = 0; i < mSamplingRates.size(); i++) {
- if (i == 0 && mSamplingRates[i] == 0) {
- snprintf(buffer, SIZE, "Dynamic");
- } else {
- snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+ if (mGains.size() != 0) {
+ snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
+ result = buffer;
+ write(fd, result.string(), result.size());
+ for (size_t i = 0; i < mGains.size(); i++) {
+ mGains[i]->dump(fd, spaces + 2, i);
}
- result.append(buffer);
- result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
- }
- result.append("\n");
- }
-
- if (mChannelMasks.size() != 0) {
- snprintf(buffer, SIZE, "%*s- channel masks: ", spaces, "");
- result.append(buffer);
- for (size_t i = 0; i < mChannelMasks.size(); i++) {
- ALOGV("AudioPort::dump mChannelMasks %zu %08x", i, mChannelMasks[i]);
-
- if (i == 0 && mChannelMasks[i] == 0) {
- snprintf(buffer, SIZE, "Dynamic");
- } else {
- snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
- }
- result.append(buffer);
- result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
- }
- result.append("\n");
- }
-
- if (mFormats.size() != 0) {
- snprintf(buffer, SIZE, "%*s- formats: ", spaces, "");
- result.append(buffer);
- for (size_t i = 0; i < mFormats.size(); i++) {
- const char *formatStr = ConfigParsingUtils::enumToString(sFormatNameToEnumTable,
- ARRAY_SIZE(sFormatNameToEnumTable),
- mFormats[i]);
- const bool isEmptyStr = formatStr[0] == 0;
- if (i == 0 && isEmptyStr) {
- snprintf(buffer, SIZE, "Dynamic");
- } else {
- if (isEmptyStr) {
- snprintf(buffer, SIZE, "%#x", mFormats[i]);
- } else {
- snprintf(buffer, SIZE, "%s", formatStr);
- }
- }
- result.append(buffer);
- result.append(i == (mFormats.size() - 1) ? "" : ", ");
- }
- result.append("\n");
- }
- write(fd, result.string(), result.size());
- if (mGains.size() != 0) {
- snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
- write(fd, buffer, strlen(buffer) + 1);
- for (size_t i = 0; i < mGains.size(); i++) {
- mGains[i]->dump(fd, spaces + 2, i);
}
}
}
@@ -830,9 +386,8 @@
mGain.index = -1;
}
-status_t AudioPortConfig::applyAudioPortConfig(
- const struct audio_port_config *config,
- struct audio_port_config *backupConfig)
+status_t AudioPortConfig::applyAudioPortConfig(const struct audio_port_config *config,
+ struct audio_port_config *backupConfig)
{
struct audio_port_config localBackupConfig;
status_t status = NO_ERROR;
@@ -845,25 +400,19 @@
status = NO_INIT;
goto exit;
}
+ status = audioport->checkExactAudioProfile(config->sample_rate,
+ config->channel_mask,
+ config->format);
+ if (status != NO_ERROR) {
+ goto exit;
+ }
if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
- status = audioport->checkExactSamplingRate(config->sample_rate);
- if (status != NO_ERROR) {
- goto exit;
- }
mSamplingRate = config->sample_rate;
}
if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
- status = audioport->checkExactChannelMask(config->channel_mask);
- if (status != NO_ERROR) {
- goto exit;
- }
mChannelMask = config->channel_mask;
}
if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
- status = audioport->checkExactFormat(config->format);
- if (status != NO_ERROR) {
- goto exit;
- }
mFormat = config->format;
}
if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
@@ -911,9 +460,11 @@
} else {
dstConfig->format = AUDIO_FORMAT_INVALID;
}
- if (dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) {
+ sp<AudioPort> audioport = getAudioPort();
+ if ((dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) && audioport != NULL) {
dstConfig->gain = mGain;
- if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)) {
+ if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)
+ && audioport->checkGain(&srcConfig->gain, srcConfig->gain.index) == OK) {
dstConfig->gain = srcConfig->gain;
}
} else {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
new file mode 100644
index 0000000..961072e
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
@@ -0,0 +1,288 @@
+/*
+ * 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 "APM::AudioProfile"
+//#define LOG_NDEBUG 0
+
+#include "AudioProfile.h"
+#include "AudioPort.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+#include <utils/SortedVector.h>
+#include "TypeConverter.h"
+#include <media/AudioResamplerPublic.h>
+#include <algorithm>
+
+namespace android {
+
+status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
+ audio_format_t format) const
+{
+ if (audio_formats_match(format, mFormat) &&
+ (mChannelMasks.isEmpty() || supportsChannels(channelMask)) &&
+ (mSamplingRates.isEmpty() || supportsRate(samplingRate))) {
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+}
+
+template <typename T>
+bool operator == (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+ if (left.size() != right.size()) {
+ return false;
+ }
+ for(size_t index = 0; index < right.size(); index++) {
+ if (left[index] != right[index]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
+{
+ return (left.getFormat() == compareTo.getFormat()) &&
+ (left.getChannels() == compareTo.getChannels()) &&
+ (left.getSampleRates() == compareTo.getSampleRates());
+}
+
+status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
+ uint32_t &updatedSamplingRate) const
+{
+ if (mSamplingRates.isEmpty()) {
+ updatedSamplingRate = samplingRate;
+ return NO_ERROR;
+ }
+ // Search for the closest supported sampling rate that is above (preferred)
+ // or below (acceptable) the desired sampling rate, within a permitted ratio.
+ // The sampling rates are sorted in ascending order.
+ size_t orderOfDesiredRate = mSamplingRates.orderOf(samplingRate);
+
+ // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
+ if (orderOfDesiredRate < mSamplingRates.size()) {
+ uint32_t candidate = mSamplingRates[orderOfDesiredRate];
+ if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
+ updatedSamplingRate = candidate;
+ return NO_ERROR;
+ }
+ }
+ // But if we have to up-sample from a lower sampling rate, that's OK.
+ if (orderOfDesiredRate != 0) {
+ uint32_t candidate = mSamplingRates[orderOfDesiredRate - 1];
+ if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
+ updatedSamplingRate = candidate;
+ return NO_ERROR;
+ }
+ }
+ // leave updatedSamplingRate unmodified
+ return BAD_VALUE;
+}
+
+status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
+ audio_channel_mask_t &updatedChannelMask,
+ audio_port_type_t portType,
+ audio_port_role_t portRole) const
+{
+ if (mChannelMasks.isEmpty()) {
+ updatedChannelMask = channelMask;
+ return NO_ERROR;
+ }
+ const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
+ const bool isIndex = audio_channel_mask_get_representation(channelMask)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX;
+ int bestMatch = 0;
+ for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+ audio_channel_mask_t supported = mChannelMasks[i];
+ if (supported == channelMask) {
+ // Exact matches always taken.
+ updatedChannelMask = channelMask;
+ return NO_ERROR;
+ }
+
+ // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
+ if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
+ // Approximate (best) match:
+ // The match score measures how well the supported channel mask matches the
+ // desired mask, where increasing-is-better.
+ //
+ // TODO: Some tweaks may be needed.
+ // Should be a static function of the data processing library.
+ //
+ // In priority:
+ // match score = 1000 if legacy channel conversion equivalent (always prefer this)
+ // OR
+ // match score += 100 if the channel mask representations match
+ // match score += number of channels matched.
+ //
+ // If there are no matched channels, the mask may still be accepted
+ // but the playback or record will be silent.
+ const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX);
+ int match;
+ if (isIndex && isSupportedIndex) {
+ // index equivalence
+ match = 100 + __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask)
+ & audio_channel_mask_get_bits(supported));
+ } else if (isIndex && !isSupportedIndex) {
+ const uint32_t equivalentBits =
+ (1 << audio_channel_count_from_in_mask(supported)) - 1 ;
+ match = __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask) & equivalentBits);
+ } else if (!isIndex && isSupportedIndex) {
+ const uint32_t equivalentBits =
+ (1 << audio_channel_count_from_in_mask(channelMask)) - 1;
+ match = __builtin_popcount(
+ equivalentBits & audio_channel_mask_get_bits(supported));
+ } else {
+ // positional equivalence
+ match = 100 + __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask)
+ & audio_channel_mask_get_bits(supported));
+ switch (supported) {
+ case AUDIO_CHANNEL_IN_FRONT_BACK:
+ case AUDIO_CHANNEL_IN_STEREO:
+ if (channelMask == AUDIO_CHANNEL_IN_MONO) {
+ match = 1000;
+ }
+ break;
+ case AUDIO_CHANNEL_IN_MONO:
+ if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
+ || channelMask == AUDIO_CHANNEL_IN_STEREO) {
+ match = 1000;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (match > bestMatch) {
+ bestMatch = match;
+ updatedChannelMask = supported;
+ }
+ }
+ }
+ return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
+}
+
+void AudioProfile::dump(int fd, int spaces) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
+ mIsDynamicChannels ? "[dynamic channels]" : "",
+ mIsDynamicRate ? "[dynamic rates]" : "");
+ result.append(buffer);
+ if (mName.length() != 0) {
+ snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
+ result.append(buffer);
+ }
+ std::string formatLiteral;
+ if (FormatConverter::toString(mFormat, formatLiteral)) {
+ snprintf(buffer, SIZE, "%*s- format: %s\n", spaces, "", formatLiteral.c_str());
+ result.append(buffer);
+ }
+ if (!mSamplingRates.isEmpty()) {
+ snprintf(buffer, SIZE, "%*s- sampling rates:", spaces, "");
+ result.append(buffer);
+ for (size_t i = 0; i < mSamplingRates.size(); i++) {
+ snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+ result.append(buffer);
+ result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
+ }
+ result.append("\n");
+ }
+
+ if (!mChannelMasks.isEmpty()) {
+ snprintf(buffer, SIZE, "%*s- channel masks:", spaces, "");
+ result.append(buffer);
+ for (size_t i = 0; i < mChannelMasks.size(); i++) {
+ snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
+ result.append(buffer);
+ result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
+ }
+ result.append("\n");
+ }
+ write(fd, result.string(), result.size());
+}
+
+status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format) const
+{
+ if (isEmpty()) {
+ return NO_ERROR;
+ }
+
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioProfile> profile = itemAt(i);
+ if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+ return BAD_VALUE;
+}
+
+status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format,
+ audio_port_type_t portType,
+ audio_port_role_t portRole) const
+{
+ if (isEmpty()) {
+ return NO_ERROR;
+ }
+
+ const bool checkInexact = // when port is input and format is linear pcm
+ portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
+ && audio_is_linear_pcm(format);
+
+ // iterate from best format to worst format (reverse order)
+ for (ssize_t i = size() - 1; i >= 0 ; --i) {
+ const sp<AudioProfile> profile = itemAt(i);
+ audio_format_t formatToCompare = profile->getFormat();
+ if (formatToCompare == format ||
+ (checkInexact
+ && formatToCompare != AUDIO_FORMAT_DEFAULT
+ && audio_is_linear_pcm(formatToCompare))) {
+ // Compatible profile has been found, checks if this profile has compatible
+ // rate and channels as well
+ audio_channel_mask_t updatedChannels;
+ uint32_t updatedRate;
+ if (profile->checkCompatibleChannelMask(channelMask, updatedChannels,
+ portType, portRole) == NO_ERROR &&
+ profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) {
+ // for inexact checks we take the first linear pcm format due to sorting.
+ format = formatToCompare;
+ channelMask = updatedChannels;
+ samplingRate = updatedRate;
+ return NO_ERROR;
+ }
+ }
+ }
+ return BAD_VALUE;
+}
+
+int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
+ const sp<AudioProfile> *profile2)
+{
+ return AudioPort::compareFormats((*profile1)->getFormat(), (*profile2)->getFormat());
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
new file mode 100644
index 0000000..79ad1f7
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "APM::AudioRoute"
+//#define LOG_NDEBUG 0
+
+#include "AudioRoute.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+
+namespace android
+{
+
+void AudioRoute::dump(int fd, int spaces) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
+ result.append(buffer);
+
+ snprintf(buffer, SIZE, "%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
+ result.append(buffer);
+
+ if (mSources.size() != 0) {
+ snprintf(buffer, SIZE, "%*s- Sources: \n", spaces, "");
+ result.append(buffer);
+ for (size_t i = 0; i < mSources.size(); i++) {
+ snprintf(buffer, SIZE, "%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
+ result.append(buffer);
+ }
+ }
+ result.append("\n");
+
+ write(fd, result.string(), result.size());
+}
+
+}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
new file mode 100644
index 0000000..597c029
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
@@ -0,0 +1,223 @@
+/*
+ * 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 "APM::AudioSession"
+//#define LOG_NDEBUG 0
+
+#include <AudioPolicyInterface.h>
+#include "AudioSession.h"
+#include "AudioGain.h"
+#include "TypeConverter.h"
+#include <cutils/log.h>
+#include <utils/String8.h>
+
+namespace android {
+
+AudioSession::AudioSession(audio_session_t session,
+ audio_source_t inputSource,
+ audio_format_t format,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags,
+ uid_t uid,
+ bool isSoundTrigger,
+ AudioMix* policyMix,
+ AudioPolicyClientInterface *clientInterface) :
+ mSession(session), mInputSource(inputSource),
+ mFormat(format), mSampleRate(sampleRate), mChannelMask(channelMask),
+ mFlags(flags), mUid(uid), mIsSoundTrigger(isSoundTrigger),
+ mOpenCount(1), mActiveCount(0), mPolicyMix(policyMix), mClientInterface(clientInterface)
+{
+}
+
+uint32_t AudioSession::changeOpenCount(int delta)
+{
+ if ((delta + (int)mOpenCount) < 0) {
+ ALOGW("%s invalid delta %d, open count %d",
+ __FUNCTION__, delta, mOpenCount);
+ mOpenCount = (uint32_t)(-delta);
+ }
+ mOpenCount += delta;
+ ALOGV("%s open count %d", __FUNCTION__, mOpenCount);
+ return mOpenCount;
+}
+
+uint32_t AudioSession::changeActiveCount(int delta)
+{
+ const uint32_t oldActiveCount = mActiveCount;
+ if ((delta + (int)mActiveCount) < 0) {
+ ALOGW("%s invalid delta %d, active count %d",
+ __FUNCTION__, delta, mActiveCount);
+ mActiveCount = (uint32_t)(-delta);
+ }
+ mActiveCount += delta;
+ ALOGV("%s active count %d", __FUNCTION__, mActiveCount);
+
+ if ((oldActiveCount == 0) && (mActiveCount > 0)) {
+ // if input maps to a dynamic policy with an activity listener, notify of state change
+ if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ {
+ mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
+ MIX_STATE_MIXING);
+ }
+ mClientInterface->onRecordingConfigurationUpdate(RECORD_CONFIG_EVENT_START,
+ mSession, mInputSource);
+ } else if ((oldActiveCount > 0) && (mActiveCount == 0)) {
+ // if input maps to a dynamic policy with an activity listener, notify of state change
+ if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ {
+ mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
+ MIX_STATE_IDLE);
+ }
+ mClientInterface->onRecordingConfigurationUpdate(RECORD_CONFIG_EVENT_STOP,
+ mSession, mInputSource);
+ }
+
+ return mActiveCount;
+}
+
+bool AudioSession::matches(const sp<AudioSession> &other) const
+{
+ if (other->session() == mSession &&
+ other->inputSource() == mInputSource &&
+ other->format() == mFormat &&
+ other->sampleRate() == mSampleRate &&
+ other->channelMask() == mChannelMask &&
+ other->flags() == mFlags &&
+ other->uid() == mUid) {
+ return true;
+ }
+ return false;
+}
+
+
+status_t AudioSession::dump(int fd, int spaces, int index) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%*sAudio session %d:\n", spaces, "", index+1);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- session: %2d\n", spaces, "", mSession);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mUid);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- input source: %d\n", spaces, "", mInputSource);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- format: %08x\n", spaces, "", mFormat);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- sample: %d\n", spaces, "", mSampleRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- channel mask: %08x\n",
+ spaces, "", mChannelMask);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- is soundtrigger: %s\n",
+ spaces, "", mIsSoundTrigger ? "true" : "false");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- open count: %d\n", spaces, "", mOpenCount);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- active count: %d\n", spaces, "", mActiveCount);
+ result.append(buffer);
+
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioSessionCollection::addSession(audio_session_t session,
+ const sp<AudioSession>& audioSession)
+{
+ ssize_t index = indexOfKey(session);
+
+ if (index >= 0) {
+ ALOGW("addSession() session %d already in", session);
+ return ALREADY_EXISTS;
+ }
+ add(session, audioSession);
+ ALOGV("addSession() session %d client %d source %d",
+ session, audioSession->uid(), audioSession->inputSource());
+ return NO_ERROR;
+}
+
+status_t AudioSessionCollection::removeSession(audio_session_t session)
+{
+ ssize_t index = indexOfKey(session);
+
+ if (index < 0) {
+ ALOGW("removeSession() session %d not in", session);
+ return ALREADY_EXISTS;
+ }
+ ALOGV("removeSession() session %d", session);
+ removeItemsAt(index);
+ return NO_ERROR;
+}
+
+uint32_t AudioSessionCollection::getOpenCount() const
+{
+ uint32_t openCount = 0;
+ for (size_t i = 0; i < size(); i++) {
+ openCount += valueAt(i)->openCount();
+ }
+ return openCount;
+}
+
+AudioSessionCollection AudioSessionCollection::getActiveSessions() const
+{
+ AudioSessionCollection activeSessions;
+ for (size_t i = 0; i < size(); i++) {
+ if (valueAt(i)->activeCount() != 0) {
+ activeSessions.add(valueAt(i)->session(), valueAt(i));
+ }
+ }
+ return activeSessions;
+}
+
+bool AudioSessionCollection::hasActiveSession() const
+{
+ return getActiveSessions().size() != 0;
+}
+
+bool AudioSessionCollection::isSourceActive(audio_source_t source) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioSession> audioSession = valueAt(i);
+ // AUDIO_SOURCE_HOTWORD is equivalent to AUDIO_SOURCE_VOICE_RECOGNITION only if it
+ // corresponds to an active capture triggered by a hardware hotword recognition
+ if (audioSession->activeCount() > 0 &&
+ ((audioSession->inputSource() == source) ||
+ ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
+ (audioSession->inputSource() == AUDIO_SOURCE_HOTWORD) &&
+ audioSession->isSoundTrigger()))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+status_t AudioSessionCollection::dump(int fd, int spaces) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "%*sAudio Sessions:\n", spaces, "");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ valueAt(i)->dump(fd, spaces + 2, i);
+ }
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
new file mode 100644
index 0000000..ba33e57
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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 "APM::AudioSourceDescriptor"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <media/AudioPolicyHelper.h>
+#include <HwModule.h>
+#include <AudioGain.h>
+#include <AudioSourceDescriptor.h>
+#include <DeviceDescriptor.h>
+#include <IOProfile.h>
+#include <AudioOutputDescriptor.h>
+
+namespace android {
+
+status_t AudioSourceDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "mStream: %d\n", audio_attributes_to_stream_type(&mAttributes));
+ result.append(buffer);
+ snprintf(buffer, SIZE, "mDevice:\n");
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ mDevice->dump(fd, 2 , 0);
+ return NO_ERROR;
+}
+
+
+status_t AudioSourceCollection::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\nAudio sources dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "- Source %d dump:\n", keyAt(i));
+ write(fd, buffer, strlen(buffer));
+ valueAt(i)->dump(fd);
+ }
+
+ return NO_ERROR;
+}
+
+}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 89ef045..a3536e5 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -18,139 +18,230 @@
//#define LOG_NDEBUG 0
#include "ConfigParsingUtils.h"
+#include <convert/convert.h>
#include "AudioGain.h"
+#include "IOProfile.h"
+#include "TypeConverter.h"
#include <hardware/audio.h>
#include <utils/Log.h>
#include <cutils/misc.h>
namespace android {
-//static
-uint32_t ConfigParsingUtils::stringToEnum(const struct StringToEnum *table,
- size_t size,
- const char *name)
-{
- for (size_t i = 0; i < size; i++) {
- if (strcmp(table[i].name, name) == 0) {
- ALOGV("stringToEnum() found %s", table[i].name);
- return table[i].value;
- }
- }
- return 0;
-}
-
-//static
-const char *ConfigParsingUtils::enumToString(const struct StringToEnum *table,
- size_t size,
- uint32_t value)
-{
- for (size_t i = 0; i < size; i++) {
- if (table[i].value == value) {
- return table[i].name;
- }
- }
- return "";
-}
-
-//static
-bool ConfigParsingUtils::stringToBool(const char *value)
-{
- return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0));
-}
-
-
// --- audio_policy.conf file parsing
-//static
-uint32_t ConfigParsingUtils::parseOutputFlagNames(char *name)
-{
- uint32_t flag = 0;
- // it is OK to cast name to non const here as we are not going to use it after
- // strtok() modifies it
- char *flagName = strtok(name, "|");
- while (flagName != NULL) {
- if (strlen(flagName) != 0) {
- flag |= ConfigParsingUtils::stringToEnum(sOutputFlagNameToEnumTable,
- ARRAY_SIZE(sOutputFlagNameToEnumTable),
- flagName);
+//static
+void ConfigParsingUtils::loadAudioPortGain(cnode *root, AudioPort &audioPort, int index)
+{
+ cnode *node = root->first_child;
+
+ sp<AudioGain> gain = new AudioGain(index, audioPort.useInputChannelMask());
+
+ while (node) {
+ if (strcmp(node->name, GAIN_MODE) == 0) {
+ gain->setMode(GainModeConverter::maskFromString(node->value));
+ } else if (strcmp(node->name, GAIN_CHANNELS) == 0) {
+ audio_channel_mask_t mask;
+ if (audioPort.useInputChannelMask()) {
+ if (InputChannelConverter::fromString(node->value, mask)) {
+ gain->setChannelMask(mask);
+ }
+ } else {
+ if (OutputChannelConverter::fromString(node->value, mask)) {
+ gain->setChannelMask(mask);
+ }
+ }
+ } else if (strcmp(node->name, GAIN_MIN_VALUE) == 0) {
+ gain->setMinValueInMb(atoi(node->value));
+ } else if (strcmp(node->name, GAIN_MAX_VALUE) == 0) {
+ gain->setMaxValueInMb(atoi(node->value));
+ } else if (strcmp(node->name, GAIN_DEFAULT_VALUE) == 0) {
+ gain->setDefaultValueInMb(atoi(node->value));
+ } else if (strcmp(node->name, GAIN_STEP_VALUE) == 0) {
+ gain->setStepValueInMb(atoi(node->value));
+ } else if (strcmp(node->name, GAIN_MIN_RAMP_MS) == 0) {
+ gain->setMinRampInMs(atoi(node->value));
+ } else if (strcmp(node->name, GAIN_MAX_RAMP_MS) == 0) {
+ gain->setMaxRampInMs(atoi(node->value));
}
- flagName = strtok(NULL, "|");
- }
- //force direct flag if offload flag is set: offloading implies a direct output stream
- // and all common behaviors are driven by checking only the direct flag
- // this should normally be set appropriately in the policy configuration file
- if ((flag & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
- flag |= AUDIO_OUTPUT_FLAG_DIRECT;
+ node = node->next;
}
- return flag;
+ ALOGV("loadGain() adding new gain mode %08x channel mask %08x min mB %d max mB %d",
+ gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
+ gain->getMaxValueInMb());
+
+ if (gain->getMode() == 0) {
+ return;
+ }
+ audioPort.mGains.add(gain);
+}
+
+void ConfigParsingUtils::loadAudioPortGains(cnode *root, AudioPort &audioPort)
+{
+ cnode *node = root->first_child;
+ int index = 0;
+ while (node) {
+ ALOGV("loadGains() loading gain %s", node->name);
+ loadAudioPortGain(node, audioPort, index++);
+ node = node->next;
+ }
}
//static
-uint32_t ConfigParsingUtils::parseInputFlagNames(char *name)
+void ConfigParsingUtils::loadDeviceDescriptorGains(cnode *root, sp<DeviceDescriptor> &deviceDesc)
{
- uint32_t flag = 0;
+ loadAudioPortGains(root, *deviceDesc);
+ if (deviceDesc->mGains.size() > 0) {
+ deviceDesc->mGains[0]->getDefaultConfig(&deviceDesc->mGain);
+ }
+}
- // it is OK to cast name to non const here as we are not going to use it after
- // strtok() modifies it
- char *flagName = strtok(name, "|");
- while (flagName != NULL) {
- if (strlen(flagName) != 0) {
- flag |= stringToEnum(sInputFlagNameToEnumTable,
- ARRAY_SIZE(sInputFlagNameToEnumTable),
- flagName);
+//static
+status_t ConfigParsingUtils::loadHwModuleDevice(cnode *root, DeviceVector &devices)
+{
+ cnode *node = root->first_child;
+
+ audio_devices_t type = AUDIO_DEVICE_NONE;
+ while (node) {
+ if (strcmp(node->name, APM_DEVICE_TYPE) == 0) {
+ DeviceConverter::fromString(node->value, type);
+ break;
}
- flagName = strtok(NULL, "|");
+ node = node->next;
}
- return flag;
+ if (type == AUDIO_DEVICE_NONE ||
+ (!audio_is_input_device(type) && !audio_is_output_device(type))) {
+ ALOGW("loadDevice() bad type %08x", type);
+ return BAD_VALUE;
+ }
+ sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(type, String8(root->name));
+
+ node = root->first_child;
+ while (node) {
+ if (strcmp(node->name, APM_DEVICE_ADDRESS) == 0) {
+ deviceDesc->mAddress = String8((char *)node->value);
+ } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
+ if (audio_is_input_device(type)) {
+ deviceDesc->addAudioProfile(
+ new AudioProfile(gDynamicFormat,
+ inputChannelMasksFromString(node->value),
+ SampleRateVector()));
+ } else {
+ deviceDesc->addAudioProfile(
+ new AudioProfile(gDynamicFormat,
+ outputChannelMasksFromString(node->value),
+ SampleRateVector()));
+ }
+ } else if (strcmp(node->name, GAINS_TAG) == 0) {
+ loadDeviceDescriptorGains(node, deviceDesc);
+ }
+ node = node->next;
+ }
+
+ ALOGV("loadDevice() adding device tag (literal type) %s type %08x address %s",
+ deviceDesc->getTagName().string(), type, deviceDesc->mAddress.string());
+
+ devices.add(deviceDesc);
+ return NO_ERROR;
}
//static
-audio_devices_t ConfigParsingUtils::parseDeviceNames(char *name)
+status_t ConfigParsingUtils::loadHwModuleProfile(cnode *root, sp<HwModule> &module,
+ audio_port_role_t role)
{
- uint32_t device = 0;
+ cnode *node = root->first_child;
- char *devName = strtok(name, "|");
- while (devName != NULL) {
- if (strlen(devName) != 0) {
- device |= stringToEnum(sDeviceTypeToEnumTable,
- ARRAY_SIZE(sDeviceTypeToEnumTable),
- devName);
- }
- devName = strtok(NULL, "|");
- }
- return device;
+ sp<IOProfile> profile = new IOProfile(String8(root->name), role);
+
+ AudioProfileVector audioProfiles;
+ SampleRateVector sampleRates;
+ ChannelsVector channels;
+ FormatVector formats;
+
+ while (node) {
+ if (strcmp(node->name, FORMATS_TAG) == 0 &&
+ strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+ formats = formatsFromString(node->value);
+ } else if (strcmp(node->name, SAMPLING_RATES_TAG) == 0 &&
+ strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+ collectionFromString<SampleRateTraits>(node->value, sampleRates);
+ } else if (strcmp(node->name, CHANNELS_TAG) == 0 &&
+ strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+ if (role == AUDIO_PORT_ROLE_SINK) {
+ channels = inputChannelMasksFromString(node->value);
+ } else {
+ channels = outputChannelMasksFromString(node->value);
+ }
+ } else if (strcmp(node->name, DEVICES_TAG) == 0) {
+ DeviceVector devices;
+ loadDevicesFromTag(node->value, devices, module->getDeclaredDevices());
+ profile->setSupportedDevices(devices);
+ } else if (strcmp(node->name, FLAGS_TAG) == 0) {
+ if (role == AUDIO_PORT_ROLE_SINK) {
+ profile->setFlags(InputFlagConverter::maskFromString(node->value));
+ } else {
+ profile->setFlags(OutputFlagConverter::maskFromString(node->value));
+ }
+ } else if (strcmp(node->name, GAINS_TAG) == 0) {
+ loadAudioPortGains(node, *profile);
+ }
+ node = node->next;
+ }
+ if (formats.isEmpty()) {
+ sp<AudioProfile> profileToAdd = new AudioProfile(gDynamicFormat, channels, sampleRates);
+ profileToAdd->setDynamicFormat(true);
+ profileToAdd->setDynamicChannels(channels.isEmpty());
+ profileToAdd->setDynamicRate(sampleRates.isEmpty());
+ audioProfiles.add(profileToAdd);
+ } else {
+ for (size_t i = 0; i < formats.size(); i++) {
+ // For compatibility reason, for each format, creates a profile with the same
+ // collection of rate and channels.
+ sp<AudioProfile> profileToAdd = new AudioProfile(formats[i], channels, sampleRates);
+ profileToAdd->setDynamicFormat(formats[i] == gDynamicFormat);
+ profileToAdd->setDynamicChannels(channels.isEmpty());
+ profileToAdd->setDynamicRate(sampleRates.isEmpty());
+ audioProfiles.add(profileToAdd);
+ }
+ }
+ profile->setAudioProfiles(audioProfiles);
+ ALOGW_IF(!profile->hasSupportedDevices(), "load%s() invalid supported devices",
+ role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output");
+ if (profile->hasSupportedDevices()) {
+ ALOGV("load%s() adding Supported Devices %04x, mFlags %04x",
+ role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output",
+ profile->getSupportedDevicesType(), profile->getFlags());
+ return module->addProfile(profile);
+ }
+ return BAD_VALUE;
}
//static
-void ConfigParsingUtils::loadHwModule(cnode *root, HwModuleCollection &hwModules,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnable)
+status_t ConfigParsingUtils::loadHwModule(cnode *root, sp<HwModule> &module,
+ AudioPolicyConfig &config)
{
status_t status = NAME_NOT_FOUND;
- cnode *node;
- sp<HwModule> module = new HwModule(root->name);
-
- node = config_find(root, DEVICES_TAG);
+ cnode *node = config_find(root, DEVICES_TAG);
if (node != NULL) {
node = node->first_child;
+ DeviceVector devices;
while (node) {
ALOGV("loadHwModule() loading device %s", node->name);
- status_t tmpStatus = module->loadDevice(node);
+ status_t tmpStatus = loadHwModuleDevice(node, devices);
if (status == NAME_NOT_FOUND || status == NO_ERROR) {
status = tmpStatus;
}
node = node->next;
}
+ module->setDeclaredDevices(devices);
}
node = config_find(root, OUTPUTS_TAG);
if (node != NULL) {
node = node->first_child;
while (node) {
ALOGV("loadHwModule() loading output %s", node->name);
- status_t tmpStatus = module->loadOutput(node);
+ status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SOURCE);
if (status == NAME_NOT_FOUND || status == NO_ERROR) {
status = tmpStatus;
}
@@ -162,27 +253,20 @@
node = node->first_child;
while (node) {
ALOGV("loadHwModule() loading input %s", node->name);
- status_t tmpStatus = module->loadInput(node);
+ status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SINK);
if (status == NAME_NOT_FOUND || status == NO_ERROR) {
status = tmpStatus;
}
node = node->next;
}
}
- loadGlobalConfig(root, module, availableInputDevices, availableOutputDevices,
- defaultOutputDevices, isSpeakerDrcEnable);
-
- if (status == NO_ERROR) {
- hwModules.add(module);
- }
+ loadModuleGlobalConfig(root, module, config);
+ return status;
}
//static
void ConfigParsingUtils::loadHwModules(cnode *root, HwModuleCollection &hwModules,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnabled)
+ AudioPolicyConfig &config)
{
cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
if (node == NULL) {
@@ -192,18 +276,49 @@
node = node->first_child;
while (node) {
ALOGV("loadHwModules() loading module %s", node->name);
- loadHwModule(node, hwModules, availableInputDevices, availableOutputDevices,
- defaultOutputDevices, isSpeakerDrcEnabled);
+ sp<HwModule> module = new HwModule(node->name);
+ if (loadHwModule(node, module, config) == NO_ERROR) {
+ hwModules.add(module);
+ }
node = node->next;
}
}
//static
-void ConfigParsingUtils::loadGlobalConfig(cnode *root, const sp<HwModule>& module,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevice,
- bool &speakerDrcEnabled)
+void ConfigParsingUtils::loadDevicesFromTag(const char *tag, DeviceVector &devices,
+ const DeviceVector &declaredDevices)
+{
+ char *tagLiteral = strndup(tag, strlen(tag));
+ char *devTag = strtok(tagLiteral, "|");
+ while (devTag != NULL) {
+ if (strlen(devTag) != 0) {
+ audio_devices_t type;
+ if (DeviceConverter::fromString(devTag, type)) {
+ uint32_t inBit = type & AUDIO_DEVICE_BIT_IN;
+ type &= ~AUDIO_DEVICE_BIT_IN;
+ while (type) {
+ audio_devices_t singleType =
+ inBit | (1 << (31 - __builtin_clz(type)));
+ type &= ~singleType;
+ sp<DeviceDescriptor> dev = new DeviceDescriptor(singleType);
+ devices.add(dev);
+ }
+ } else {
+ sp<DeviceDescriptor> deviceDesc =
+ declaredDevices.getDeviceFromTagName(String8(devTag));
+ if (deviceDesc != 0) {
+ devices.add(deviceDesc);
+ }
+ }
+ }
+ devTag = strtok(NULL, "|");
+ }
+ free(tagLiteral);
+}
+
+//static
+void ConfigParsingUtils::loadModuleGlobalConfig(cnode *root, const sp<HwModule> &module,
+ AudioPolicyConfig &config)
{
cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
@@ -212,52 +327,68 @@
}
DeviceVector declaredDevices;
if (module != NULL) {
- declaredDevices = module->mDeclaredDevices;
+ declaredDevices = module->getDeclaredDevices();
}
node = node->first_child;
while (node) {
if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
- availableOutputDevices.loadDevicesFromTag((char *)node->value,
- declaredDevices);
+ DeviceVector availableOutputDevices;
+ loadDevicesFromTag(node->value, availableOutputDevices, declaredDevices);
ALOGV("loadGlobalConfig() Attached Output Devices %08x",
availableOutputDevices.types());
+ config.addAvailableOutputDevices(availableOutputDevices);
} else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
- audio_devices_t device = (audio_devices_t)stringToEnum(
- sDeviceTypeToEnumTable,
- ARRAY_SIZE(sDeviceTypeToEnumTable),
- (char *)node->value);
+ audio_devices_t device = AUDIO_DEVICE_NONE;
+ DeviceConverter::fromString(node->value, device);
if (device != AUDIO_DEVICE_NONE) {
- defaultOutputDevice = new DeviceDescriptor(device);
+ sp<DeviceDescriptor> defaultOutputDevice = new DeviceDescriptor(device);
+ config.setDefaultOutputDevice(defaultOutputDevice);
+ ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type());
} else {
ALOGW("loadGlobalConfig() default device not specified");
}
- ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type());
} else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
- availableInputDevices.loadDevicesFromTag((char *)node->value,
- declaredDevices);
+ DeviceVector availableInputDevices;
+ loadDevicesFromTag(node->value, availableInputDevices, declaredDevices);
ALOGV("loadGlobalConfig() Available InputDevices %08x", availableInputDevices.types());
- } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
- speakerDrcEnabled = stringToBool((char *)node->value);
- ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", speakerDrcEnabled);
+ config.addAvailableInputDevices(availableInputDevices);
} else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) {
uint32_t major, minor;
sscanf((char *)node->value, "%u.%u", &major, &minor);
- module->mHalVersion = HARDWARE_DEVICE_API_VERSION(major, minor);
+ module->setHalVersion(HARDWARE_DEVICE_API_VERSION(major, minor));
ALOGV("loadGlobalConfig() mHalVersion = %04x major %u minor %u",
- module->mHalVersion, major, minor);
+ module->getHalVersion(), major, minor);
}
node = node->next;
}
}
//static
-status_t ConfigParsingUtils::loadAudioPolicyConfig(const char *path,
- HwModuleCollection &hwModules,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnabled)
+void ConfigParsingUtils::loadGlobalConfig(cnode *root, AudioPolicyConfig &config,
+ const sp<HwModule>& primaryModule)
+{
+ cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
+
+ if (node == NULL) {
+ return;
+ }
+ node = node->first_child;
+ while (node) {
+ if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
+ bool speakerDrcEnabled;
+ if (utilities::convertTo<std::string, bool>(node->value, speakerDrcEnabled)) {
+ ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", speakerDrcEnabled);
+ config.setSpeakerDrcEnabled(speakerDrcEnabled);
+ }
+ }
+ node = node->next;
+ }
+ loadModuleGlobalConfig(root, primaryModule, config);
+}
+
+//static
+status_t ConfigParsingUtils::loadConfig(const char *path, AudioPolicyConfig &config)
{
cnode *root;
char *data;
@@ -269,13 +400,14 @@
root = config_node("", "");
config_load(root, data);
- loadHwModules(root, hwModules,
- availableInputDevices, availableOutputDevices,
- defaultOutputDevices, isSpeakerDrcEnabled);
- // legacy audio_policy.conf files have one global_configuration section
- loadGlobalConfig(root, hwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY),
- availableInputDevices, availableOutputDevices,
- defaultOutputDevices, isSpeakerDrcEnabled);
+ HwModuleCollection hwModules;
+ loadHwModules(root, hwModules, config);
+
+ // legacy audio_policy.conf files have one global_configuration section, attached to primary.
+ loadGlobalConfig(root, config, hwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY));
+
+ config.setHwModules(hwModules);
+
config_free(root);
free(root);
free(data);
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 1f1fca3..787f53f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -18,19 +18,21 @@
//#define LOG_NDEBUG 0
#include "DeviceDescriptor.h"
+#include "TypeConverter.h"
#include "AudioGain.h"
#include "HwModule.h"
-#include "ConfigParsingUtils.h"
namespace android {
-DeviceDescriptor::DeviceDescriptor(audio_devices_t type) :
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const String8 &tagName) :
AudioPort(String8(""), AUDIO_PORT_TYPE_DEVICE,
audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
AUDIO_PORT_ROLE_SOURCE),
- mTag(""), mAddress(""), mDeviceType(type), mId(0)
+ mAddress(""), mTagName(tagName), mDeviceType(type), mId(0)
{
-
+ if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX || type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) {
+ mAddress = String8("0");
+ }
}
audio_port_handle_t DeviceDescriptor::getId() const
@@ -59,14 +61,6 @@
mChannelMask == other->mChannelMask);
}
-void DeviceDescriptor::loadGains(cnode *root)
-{
- AudioPort::loadGains(root);
- if (mGains.size() > 0) {
- mGains[0]->getDefaultConfig(&mGain);
- }
-}
-
void DeviceVector::refreshTypes()
{
mDeviceTypes = AUDIO_DEVICE_NONE;
@@ -86,6 +80,16 @@
return -1;
}
+void DeviceVector::add(const DeviceVector &devices)
+{
+ for (size_t i = 0; i < devices.size(); i++) {
+ sp<DeviceDescriptor> device = devices.itemAt(i);
+ if (indexOf(device) < 0 && SortedVector::add(device) >= 0) {
+ refreshTypes();
+ }
+ }
+}
+
ssize_t DeviceVector::add(const sp<DeviceDescriptor>& item)
{
ssize_t ret = indexOf(item);
@@ -129,49 +133,6 @@
return devices;
}
-void DeviceVector::loadDevicesFromType(audio_devices_t types)
-{
- DeviceVector deviceList;
-
- uint32_t role_bit = AUDIO_DEVICE_BIT_IN & types;
- types &= ~role_bit;
-
- while (types) {
- uint32_t i = 31 - __builtin_clz(types);
- uint32_t type = 1 << i;
- types &= ~type;
- add(new DeviceDescriptor(type | role_bit));
- }
-}
-
-void DeviceVector::loadDevicesFromTag(char *tag,
- const DeviceVector& declaredDevices)
-{
- char *devTag = strtok(tag, "|");
- while (devTag != NULL) {
- if (strlen(devTag) != 0) {
- audio_devices_t type = ConfigParsingUtils::stringToEnum(sDeviceTypeToEnumTable,
- ARRAY_SIZE(sDeviceTypeToEnumTable),
- devTag);
- if (type != AUDIO_DEVICE_NONE) {
- sp<DeviceDescriptor> dev = new DeviceDescriptor(type);
- if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX ||
- type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) {
- dev->mAddress = String8("0");
- }
- add(dev);
- } else {
- sp<DeviceDescriptor> deviceDesc =
- declaredDevices.getDeviceFromTag(String8(devTag));
- if (deviceDesc != 0) {
- add(deviceDesc);
- }
- }
- }
- devTag = strtok(NULL, "|");
- }
-}
-
sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, String8 address) const
{
sp<DeviceDescriptor> device;
@@ -234,11 +195,11 @@
return devices;
}
-sp<DeviceDescriptor> DeviceVector::getDeviceFromTag(const String8& tag) const
+sp<DeviceDescriptor> DeviceVector::getDeviceFromTagName(const String8 &tagName) const
{
sp<DeviceDescriptor> device;
for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->mTag == tag) {
+ if (itemAt(i)->getTagName() == tagName) {
device = itemAt(i);
break;
}
@@ -246,16 +207,18 @@
return device;
}
-
-status_t DeviceVector::dump(int fd, const String8 &direction) const
+status_t DeviceVector::dump(int fd, const String8 &tag, int spaces, bool verbose) const
{
+ if (isEmpty()) {
+ return NO_ERROR;
+ }
const size_t SIZE = 256;
char buffer[SIZE];
- snprintf(buffer, SIZE, "\n Available %s devices:\n", direction.string());
+ snprintf(buffer, SIZE, "%*s- %s devices:\n", spaces, "", tag.string());
write(fd, buffer, strlen(buffer));
for (size_t i = 0; i < size(); i++) {
- itemAt(i)->dump(fd, 2, i);
+ itemAt(i)->dump(fd, spaces + 2, i, verbose);
}
return NO_ERROR;
}
@@ -303,12 +266,10 @@
void DeviceDescriptor::importAudioPort(const sp<AudioPort> port) {
AudioPort::importAudioPort(port);
- mSamplingRate = port->pickSamplingRate();
- mFormat = port->pickFormat();
- mChannelMask = port->pickChannelMask();
+ port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
}
-status_t DeviceDescriptor::dump(int fd, int spaces, int index) const
+status_t DeviceDescriptor::dump(int fd, int spaces, int index, bool verbose) const
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -320,28 +281,30 @@
snprintf(buffer, SIZE, "%*s- id: %2d\n", spaces, "", mId);
result.append(buffer);
}
- snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "",
- ConfigParsingUtils::enumToString(sDeviceTypeToEnumTable,
- ARRAY_SIZE(sDeviceTypeToEnumTable),
- mDeviceType));
- result.append(buffer);
+ if (!mTagName.isEmpty()) {
+ snprintf(buffer, SIZE, "%*s- tag name: %s\n", spaces, "", mTagName.string());
+ result.append(buffer);
+ }
+ std::string deviceLiteral;
+ if (DeviceConverter::toString(mDeviceType, deviceLiteral)) {
+ snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "", deviceLiteral.c_str());
+ result.append(buffer);
+ }
if (mAddress.size() != 0) {
snprintf(buffer, SIZE, "%*s- address: %-32s\n", spaces, "", mAddress.string());
result.append(buffer);
}
write(fd, result.string(), result.size());
- AudioPort::dump(fd, spaces);
+ AudioPort::dump(fd, spaces, verbose);
return NO_ERROR;
}
void DeviceDescriptor::log() const
{
- ALOGI("Device id:%d type:0x%X:%s, addr:%s",
- mId,
- mDeviceType,
- ConfigParsingUtils::enumToString(
- sDeviceNameToEnumTable, ARRAY_SIZE(sDeviceNameToEnumTable), mDeviceType),
+ std::string device;
+ DeviceConverter::toString(mDeviceType, device);
+ ALOGI("Device id:%d type:0x%X:%s, addr:%s", mId, mDeviceType, device.c_str(),
mAddress.string());
AudioPort::log(" ");
diff --git a/services/audiopolicy/enginedefault/src/Gains.cpp b/services/audiopolicy/common/managerdefinitions/src/Gains.cpp
similarity index 90%
rename from services/audiopolicy/enginedefault/src/Gains.cpp
rename to services/audiopolicy/common/managerdefinitions/src/Gains.cpp
index d06365c..e3fc9a8 100644
--- a/services/audiopolicy/enginedefault/src/Gains.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Gains.cpp
@@ -114,7 +114,7 @@
};
const VolumeCurvePoint *Gains::sVolumeProfiles[AUDIO_STREAM_CNT]
- [Volume::DEVICE_CATEGORY_CNT] = {
+ [DEVICE_CATEGORY_CNT] = {
{ // AUDIO_STREAM_VOICE_CALL
Gains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
Gains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
@@ -197,17 +197,11 @@
};
//static
-float Gains::volIndexToDb(Volume::device_category deviceCategory,
- const StreamDescriptor& streamDesc,
- int indexInUi)
+float Gains::volIndexToDb(const VolumeCurvePoint *curve, int indexMin, int indexMax, int indexInUi)
{
- const VolumeCurvePoint *curve = streamDesc.getVolumeCurvePoint(deviceCategory);
-
// the volume index in the UI is relative to the min and max volume indices for this stream type
- int nbSteps = 1 + curve[Volume::VOLMAX].mIndex -
- curve[Volume::VOLMIN].mIndex;
- int volIdx = (nbSteps * (indexInUi - streamDesc.getVolumeIndexMin())) /
- (streamDesc.getVolumeIndexMax() - streamDesc.getVolumeIndexMin());
+ int nbSteps = 1 + curve[Volume::VOLMAX].mIndex - curve[Volume::VOLMIN].mIndex;
+ int volIdx = (nbSteps * (indexInUi - indexMin)) / (indexMax - indexMin);
// find what part of the curve this index volume belongs to, or if it's out of bounds
int segment = 0;
@@ -241,15 +235,4 @@
return decibels;
}
-
-//static
-float Gains::volIndexToAmpl(Volume::device_category deviceCategory,
- const StreamDescriptor& streamDesc,
- int indexInUi)
-{
- return Volume::DbToAmpl(volIndexToDb(deviceCategory, streamDesc, indexInUi));
-}
-
-
-
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 7e2050b..dd2a60a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -20,190 +20,83 @@
#include "HwModule.h"
#include "IOProfile.h"
#include "AudioGain.h"
-#include "ConfigParsingUtils.h"
-#include "audio_policy_conf.h"
#include <hardware/audio.h>
#include <policy.h>
namespace android {
-HwModule::HwModule(const char *name)
- : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)),
- mHalVersion(AUDIO_DEVICE_API_VERSION_MIN), mHandle(0)
+HwModule::HwModule(const char *name, uint32_t halVersion)
+ : mName(String8(name)),
+ mHandle(0),
+ mHalVersion(halVersion)
{
}
HwModule::~HwModule()
{
for (size_t i = 0; i < mOutputProfiles.size(); i++) {
- mOutputProfiles[i]->mSupportedDevices.clear();
+ mOutputProfiles[i]->clearSupportedDevices();
}
for (size_t i = 0; i < mInputProfiles.size(); i++) {
- mInputProfiles[i]->mSupportedDevices.clear();
+ mInputProfiles[i]->clearSupportedDevices();
}
- free((void *)mName);
-}
-
-status_t HwModule::loadInput(cnode *root)
-{
- cnode *node = root->first_child;
-
- sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SINK);
-
- while (node) {
- if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
- profile->loadSamplingRates((char *)node->value);
- } else if (strcmp(node->name, FORMATS_TAG) == 0) {
- profile->loadFormats((char *)node->value);
- } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
- profile->loadInChannels((char *)node->value);
- } else if (strcmp(node->name, DEVICES_TAG) == 0) {
- profile->mSupportedDevices.loadDevicesFromTag((char *)node->value,
- mDeclaredDevices);
- } else if (strcmp(node->name, FLAGS_TAG) == 0) {
- profile->mFlags = ConfigParsingUtils::parseInputFlagNames((char *)node->value);
- } else if (strcmp(node->name, GAINS_TAG) == 0) {
- profile->loadGains(node);
- }
- node = node->next;
- }
- ALOGW_IF(profile->mSupportedDevices.isEmpty(),
- "loadInput() invalid supported devices");
- ALOGW_IF(profile->mChannelMasks.size() == 0,
- "loadInput() invalid supported channel masks");
- ALOGW_IF(profile->mSamplingRates.size() == 0,
- "loadInput() invalid supported sampling rates");
- ALOGW_IF(profile->mFormats.size() == 0,
- "loadInput() invalid supported formats");
- if (!profile->mSupportedDevices.isEmpty() &&
- (profile->mChannelMasks.size() != 0) &&
- (profile->mSamplingRates.size() != 0) &&
- (profile->mFormats.size() != 0)) {
-
- ALOGV("loadInput() adding input Supported Devices %04x",
- profile->mSupportedDevices.types());
-
- profile->attach(this);
- mInputProfiles.add(profile);
- return NO_ERROR;
- } else {
- return BAD_VALUE;
- }
-}
-
-status_t HwModule::loadOutput(cnode *root)
-{
- cnode *node = root->first_child;
-
- sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SOURCE);
-
- while (node) {
- if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
- profile->loadSamplingRates((char *)node->value);
- } else if (strcmp(node->name, FORMATS_TAG) == 0) {
- profile->loadFormats((char *)node->value);
- } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
- profile->loadOutChannels((char *)node->value);
- } else if (strcmp(node->name, DEVICES_TAG) == 0) {
- profile->mSupportedDevices.loadDevicesFromTag((char *)node->value,
- mDeclaredDevices);
- } else if (strcmp(node->name, FLAGS_TAG) == 0) {
- profile->mFlags = ConfigParsingUtils::parseOutputFlagNames((char *)node->value);
- } else if (strcmp(node->name, GAINS_TAG) == 0) {
- profile->loadGains(node);
- }
- node = node->next;
- }
- ALOGW_IF(profile->mSupportedDevices.isEmpty(),
- "loadOutput() invalid supported devices");
- ALOGW_IF(profile->mChannelMasks.size() == 0,
- "loadOutput() invalid supported channel masks");
- ALOGW_IF(profile->mSamplingRates.size() == 0,
- "loadOutput() invalid supported sampling rates");
- ALOGW_IF(profile->mFormats.size() == 0,
- "loadOutput() invalid supported formats");
- if (!profile->mSupportedDevices.isEmpty() &&
- (profile->mChannelMasks.size() != 0) &&
- (profile->mSamplingRates.size() != 0) &&
- (profile->mFormats.size() != 0)) {
-
- ALOGV("loadOutput() adding output Supported Devices %04x, mFlags %04x",
- profile->mSupportedDevices.types(), profile->mFlags);
- profile->attach(this);
- mOutputProfiles.add(profile);
- return NO_ERROR;
- } else {
- return BAD_VALUE;
- }
-}
-
-status_t HwModule::loadDevice(cnode *root)
-{
- cnode *node = root->first_child;
-
- audio_devices_t type = AUDIO_DEVICE_NONE;
- while (node) {
- if (strcmp(node->name, APM_DEVICE_TYPE) == 0) {
- type = ConfigParsingUtils::parseDeviceNames((char *)node->value);
- break;
- }
- node = node->next;
- }
- if (type == AUDIO_DEVICE_NONE ||
- (!audio_is_input_device(type) && !audio_is_output_device(type))) {
- ALOGW("loadDevice() bad type %08x", type);
- return BAD_VALUE;
- }
- sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(type);
- deviceDesc->mTag = String8(root->name);
-
- node = root->first_child;
- while (node) {
- if (strcmp(node->name, APM_DEVICE_ADDRESS) == 0) {
- deviceDesc->mAddress = String8((char *)node->value);
- } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
- if (audio_is_input_device(type)) {
- deviceDesc->loadInChannels((char *)node->value);
- } else {
- deviceDesc->loadOutChannels((char *)node->value);
- }
- } else if (strcmp(node->name, GAINS_TAG) == 0) {
- deviceDesc->loadGains(node);
- }
- node = node->next;
- }
-
- ALOGV("loadDevice() adding device tag %s type %08x address %s",
- deviceDesc->mTag.string(), type, deviceDesc->mAddress.string());
-
- mDeclaredDevices.add(deviceDesc);
-
- return NO_ERROR;
}
status_t HwModule::addOutputProfile(String8 name, const audio_config_t *config,
- audio_devices_t device, String8 address)
+ audio_devices_t device, String8 address)
{
- sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SOURCE);
+ sp<IOProfile> profile = new OutputProfile(name);
- profile->mSamplingRates.add(config->sample_rate);
- profile->mChannelMasks.add(config->channel_mask);
- profile->mFormats.add(config->format);
+ profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
+ config->sample_rate));
sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
devDesc->mAddress = address;
- profile->mSupportedDevices.add(devDesc);
+ profile->addSupportedDevice(devDesc);
+ return addOutputProfile(profile);
+}
+
+status_t HwModule::addOutputProfile(const sp<IOProfile> &profile)
+{
profile->attach(this);
mOutputProfiles.add(profile);
-
+ mPorts.add(profile);
return NO_ERROR;
}
+status_t HwModule::addInputProfile(const sp<IOProfile> &profile)
+{
+ profile->attach(this);
+ mInputProfiles.add(profile);
+ mPorts.add(profile);
+ return NO_ERROR;
+}
+
+status_t HwModule::addProfile(const sp<IOProfile> &profile)
+{
+ switch (profile->getRole()) {
+ case AUDIO_PORT_ROLE_SOURCE:
+ return addOutputProfile(profile);
+ case AUDIO_PORT_ROLE_SINK:
+ return addInputProfile(profile);
+ case AUDIO_PORT_ROLE_NONE:
+ return BAD_VALUE;
+ }
+ return BAD_VALUE;
+}
+
+void HwModule::setProfiles(const IOProfileCollection &profiles)
+{
+ for (size_t i = 0; i < profiles.size(); i++) {
+ addProfile(profiles[i]);
+ }
+}
+
status_t HwModule::removeOutputProfile(String8 name)
{
for (size_t i = 0; i < mOutputProfiles.size(); i++) {
- if (mOutputProfiles[i]->mName == name) {
+ if (mOutputProfiles[i]->getName() == name) {
mOutputProfiles.removeAt(i);
break;
}
@@ -213,30 +106,26 @@
}
status_t HwModule::addInputProfile(String8 name, const audio_config_t *config,
- audio_devices_t device, String8 address)
+ audio_devices_t device, String8 address)
{
- sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SINK);
-
- profile->mSamplingRates.add(config->sample_rate);
- profile->mChannelMasks.add(config->channel_mask);
- profile->mFormats.add(config->format);
+ sp<IOProfile> profile = new InputProfile(name);
+ profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
+ config->sample_rate));
sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
devDesc->mAddress = address;
- profile->mSupportedDevices.add(devDesc);
+ profile->addSupportedDevice(devDesc);
- ALOGV("addInputProfile() name %s rate %d mask 0x08", name.string(), config->sample_rate, config->channel_mask);
+ ALOGV("addInputProfile() name %s rate %d mask 0x%08x",
+ name.string(), config->sample_rate, config->channel_mask);
- profile->attach(this);
- mInputProfiles.add(profile);
-
- return NO_ERROR;
+ return addInputProfile(profile);
}
status_t HwModule::removeInputProfile(String8 name)
{
for (size_t i = 0; i < mInputProfiles.size(); i++) {
- if (mInputProfiles[i]->mName == name) {
+ if (mInputProfiles[i]->getName() == name) {
mInputProfiles.removeAt(i);
break;
}
@@ -245,6 +134,88 @@
return NO_ERROR;
}
+void HwModule::setDeclaredDevices(const DeviceVector &devices)
+{
+ mDeclaredDevices = devices;
+ for (size_t i = 0; i < devices.size(); i++) {
+ mPorts.add(devices[i]);
+ }
+}
+
+sp<DeviceDescriptor> HwModule::getRouteSinkDevice(const sp<AudioRoute> &route) const
+{
+ sp<DeviceDescriptor> sinkDevice = 0;
+ if (route->getSink()->getType() == AUDIO_PORT_TYPE_DEVICE) {
+ sinkDevice = mDeclaredDevices.getDeviceFromTagName(route->getSink()->getTagName());
+ }
+ return sinkDevice;
+}
+
+DeviceVector HwModule::getRouteSourceDevices(const sp<AudioRoute> &route) const
+{
+ DeviceVector sourceDevices;
+ Vector <sp<AudioPort> > sources = route->getSources();
+ for (size_t i = 0; i < sources.size(); i++) {
+ if (sources[i]->getType() == AUDIO_PORT_TYPE_DEVICE) {
+ sourceDevices.add(mDeclaredDevices.getDeviceFromTagName(sources[i]->getTagName()));
+ }
+ }
+ return sourceDevices;
+}
+
+void HwModule::setRoutes(const AudioRouteVector &routes)
+{
+ mRoutes = routes;
+ // Now updating the streams (aka IOProfile until now) supported devices
+ refreshSupportedDevices();
+}
+
+void HwModule::refreshSupportedDevices()
+{
+ // Now updating the streams (aka IOProfile until now) supported devices
+ for (size_t i = 0; i < mInputProfiles.size(); i++) {
+ sp<IOProfile> stream = mInputProfiles[i];
+ DeviceVector sourceDevices;
+ const AudioRouteVector &routes = stream->getRoutes();
+ for (size_t j = 0; j < routes.size(); j++) {
+ sp<AudioPort> sink = routes[j]->getSink();
+ if (sink == 0 || stream != sink) {
+ ALOGE("%s: Invalid route attached to input stream", __FUNCTION__);
+ continue;
+ }
+ DeviceVector sourceDevicesForRoute = getRouteSourceDevices(routes[j]);
+ if (sourceDevicesForRoute.isEmpty()) {
+ ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+ continue;
+ }
+ sourceDevices.add(sourceDevicesForRoute);
+ }
+ if (sourceDevices.isEmpty()) {
+ ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+ continue;
+ }
+ stream->setSupportedDevices(sourceDevices);
+ }
+ for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+ sp<IOProfile> stream = mOutputProfiles[i];
+ DeviceVector sinkDevices;
+ const AudioRouteVector &routes = stream->getRoutes();
+ for (size_t j = 0; j < routes.size(); j++) {
+ sp<AudioPort> source = routes[j]->getSources().findByTagName(stream->getTagName());
+ if (source == 0 || stream != source) {
+ ALOGE("%s: Invalid route attached to output stream", __FUNCTION__);
+ continue;
+ }
+ sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(routes[j]);
+ if (sinkDevice == 0) {
+ ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().string());
+ continue;
+ }
+ sinkDevices.add(sinkDevice);
+ }
+ stream->setSupportedDevices(sinkDevices);
+ }
+}
void HwModule::dump(int fd)
{
@@ -252,7 +223,7 @@
char buffer[SIZE];
String8 result;
- snprintf(buffer, SIZE, " - name: %s\n", mName);
+ snprintf(buffer, SIZE, " - name: %s\n", getName());
result.append(buffer);
snprintf(buffer, SIZE, " - handle: %d\n", mHandle);
result.append(buffer);
@@ -275,12 +246,8 @@
mInputProfiles[i]->dump(fd);
}
}
- if (mDeclaredDevices.size()) {
- write(fd, " - devices:\n", strlen(" - devices:\n"));
- for (size_t i = 0; i < mDeclaredDevices.size(); i++) {
- mDeclaredDevices[i]->dump(fd, 4, i);
- }
- }
+ mDeclaredDevices.dump(fd, String8("Declared"), 2, true);
+ mRoutes.dump(fd, 2);
}
sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
@@ -289,7 +256,7 @@
for (size_t i = 0; i < size(); i++)
{
- if (strcmp(itemAt(i)->mName, name) == 0) {
+ if (strcmp(itemAt(i)->getName(), name) == 0) {
return itemAt(i);
}
}
@@ -302,20 +269,19 @@
sp <HwModule> module;
for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->mHandle == 0) {
+ if (itemAt(i)->getHandle() == 0) {
continue;
}
if (audio_is_output_device(device)) {
for (size_t j = 0; j < itemAt(i)->mOutputProfiles.size(); j++)
{
- if (itemAt(i)->mOutputProfiles[j]->mSupportedDevices.types() & device) {
+ if (itemAt(i)->mOutputProfiles[j]->supportDevice(device)) {
return itemAt(i);
}
}
} else {
for (size_t j = 0; j < itemAt(i)->mInputProfiles.size(); j++) {
- if (itemAt(i)->mInputProfiles[j]->mSupportedDevices.types() &
- device & ~AUDIO_DEVICE_BIT_IN) {
+ if (itemAt(i)->mInputProfiles[j]->supportDevice(device)) {
return itemAt(i);
}
}
@@ -340,19 +306,20 @@
continue;
}
DeviceVector deviceList =
- hwModule->mDeclaredDevices.getDevicesFromTypeAddr(device, address);
+ hwModule->getDeclaredDevices().getDevicesFromTypeAddr(device, address);
if (!deviceList.isEmpty()) {
return deviceList.itemAt(0);
}
- deviceList = hwModule->mDeclaredDevices.getDevicesFromType(device);
+ deviceList = hwModule->getDeclaredDevices().getDevicesFromType(device);
if (!deviceList.isEmpty()) {
+ deviceList.itemAt(0)->setName(String8(device_name));
+ deviceList.itemAt(0)->mAddress = address;
return deviceList.itemAt(0);
}
}
- sp<DeviceDescriptor> devDesc =
- new DeviceDescriptor(device);
- devDesc->mName = device_name;
+ sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
+ devDesc->setName(String8(device_name));
devDesc->mAddress = address;
return devDesc;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index 7b6d51d..204eb04 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -20,18 +20,10 @@
#include "IOProfile.h"
#include "HwModule.h"
#include "AudioGain.h"
+#include "TypeConverter.h"
namespace android {
-IOProfile::IOProfile(const String8& name, audio_port_role_t role)
- : AudioPort(name, AUDIO_PORT_TYPE_MIX, role)
-{
-}
-
-IOProfile::~IOProfile()
-{
-}
-
// checks if the IO profile is compatible with specified parameters.
// Sampling rate, format and channel mask must be specified in order to
// get a valid a match
@@ -45,8 +37,10 @@
audio_channel_mask_t *updatedChannelMask,
uint32_t flags) const
{
- const bool isPlaybackThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SOURCE;
- const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
+ const bool isPlaybackThread =
+ getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
+ const bool isRecordThread =
+ getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
ALOG_ASSERT(isPlaybackThread != isRecordThread);
@@ -61,47 +55,35 @@
}
}
- if (samplingRate == 0) {
- return false;
- }
- uint32_t myUpdatedSamplingRate = samplingRate;
- if (isPlaybackThread && checkExactSamplingRate(samplingRate) != NO_ERROR) {
- return false;
- }
- if (isRecordThread && checkCompatibleSamplingRate(samplingRate, &myUpdatedSamplingRate) !=
- NO_ERROR) {
+ if (samplingRate == 0 || !audio_is_valid_format(format) ||
+ (isPlaybackThread && (!audio_is_output_channel(channelMask))) ||
+ (isRecordThread && (!audio_is_input_channel(channelMask)))) {
return false;
}
- if (!audio_is_valid_format(format)) {
- return false;
- }
- if (isPlaybackThread && checkExactFormat(format) != NO_ERROR) {
- return false;
- }
audio_format_t myUpdatedFormat = format;
- if (isRecordThread && checkCompatibleFormat(format, &myUpdatedFormat) != NO_ERROR) {
- return false;
- }
-
- if (isPlaybackThread && (!audio_is_output_channel(channelMask) ||
- checkExactChannelMask(channelMask) != NO_ERROR)) {
- return false;
- }
audio_channel_mask_t myUpdatedChannelMask = channelMask;
- if (isRecordThread && (!audio_is_input_channel(channelMask) ||
- checkCompatibleChannelMask(channelMask, &myUpdatedChannelMask) != NO_ERROR)) {
- return false;
+ uint32_t myUpdatedSamplingRate = samplingRate;
+ if (isRecordThread)
+ {
+ if (checkCompatibleAudioProfile(
+ myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) != NO_ERROR) {
+ return false;
+ }
+ } else {
+ if (checkExactAudioProfile(samplingRate, channelMask, format) != NO_ERROR) {
+ return false;
+ }
}
- if (isPlaybackThread && (mFlags & flags) != flags) {
+ if (isPlaybackThread && (getFlags() & flags) != flags) {
return false;
}
// The only input flag that is allowed to be different is the fast flag.
// An existing fast stream is compatible with a normal track request.
// An existing normal stream is compatible with a fast track request,
// but the fast request will be denied by AudioFlinger and converted to normal track.
- if (isRecordThread && ((mFlags ^ flags) &
+ if (isRecordThread && ((getFlags() ^ flags) &
~AUDIO_INPUT_FLAG_FAST)) {
return false;
}
@@ -126,39 +108,15 @@
AudioPort::dump(fd, 4);
- snprintf(buffer, SIZE, " - flags: 0x%04x\n", mFlags);
- result.append(buffer);
- snprintf(buffer, SIZE, " - devices:\n");
+ snprintf(buffer, SIZE, " - flags: 0x%04x\n", getFlags());
result.append(buffer);
write(fd, result.string(), result.size());
- for (size_t i = 0; i < mSupportedDevices.size(); i++) {
- mSupportedDevices[i]->dump(fd, 6, i);
- }
+ mSupportedDevices.dump(fd, String8("Supported"), 4, false);
}
void IOProfile::log()
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- ALOGV(" - sampling rates: ");
- for (size_t i = 0; i < mSamplingRates.size(); i++) {
- ALOGV(" %d", mSamplingRates[i]);
- }
-
- ALOGV(" - channel masks: ");
- for (size_t i = 0; i < mChannelMasks.size(); i++) {
- ALOGV(" 0x%04x", mChannelMasks[i]);
- }
-
- ALOGV(" - formats: ");
- for (size_t i = 0; i < mFormats.size(); i++) {
- ALOGV(" 0x%08x", mFormats[i]);
- }
-
- ALOGV(" - devices: 0x%04x\n", mSupportedDevices.types());
- ALOGV(" - flags: 0x%04x\n", mFlags);
+ // @TODO: forward log to AudioPort
}
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
new file mode 100644
index 0000000..3e5bb7d
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -0,0 +1,641 @@
+/*
+ * 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 "APM::Serializer"
+//#define LOG_NDEBUG 0
+
+#include "Serializer.h"
+#include <convert/convert.h>
+#include "TypeConverter.h"
+#include <libxml/parser.h>
+#include <libxml/xinclude.h>
+#include <string>
+#include <sstream>
+#include <istream>
+
+using std::string;
+
+namespace android {
+
+string getXmlAttribute(const xmlNode *cur, const char *attribute)
+{
+ xmlChar *xmlValue = xmlGetProp(cur, (const xmlChar*)attribute);
+ if (xmlValue == NULL) {
+ return "";
+ }
+ string value((const char*)xmlValue);
+ xmlFree(xmlValue);
+ return value;
+}
+
+using utilities::convertTo;
+
+const char *const PolicySerializer::rootName = "audioPolicyConfiguration";
+const char *const PolicySerializer::versionAttribute = "version";
+const uint32_t PolicySerializer::gMajor = 1;
+const uint32_t PolicySerializer::gMinor = 0;
+static const char *const gReferenceElementName = "reference";
+static const char *const gReferenceAttributeName = "name";
+
+template <class Trait>
+static void getReference(const _xmlNode *root, const _xmlNode *&refNode, const string &refName)
+{
+ const _xmlNode *col = root;
+ while (col != NULL) {
+ if (!xmlStrcmp(col->name, (const xmlChar *)Trait::collectionTag)) {
+ const xmlNode *cur = col->children;
+ while (cur != NULL) {
+ if ((!xmlStrcmp(cur->name, (const xmlChar *)gReferenceElementName))) {
+ string name = getXmlAttribute(cur, gReferenceAttributeName);
+ if (refName == name) {
+ refNode = cur;
+ return;
+ }
+ }
+ cur = cur->next;
+ }
+ }
+ col = col->next;
+ }
+ return;
+}
+
+template <class Trait>
+static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
+ typename Trait::Collection &collection,
+ typename Trait::PtrSerializingCtx serializingContext)
+{
+ const xmlNode *root = cur->xmlChildrenNode;
+ while (root != NULL) {
+ if (xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag) &&
+ xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
+ root = root->next;
+ continue;
+ }
+ const xmlNode *child = root;
+ if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {
+ child = child->xmlChildrenNode;
+ }
+ while (child != NULL) {
+ if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
+ typename Trait::PtrElement element;
+ status_t status = Trait::deserialize(doc, child, element, serializingContext);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ if (collection.add(element) < 0) {
+ ALOGE("%s: could not add element to %s collection", __FUNCTION__,
+ Trait::collectionTag);
+ }
+ }
+ child = child->next;
+ }
+ if (!xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
+ return NO_ERROR;
+ }
+ root = root->next;
+ }
+ return NO_ERROR;
+}
+
+const char *const AudioGainTraits::tag = "gain";
+const char *const AudioGainTraits::collectionTag = "gains";
+
+const char AudioGainTraits::Attributes::mode[] = "mode";
+const char AudioGainTraits::Attributes::channelMask[] = "channel_mask";
+const char AudioGainTraits::Attributes::minValueMB[] = "minValueMB";
+const char AudioGainTraits::Attributes::maxValueMB[] = "maxValueMB";
+const char AudioGainTraits::Attributes::defaultValueMB[] = "defaultValueMB";
+const char AudioGainTraits::Attributes::stepValueMB[] = "stepValueMB";
+const char AudioGainTraits::Attributes::minRampMs[] = "minRampMs";
+const char AudioGainTraits::Attributes::maxRampMs[] = "maxRampMs";
+
+status_t AudioGainTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &gain,
+ PtrSerializingCtx /*serializingContext*/)
+{
+ static uint32_t index = 0;
+ gain = new Element(index++, true);
+
+ string mode = getXmlAttribute(root, Attributes::mode);
+ if (!mode.empty()) {
+ gain->setMode(GainModeConverter::maskFromString(mode));
+ }
+
+ string channelsLiteral = getXmlAttribute(root, Attributes::channelMask);
+ if (!channelsLiteral.empty()) {
+ gain->setChannelMask(channelMaskFromString(channelsLiteral));
+ }
+
+ string minValueMBLiteral = getXmlAttribute(root, Attributes::minValueMB);
+ uint32_t minValueMB;
+ if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
+ gain->setMinValueInMb(minValueMB);
+ }
+
+ string maxValueMBLiteral = getXmlAttribute(root, Attributes::maxValueMB);
+ uint32_t maxValueMB;
+ if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
+ gain->setMaxValueInMb(maxValueMB);
+ }
+
+ string defaultValueMBLiteral = getXmlAttribute(root, Attributes::defaultValueMB);
+ uint32_t defaultValueMB;
+ if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
+ gain->setDefaultValueInMb(defaultValueMB);
+ }
+
+ string stepValueMBLiteral = getXmlAttribute(root, Attributes::stepValueMB);
+ uint32_t stepValueMB;
+ if (!stepValueMBLiteral.empty() && convertTo(stepValueMBLiteral, stepValueMB)) {
+ gain->setStepValueInMb(stepValueMB);
+ }
+
+ string minRampMsLiteral = getXmlAttribute(root, Attributes::minRampMs);
+ uint32_t minRampMs;
+ if (!minRampMsLiteral.empty() && convertTo(minRampMsLiteral, minRampMs)) {
+ gain->setMinRampInMs(minRampMs);
+ }
+
+ string maxRampMsLiteral = getXmlAttribute(root, Attributes::maxRampMs);
+ uint32_t maxRampMs;
+ if (!maxRampMsLiteral.empty() && convertTo(maxRampMsLiteral, maxRampMs)) {
+ gain->setMaxRampInMs(maxRampMs);
+ }
+ ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d", __FUNCTION__,
+ gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
+ gain->getMaxValueInMb());
+
+ if (gain->getMode() == 0) {
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+}
+
+const char *const AudioProfileTraits::collectionTag = "profiles";
+const char *const AudioProfileTraits::tag = "profile";
+
+const char AudioProfileTraits::Attributes::name[] = "name";
+const char AudioProfileTraits::Attributes::samplingRates[] = "samplingRates";
+const char AudioProfileTraits::Attributes::format[] = "format";
+const char AudioProfileTraits::Attributes::channelMasks[] = "channelMasks";
+
+status_t AudioProfileTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &profile,
+ PtrSerializingCtx /*serializingContext*/)
+{
+ string samplingRates = getXmlAttribute(root, Attributes::samplingRates);
+ string format = getXmlAttribute(root, Attributes::format);
+ string channels = getXmlAttribute(root, Attributes::channelMasks);
+
+ profile = new Element(formatFromString(format), channelMasksFromString(channels, ","),
+ samplingRatesFromString(samplingRates, ","));
+
+ profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
+ profile->setDynamicChannels(profile->getChannels().isEmpty());
+ profile->setDynamicRate(profile->getSampleRates().isEmpty());
+
+ return NO_ERROR;
+}
+
+
+const char *const MixPortTraits::collectionTag = "mixPorts";
+const char *const MixPortTraits::tag = "mixPort";
+
+const char MixPortTraits::Attributes::name[] = "name";
+const char MixPortTraits::Attributes::role[] = "role";
+const char MixPortTraits::Attributes::flags[] = "flags";
+
+status_t MixPortTraits::deserialize(_xmlDoc *doc, const _xmlNode *child, PtrElement &mixPort,
+ PtrSerializingCtx /*serializingContext*/)
+{
+ string name = getXmlAttribute(child, Attributes::name);
+ if (name.empty()) {
+ ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
+ return BAD_VALUE;
+ }
+ ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
+ string role = getXmlAttribute(child, Attributes::role);
+ if (role.empty()) {
+ ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
+ return BAD_VALUE;
+ }
+ ALOGV("%s: Role=%s", __FUNCTION__, role.c_str());
+ audio_port_role_t portRole = role == "source" ? AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
+
+ mixPort = new Element(String8(name.c_str()), portRole);
+
+ AudioProfileTraits::Collection profiles;
+ deserializeCollection<AudioProfileTraits>(doc, child, profiles, NULL);
+ if (profiles.isEmpty()) {
+ sp <AudioProfile> dynamicProfile = new AudioProfile(gDynamicFormat,
+ ChannelsVector(), SampleRateVector());
+ dynamicProfile->setDynamicFormat(true);
+ dynamicProfile->setDynamicChannels(true);
+ dynamicProfile->setDynamicRate(true);
+ profiles.add(dynamicProfile);
+ }
+ mixPort->setAudioProfiles(profiles);
+
+ string flags = getXmlAttribute(child, Attributes::flags);
+ if (!flags.empty()) {
+ // Source role
+ if (portRole == AUDIO_PORT_ROLE_SOURCE) {
+ mixPort->setFlags(OutputFlagConverter::maskFromString(flags));
+ } else {
+ // Sink role
+ mixPort->setFlags(InputFlagConverter::maskFromString(flags));
+ }
+ }
+ // Deserialize children
+ AudioGainTraits::Collection gains;
+ deserializeCollection<AudioGainTraits>(doc, child, gains, NULL);
+ mixPort->setGains(gains);
+
+ return NO_ERROR;
+}
+
+const char *const DevicePortTraits::tag = "devicePort";
+const char *const DevicePortTraits::collectionTag = "devicePorts";
+
+const char DevicePortTraits::Attributes::tagName[] = "tagName";
+const char DevicePortTraits::Attributes::type[] = "type";
+const char DevicePortTraits::Attributes::role[] = "role";
+const char DevicePortTraits::Attributes::address[] = "address";
+const char DevicePortTraits::Attributes::roleSource[] = "source";
+
+status_t DevicePortTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &deviceDesc,
+ PtrSerializingCtx /*serializingContext*/)
+{
+ string name = getXmlAttribute(root, Attributes::tagName);
+ if (name.empty()) {
+ ALOGE("%s: No %s found", __FUNCTION__, Attributes::tagName);
+ return BAD_VALUE;
+ }
+ ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::tagName, name.c_str());
+ string typeName = getXmlAttribute(root, Attributes::type);
+ if (typeName.empty()) {
+ ALOGE("%s: no type for %s", __FUNCTION__, name.c_str());
+ return BAD_VALUE;
+ }
+ ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, typeName.c_str());
+ string role = getXmlAttribute(root, Attributes::role);
+ if (role.empty()) {
+ ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
+ return BAD_VALUE;
+ }
+ ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::role, role.c_str());
+ audio_port_role_t portRole = (role == Attributes::roleSource) ?
+ AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
+
+ audio_devices_t type = AUDIO_DEVICE_NONE;
+ if (!DeviceConverter::fromString(typeName, type) ||
+ (!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
+ (!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
+ ALOGW("%s: bad type %08x", __FUNCTION__, type);
+ return BAD_VALUE;
+ }
+ deviceDesc = new Element(type, String8(name.c_str()));
+
+ string address = getXmlAttribute(root, Attributes::address);
+ if (!address.empty()) {
+ ALOGV("%s: address=%s for %s", __FUNCTION__, address.c_str(), name.c_str());
+ deviceDesc->mAddress = String8(address.c_str());
+ }
+
+ AudioProfileTraits::Collection profiles;
+ deserializeCollection<AudioProfileTraits>(doc, root, profiles, NULL);
+ if (profiles.isEmpty()) {
+ sp <AudioProfile> dynamicProfile = new AudioProfile(gDynamicFormat,
+ ChannelsVector(), SampleRateVector());
+ dynamicProfile->setDynamicFormat(true);
+ dynamicProfile->setDynamicChannels(true);
+ dynamicProfile->setDynamicRate(true);
+ profiles.add(dynamicProfile);
+ }
+ deviceDesc->setAudioProfiles(profiles);
+
+ // Deserialize AudioGain children
+ deserializeCollection<AudioGainTraits>(doc, root, deviceDesc->mGains, NULL);
+ ALOGV("%s: adding device tag %s type %08x address %s", __FUNCTION__,
+ deviceDesc->getName().string(), type, deviceDesc->mAddress.string());
+ return NO_ERROR;
+}
+
+const char *const RouteTraits::tag = "route";
+const char *const RouteTraits::collectionTag = "routes";
+
+const char RouteTraits::Attributes::type[] = "type";
+const char RouteTraits::Attributes::typeMix[] = "mix";
+const char RouteTraits::Attributes::sink[] = "sink";
+const char RouteTraits::Attributes::sources[] = "sources";
+
+
+status_t RouteTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &element,
+ PtrSerializingCtx ctx)
+{
+ string type = getXmlAttribute(root, Attributes::type);
+ if (type.empty()) {
+ ALOGE("%s: No %s found", __FUNCTION__, Attributes::type);
+ return BAD_VALUE;
+ }
+ audio_route_type_t routeType = (type == Attributes::typeMix) ?
+ AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;
+
+ ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, type.c_str());
+ element = new Element(routeType);
+
+ string sinkAttr = getXmlAttribute(root, Attributes::sink);
+ if (sinkAttr.empty()) {
+ ALOGE("%s: No %s found", __FUNCTION__, Attributes::sink);
+ return BAD_VALUE;
+ }
+ // Convert Sink name to port pointer
+ sp<AudioPort> sink = ctx->findPortByTagName(String8(sinkAttr.c_str()));
+ if (sink == NULL) {
+ ALOGE("%s: no sink found with name=%s", __FUNCTION__, sinkAttr.c_str());
+ return BAD_VALUE;
+ }
+ element->setSink(sink);
+
+ string sourcesAttr = getXmlAttribute(root, Attributes::sources);
+ if (sourcesAttr.empty()) {
+ ALOGE("%s: No %s found", __FUNCTION__, Attributes::sources);
+ return BAD_VALUE;
+ }
+ // Tokenize and Convert Sources name to port pointer
+ AudioPortVector sources;
+ char *sourcesLiteral = strndup(sourcesAttr.c_str(), strlen(sourcesAttr.c_str()));
+ char *devTag = strtok(sourcesLiteral, ",");
+ while (devTag != NULL) {
+ if (strlen(devTag) != 0) {
+ sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
+ if (source == NULL) {
+ ALOGE("%s: no source found with name=%s", __FUNCTION__, devTag);
+ return BAD_VALUE;
+ }
+ sources.add(source);
+ }
+ devTag = strtok(NULL, ",");
+ }
+ free(sourcesLiteral);
+
+ sink->addRoute(element);
+ for (size_t i = 0; i < sources.size(); i++) {
+ sp<AudioPort> source = sources.itemAt(i);
+ source->addRoute(element);
+ }
+ element->setSources(sources);
+ return NO_ERROR;
+}
+
+const char *const ModuleTraits::childAttachedDevicesTag = "attachedDevices";
+const char *const ModuleTraits::childAttachedDeviceTag = "item";
+const char *const ModuleTraits::childDefaultOutputDeviceTag = "defaultOutputDevice";
+
+const char *const ModuleTraits::tag = "module";
+const char *const ModuleTraits::collectionTag = "modules";
+
+const char ModuleTraits::Attributes::name[] = "name";
+const char ModuleTraits::Attributes::version[] = "halVersion";
+
+status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module,
+ PtrSerializingCtx ctx)
+{
+ string name = getXmlAttribute(root, Attributes::name);
+ if (name.empty()) {
+ ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
+ return BAD_VALUE;
+ }
+ uint32_t version = AUDIO_DEVICE_API_VERSION_MIN;
+ string versionLiteral = getXmlAttribute(root, Attributes::version);
+ if (!versionLiteral.empty()) {
+ uint32_t major, minor;
+ sscanf(versionLiteral.c_str(), "%u.%u", &major, &minor);
+ version = HARDWARE_DEVICE_API_VERSION(major, minor);
+ ALOGV("%s: mHalVersion = %04x major %u minor %u", __FUNCTION__,
+ version, major, minor);
+ }
+
+ ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
+
+ module = new Element(name.c_str(), version);
+
+ // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
+ MixPortTraits::Collection mixPorts;
+ deserializeCollection<MixPortTraits>(doc, root, mixPorts, NULL);
+ module->setProfiles(mixPorts);
+
+ DevicePortTraits::Collection devicePorts;
+ deserializeCollection<DevicePortTraits>(doc, root, devicePorts, NULL);
+ module->setDeclaredDevices(devicePorts);
+
+ RouteTraits::Collection routes;
+ deserializeCollection<RouteTraits>(doc, root, routes, module.get());
+ module->setRoutes(routes);
+
+ const xmlNode *children = root->xmlChildrenNode;
+ while (children != NULL) {
+ if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
+ ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
+ const xmlNode *child = children->xmlChildrenNode;
+ while (child != NULL) {
+ if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
+ xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
+ if (attachedDevice != NULL) {
+ ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,
+ (const char*)attachedDevice);
+ sp<DeviceDescriptor> device =
+ module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
+ ctx->addAvailableDevice(device);
+ xmlFree(attachedDevice);
+ }
+ }
+ child = child->next;
+ }
+ }
+ if (!xmlStrcmp(children->name, (const xmlChar *)childDefaultOutputDeviceTag)) {
+ xmlChar *defaultOutputDevice = xmlNodeListGetString(doc, children->xmlChildrenNode, 1);;
+ if (defaultOutputDevice != NULL) {
+ ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childDefaultOutputDeviceTag,
+ (const char*)defaultOutputDevice);
+ sp<DeviceDescriptor> device =
+ module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)defaultOutputDevice));
+ if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
+ ctx->setDefaultOutputDevice(device);
+ ALOGV("%s: default is %08x", __FUNCTION__, ctx->getDefaultOutputDevice()->type());
+ }
+ xmlFree(defaultOutputDevice);
+ }
+ }
+ children = children->next;
+ }
+ return NO_ERROR;
+}
+
+const char *const GlobalConfigTraits::tag = "globalConfiguration";
+
+const char GlobalConfigTraits::Attributes::speakerDrcEnabled[] = "speaker_drc_enabled";
+
+
+status_t GlobalConfigTraits::deserialize(const xmlNode *cur, AudioPolicyConfig &config)
+{
+ const xmlNode *root = cur->xmlChildrenNode;
+ while (root != NULL) {
+ if (!xmlStrcmp(root->name, (const xmlChar *)tag)) {
+ string speakerDrcEnabled =
+ getXmlAttribute(root, Attributes::speakerDrcEnabled);
+ bool isSpeakerDrcEnabled;
+ if (!speakerDrcEnabled.empty() &&
+ convertTo<string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
+ config.setSpeakerDrcEnabled(isSpeakerDrcEnabled);
+ }
+ return NO_ERROR;
+ }
+ root = root->next;
+ }
+ return NO_ERROR;
+}
+
+
+const char *const VolumeTraits::tag = "volume";
+const char *const VolumeTraits::collectionTag = "volumes";
+const char *const VolumeTraits::volumePointTag = "point";
+
+const char VolumeTraits::Attributes::stream[] = "stream";
+const char VolumeTraits::Attributes::deviceCategory[] = "deviceCategory";
+const char VolumeTraits::Attributes::reference[] = "ref";
+
+status_t VolumeTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+ PtrSerializingCtx /*serializingContext*/)
+{
+ string streamTypeLiteral = getXmlAttribute(root, Attributes::stream);
+ if (streamTypeLiteral.empty()) {
+ ALOGE("%s: No %s found", __FUNCTION__, Attributes::stream);
+ return BAD_VALUE;
+ }
+ audio_stream_type_t streamType;
+ if (!StreamTypeConverter::fromString(streamTypeLiteral, streamType)) {
+ ALOGE("%s: Invalid %s", __FUNCTION__, Attributes::stream);
+ return BAD_VALUE;
+ }
+ string deviceCategoryLiteral = getXmlAttribute(root, Attributes::deviceCategory);
+ if (deviceCategoryLiteral.empty()) {
+ ALOGE("%s: No %s found", __FUNCTION__, Attributes::deviceCategory);
+ return BAD_VALUE;
+ }
+ device_category deviceCategory;
+ if (!DeviceCategoryConverter::fromString(deviceCategoryLiteral, deviceCategory)) {
+ ALOGE("%s: Invalid %s=%s", __FUNCTION__, Attributes::deviceCategory,
+ deviceCategoryLiteral.c_str());
+ return BAD_VALUE;
+ }
+
+ string referenceName = getXmlAttribute(root, Attributes::reference);
+ const _xmlNode *ref = NULL;
+ if (!referenceName.empty()) {
+ getReference<VolumeTraits>(root->parent, ref, referenceName);
+ if (ref == NULL) {
+ ALOGE("%s: No reference Ptr found for %s", __FUNCTION__, referenceName.c_str());
+ return BAD_VALUE;
+ }
+ }
+
+ element = new Element(deviceCategory, streamType);
+
+ const xmlNode *child = referenceName.empty() ? root->xmlChildrenNode : ref->xmlChildrenNode;
+ while (child != NULL) {
+ if (!xmlStrcmp(child->name, (const xmlChar *)volumePointTag)) {
+ xmlChar *pointDefinition = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);;
+ if (pointDefinition == NULL) {
+ return BAD_VALUE;
+ }
+ ALOGV("%s: %s=%s", __FUNCTION__, tag, (const char*)pointDefinition);
+ Vector<int32_t> point;
+ collectionFromString<DefaultTraits<int32_t> >((const char*)pointDefinition, point, ",");
+ if (point.size() != 2) {
+ ALOGE("%s: Invalid %s: %s", __FUNCTION__, volumePointTag,
+ (const char*)pointDefinition);
+ return BAD_VALUE;
+ }
+ element->add(CurvePoint(point[0], point[1]));
+ xmlFree(pointDefinition);
+ }
+ child = child->next;
+ }
+ return NO_ERROR;
+}
+
+PolicySerializer::PolicySerializer() : mRootElementName(rootName)
+{
+ std::ostringstream oss;
+ oss << gMajor << "." << gMinor;
+ mVersion = oss.str();
+ ALOGV("%s: Version=%s Root=%s", __FUNCTION__, mVersion.c_str(), mRootElementName.c_str());
+}
+
+status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig &config)
+{
+ xmlDocPtr doc;
+ doc = xmlParseFile(configFile);
+ if (doc == NULL) {
+ ALOGE("%s: Could not parse %s document.", __FUNCTION__, configFile);
+ return BAD_VALUE;
+ }
+ xmlNodePtr cur = xmlDocGetRootElement(doc);
+ if (cur == NULL) {
+ ALOGE("%s: Could not parse %s document: empty.", __FUNCTION__, configFile);
+ xmlFreeDoc(doc);
+ return BAD_VALUE;
+ }
+ if (xmlXIncludeProcess(doc) < 0) {
+ ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __FUNCTION__, configFile);
+ }
+
+ if (xmlStrcmp(cur->name, (const xmlChar *) mRootElementName.c_str())) {
+ ALOGE("%s: No %s root element found in xml data %s.", __FUNCTION__, mRootElementName.c_str(),
+ (const char *)cur->name);
+ xmlFreeDoc(doc);
+ return BAD_VALUE;
+ }
+
+ string version = getXmlAttribute(cur, versionAttribute);
+ if (version.empty()) {
+ ALOGE("%s: No version found in root node %s", __FUNCTION__, mRootElementName.c_str());
+ return BAD_VALUE;
+ }
+ if (version != mVersion) {
+ ALOGE("%s: Version does not match; expect %s got %s", __FUNCTION__, mVersion.c_str(),
+ version.c_str());
+ return BAD_VALUE;
+ }
+ // Lets deserialize children
+ // Modules
+ ModuleTraits::Collection modules;
+ deserializeCollection<ModuleTraits>(doc, cur, modules, &config);
+ config.setHwModules(modules);
+
+ // deserialize volume section
+ VolumeTraits::Collection volumes;
+ deserializeCollection<VolumeTraits>(doc, cur, volumes, &config);
+ config.setVolumes(volumes);
+
+ // Global Configuration
+ GlobalConfigTraits::deserialize(cur, config);
+
+ xmlFreeDoc(doc);
+ return android::OK;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
index b682e2c..8388a50 100644
--- a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
@@ -25,6 +25,7 @@
#endif
#include "StreamDescriptor.h"
+#include "Gains.h"
#include <utils/Log.h>
#include <utils/String8.h>
@@ -35,7 +36,10 @@
StreamDescriptor::StreamDescriptor()
: mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
{
- mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0);
+ // Initialize the current stream's index to mIndexMax so volume isn't 0 in
+ // cases where the Java layer doesn't call into the audio policy service to
+ // set the default volume.
+ mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, mIndexMax);
}
int StreamDescriptor::getVolumeIndex(audio_devices_t device) const
@@ -68,7 +72,7 @@
mIndexMax = volIndexMax;
}
-void StreamDescriptor::setVolumeCurvePoint(Volume::device_category deviceCategory,
+void StreamDescriptor::setVolumeCurvePoint(device_category deviceCategory,
const VolumeCurvePoint *point)
{
mVolumeCurve[deviceCategory] = point;
@@ -118,14 +122,14 @@
}
void StreamDescriptorCollection::setVolumeCurvePoint(audio_stream_type_t stream,
- Volume::device_category deviceCategory,
+ device_category deviceCategory,
const VolumeCurvePoint *point)
{
editValueAt(stream).setVolumeCurvePoint(deviceCategory, point);
}
const VolumeCurvePoint *StreamDescriptorCollection::getVolumeCurvePoint(audio_stream_type_t stream,
- Volume::device_category deviceCategory) const
+ device_category deviceCategory) const
{
return valueAt(stream).getVolumeCurvePoint(deviceCategory);
}
@@ -140,6 +144,65 @@
return editValueAt(stream).setVolumeIndexMax(volIndexMax);
}
+float StreamDescriptorCollection::volIndexToDb(audio_stream_type_t stream, device_category category,
+ int indexInUi) const
+{
+ const StreamDescriptor &streamDesc = valueAt(stream);
+ return Gains::volIndexToDb(streamDesc.getVolumeCurvePoint(category),
+ streamDesc.getVolumeIndexMin(), streamDesc.getVolumeIndexMax(),
+ indexInUi);
+}
+
+status_t StreamDescriptorCollection::initStreamVolume(audio_stream_type_t stream,
+ int indexMin, int indexMax)
+{
+ ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
+ if (indexMin < 0 || indexMin >= indexMax) {
+ ALOGW("initStreamVolume() invalid index limits for stream %d, min %d, max %d",
+ stream , indexMin, indexMax);
+ return BAD_VALUE;
+ }
+ setVolumeIndexMin(stream, indexMin);
+ setVolumeIndexMax(stream, indexMax);
+ return NO_ERROR;
+}
+
+void StreamDescriptorCollection::initializeVolumeCurves(bool isSpeakerDrcEnabled)
+{
+ for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
+ for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+ setVolumeCurvePoint(static_cast<audio_stream_type_t>(i),
+ static_cast<device_category>(j),
+ Gains::sVolumeProfiles[i][j]);
+ }
+ }
+
+ // Check availability of DRC on speaker path: if available, override some of the speaker curves
+ if (isSpeakerDrcEnabled) {
+ setVolumeCurvePoint(AUDIO_STREAM_SYSTEM, DEVICE_CATEGORY_SPEAKER,
+ Gains::sDefaultSystemVolumeCurveDrc);
+ setVolumeCurvePoint(AUDIO_STREAM_RING, DEVICE_CATEGORY_SPEAKER,
+ Gains::sSpeakerSonificationVolumeCurveDrc);
+ setVolumeCurvePoint(AUDIO_STREAM_ALARM, DEVICE_CATEGORY_SPEAKER,
+ Gains::sSpeakerSonificationVolumeCurveDrc);
+ setVolumeCurvePoint(AUDIO_STREAM_NOTIFICATION, DEVICE_CATEGORY_SPEAKER,
+ Gains::sSpeakerSonificationVolumeCurveDrc);
+ setVolumeCurvePoint(AUDIO_STREAM_MUSIC, DEVICE_CATEGORY_SPEAKER,
+ Gains::sSpeakerMediaVolumeCurveDrc);
+ setVolumeCurvePoint(AUDIO_STREAM_ACCESSIBILITY, DEVICE_CATEGORY_SPEAKER,
+ Gains::sSpeakerMediaVolumeCurveDrc);
+ }
+}
+
+void StreamDescriptorCollection::switchVolumeCurve(audio_stream_type_t streamSrc,
+ audio_stream_type_t streamDst)
+{
+ for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+ setVolumeCurvePoint(streamDst, static_cast<device_category>(j),
+ Gains::sVolumeProfiles[streamSrc][j]);
+ }
+}
+
status_t StreamDescriptorCollection::dump(int fd) const
{
const size_t SIZE = 256;
diff --git a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
new file mode 100644
index 0000000..f613f94
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
@@ -0,0 +1,298 @@
+/*
+ * 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.
+ */
+
+#include "TypeConverter.h"
+
+namespace android {
+
+#define MAKE_STRING_FROM_ENUM(string) { #string, string }
+
+template <>
+const DeviceConverter::Table DeviceConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_EARPIECE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPEAKER),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPEAKER_SAFE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_SCO),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_HDMI),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_USB),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_TELEPHONY_TX),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_LINE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_HDMI_ARC),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPDIF),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_FM),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_AUX_LINE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_IP),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AMBIENT),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ALL_SCO),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_HDMI),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TELEPHONY_RX),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_FM_TUNER),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TV_TUNER),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LINE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_SPDIF),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LOOPBACK),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_IP),
+};
+
+template<>
+const size_t DeviceConverter::mSize = sizeof(DeviceConverter::mTable) /
+ sizeof(DeviceConverter::mTable[0]);
+
+
+template <>
+const OutputFlagConverter::Table OutputFlagConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_FAST),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_TTS),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_RAW),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_SYNC),
+};
+template<>
+const size_t OutputFlagConverter::mSize = sizeof(OutputFlagConverter::mTable) /
+ sizeof(OutputFlagConverter::mTable[0]);
+
+
+template <>
+const InputFlagConverter::Table InputFlagConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_FAST),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_RAW),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_SYNC),
+};
+template<>
+const size_t InputFlagConverter::mSize = sizeof(InputFlagConverter::mTable) /
+ sizeof(InputFlagConverter::mTable[0]);
+
+
+template <>
+const FormatConverter::Table FormatConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_16_BIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_8_BIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_32_BIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_FLOAT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MP3),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_MAIN),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_SSR),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LTP),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_HE_V1),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_SCALABLE),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ERLC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_HE_V2),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ELD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_VORBIS),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_HE_AAC_V1),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_HE_AAC_V2),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_OPUS),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AC3),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_E_AC3),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DTS),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DTS_HD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_IEC61937),
+};
+template<>
+const size_t FormatConverter::mSize = sizeof(FormatConverter::mTable) /
+ sizeof(FormatConverter::mTable[0]);
+
+
+template <>
+const OutputChannelConverter::Table OutputChannelConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_MONO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_STEREO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_QUAD),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+};
+template<>
+const size_t OutputChannelConverter::mSize = sizeof(OutputChannelConverter::mTable) /
+ sizeof(OutputChannelConverter::mTable[0]);
+
+
+template <>
+const InputChannelConverter::Table InputChannelConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_MONO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_STEREO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
+};
+template<>
+const size_t InputChannelConverter::mSize = sizeof(InputChannelConverter::mTable) /
+ sizeof(InputChannelConverter::mTable[0]);
+
+template <>
+const ChannelIndexConverter::Table ChannelIndexConverter::mTable[] = {
+ {"AUDIO_CHANNEL_INDEX_MASK_1", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_1)},
+ {"AUDIO_CHANNEL_INDEX_MASK_2", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_2)},
+ {"AUDIO_CHANNEL_INDEX_MASK_3", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_3)},
+ {"AUDIO_CHANNEL_INDEX_MASK_4", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_4)},
+ {"AUDIO_CHANNEL_INDEX_MASK_5", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_5)},
+ {"AUDIO_CHANNEL_INDEX_MASK_6", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_6)},
+ {"AUDIO_CHANNEL_INDEX_MASK_7", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_7)},
+ {"AUDIO_CHANNEL_INDEX_MASK_8", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_8)},
+};
+template<>
+const size_t ChannelIndexConverter::mSize = sizeof(ChannelIndexConverter::mTable) /
+ sizeof(ChannelIndexConverter::mTable[0]);
+
+
+template <>
+const GainModeConverter::Table GainModeConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_JOINT),
+ MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_CHANNELS),
+ MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_RAMP),
+};
+
+template<>
+const size_t GainModeConverter::mSize = sizeof(GainModeConverter::mTable) /
+ sizeof(GainModeConverter::mTable[0]);
+
+template <>
+const DeviceCategoryConverter::Table DeviceCategoryConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_HEADSET),
+ MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_SPEAKER),
+ MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_EARPIECE),
+ MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_EXT_MEDIA)
+};
+
+template<>
+const size_t DeviceCategoryConverter::mSize = sizeof(DeviceCategoryConverter::mTable) /
+ sizeof(DeviceCategoryConverter::mTable[0]);
+
+template <>
+const StreamTypeConverter::Table StreamTypeConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_VOICE_CALL),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_SYSTEM),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_RING),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_MUSIC),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ALARM),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_NOTIFICATION),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_BLUETOOTH_SCO ),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ENFORCED_AUDIBLE),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_DTMF),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_TTS),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ACCESSIBILITY),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_REROUTING),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_PATCH),
+};
+
+template<>
+const size_t StreamTypeConverter::mSize = sizeof(StreamTypeConverter::mTable) /
+ sizeof(StreamTypeConverter::mTable[0]);
+
+template <class Traits>
+bool TypeConverter<Traits>::toString(const typename Traits::Type &value, std::string &str)
+{
+ for (size_t i = 0; i < mSize; i++) {
+ if (mTable[i].value == value) {
+ str = mTable[i].literal;
+ return true;
+ }
+ }
+ return false;
+}
+
+template <class Traits>
+bool TypeConverter<Traits>::fromString(const std::string &str, typename Traits::Type &result)
+{
+ for (size_t i = 0; i < mSize; i++) {
+ if (strcmp(mTable[i].literal, str.c_str()) == 0) {
+ ALOGV("stringToEnum() found %s", mTable[i].literal);
+ result = mTable[i].value;
+ return true;
+ }
+ }
+ return false;
+}
+
+template <class Traits>
+void TypeConverter<Traits>::collectionFromString(const std::string &str,
+ typename Traits::Collection &collection,
+ const char *del)
+{
+ char *literal = strdup(str.c_str());
+
+ for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+ typename Traits::Type value;
+ if (fromString(cstr, value)) {
+ collection.add(value);
+ }
+ }
+ free(literal);
+}
+
+template <class Traits>
+uint32_t TypeConverter<Traits>::maskFromString(const std::string &str, const char *del)
+{
+ char *literal = strdup(str.c_str());
+ uint32_t value = 0;
+ for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+ typename Traits::Type type;
+ if (fromString(cstr, type)) {
+ value |= static_cast<uint32_t>(type);
+ }
+ }
+ free(literal);
+ return value;
+}
+
+template class TypeConverter<DeviceTraits>;
+template class TypeConverter<OutputFlagTraits>;
+template class TypeConverter<InputFlagTraits>;
+template class TypeConverter<FormatTraits>;
+template class TypeConverter<OutputChannelTraits>;
+template class TypeConverter<InputChannelTraits>;
+template class TypeConverter<ChannelIndexTraits>;
+template class TypeConverter<GainModeTraits>;
+template class TypeConverter<StreamTraits>;
+template class TypeConverter<DeviceCategoryTraits>;
+
+}; // namespace android
+
diff --git a/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp b/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
new file mode 100644
index 0000000..ab2b51f
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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 "APM::VolumeCurve"
+//#define LOG_NDEBUG 0
+
+#include "VolumeCurve.h"
+#include "TypeConverter.h"
+
+namespace android {
+
+float VolumeCurve::volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const
+{
+ ALOG_ASSERT(!mCurvePoints.isEmpty(), "Invalid volume curve");
+
+ size_t nbCurvePoints = mCurvePoints.size();
+ // the volume index in the UI is relative to the min and max volume indices for this stream
+ int nbSteps = 1 + mCurvePoints[nbCurvePoints - 1].mIndex - mCurvePoints[0].mIndex;
+ int volIdx = (nbSteps * (indexInUi - volIndexMin)) / (volIndexMax - volIndexMin);
+
+ // Where would this volume index been inserted in the curve point
+ size_t indexInUiPosition = mCurvePoints.orderOf(CurvePoint(volIdx, 0));
+ if (indexInUiPosition >= nbCurvePoints) {
+ return 0.0f; // out of bounds
+ }
+ if (indexInUiPosition == 0) {
+ if (indexInUiPosition != mCurvePoints[0].mIndex) {
+ return VOLUME_MIN_DB; // out of bounds
+ }
+ return mCurvePoints[0].mAttenuationInMb / 100.0f;
+ }
+ // linear interpolation in the attenuation table in dB
+ float decibels = (mCurvePoints[indexInUiPosition - 1].mAttenuationInMb / 100.0f) +
+ ((float)(volIdx - mCurvePoints[indexInUiPosition - 1].mIndex)) *
+ ( ((mCurvePoints[indexInUiPosition].mAttenuationInMb / 100.0f) -
+ (mCurvePoints[indexInUiPosition - 1].mAttenuationInMb / 100.0f)) /
+ ((float)(mCurvePoints[indexInUiPosition].mIndex -
+ mCurvePoints[indexInUiPosition - 1].mIndex)) );
+
+ ALOGV("VOLUME mDeviceCategory %d, mStreamType %d vol index=[%d %d %d], dB=[%.1f %.1f %.1f]",
+ mDeviceCategory, mStreamType,
+ mCurvePoints[indexInUiPosition - 1].mIndex, volIdx,
+ mCurvePoints[indexInUiPosition].mIndex,
+ ((float)mCurvePoints[indexInUiPosition - 1].mAttenuationInMb / 100.0f), decibels,
+ ((float)mCurvePoints[indexInUiPosition].mAttenuationInMb / 100.0f));
+
+ return decibels;
+}
+
+void VolumeCurve::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, " {");
+ result.append(buffer);
+ for (size_t i = 0; i < mCurvePoints.size(); i++) {
+ snprintf(buffer, SIZE, "(%3d, %5d)",
+ mCurvePoints[i].mIndex, mCurvePoints[i].mAttenuationInMb);
+ result.append(buffer);
+ result.append(i == (mCurvePoints.size() - 1) ? " }\n" : ", ");
+ }
+ write(fd, result.string(), result.size());
+}
+
+void VolumeCurvesForStream::dump(int fd, int spaces = 0, bool curvePoints) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ if (!curvePoints) {
+ snprintf(buffer, SIZE, "%s %02d %02d ",
+ mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
+ result.append(buffer);
+ for (size_t i = 0; i < mIndexCur.size(); i++) {
+ snprintf(buffer, SIZE, "%04x : %02d, ", mIndexCur.keyAt(i), mIndexCur.valueAt(i));
+ result.append(buffer);
+ }
+ result.append("\n");
+ write(fd, result.string(), result.size());
+ return;
+ }
+
+ for (size_t i = 0; i < size(); i++) {
+ std::string deviceCatLiteral;
+ DeviceCategoryConverter::toString(keyAt(i), deviceCatLiteral);
+ snprintf(buffer, SIZE, "%*s %s :",
+ spaces, "", deviceCatLiteral.c_str());
+ write(fd, buffer, strlen(buffer));
+ valueAt(i)->dump(fd);
+ }
+ result.append("\n");
+ write(fd, result.string(), result.size());
+}
+
+status_t VolumeCurvesCollection::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\nStreams dump:\n");
+ write(fd, buffer, strlen(buffer));
+ snprintf(buffer, SIZE,
+ " Stream Can be muted Index Min Index Max Index Cur [device : index]...\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, " %02zu ", i);
+ write(fd, buffer, strlen(buffer));
+ valueAt(i).dump(fd);
+ }
+ snprintf(buffer, SIZE, "\nVolume Curves for Use Cases (aka Stream types) dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ std::string streamTypeLiteral;
+ StreamTypeConverter::toString(keyAt(i), streamTypeLiteral);
+ snprintf(buffer, SIZE,
+ " %s (%02zu): Curve points for device category (index, attenuation in millibel)\n",
+ streamTypeLiteral.c_str(), i);
+ write(fd, buffer, strlen(buffer));
+ valueAt(i).dump(fd, 2, true);
+ }
+
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/config/a2dp_audio_policy_configuration.xml b/services/audiopolicy/config/a2dp_audio_policy_configuration.xml
new file mode 100644
index 0000000..ced7463
--- /dev/null
+++ b/services/audiopolicy/config/a2dp_audio_policy_configuration.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- A2dp Audio HAL Audio Policy Configuration file -->
+<module name="a2dp" halVersion="2.0">
+ <mixPorts>
+ <mixPort name="a2dp output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="a2dp input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="BT A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT A2DP Headphones" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT A2DP Speaker" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT A2DP In" type="AUDIO_DEVICE_IN_BLUETOOTH_A2DP" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="BT A2DP Out"
+ sources="a2dp output"/>
+ <route type="mix" sink="BT A2DP Headphones"
+ sources="a2dp output"/>
+ <route type="mix" sink="BT A2DP Speaker"
+ sources="a2dp output"/>
+ <route type="mix" sink="a2dp input"
+ sources="BT A2DP In"/>
+ </routes>
+</module>
diff --git a/services/audiopolicy/config/audio_policy_configuration.xml b/services/audiopolicy/config/audio_policy_configuration.xml
new file mode 100644
index 0000000..7af2f81
--- /dev/null
+++ b/services/audiopolicy/config/audio_policy_configuration.xml
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 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.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <!-- version section contains a “version” tag in the form “major.minor” e.g version=”1.0” -->
+
+ <!-- Global configuration Decalaration -->
+ <globalConfiguration speaker_drc_enabled="true"/>
+
+
+ <!-- Modules section:
+ There is one section per audio HW module present on the platform.
+ Each module section will contains two mandatory tags for audio HAL “halVersion” and “name”.
+ The module names are the same as in current .conf file:
+ “primary”, “A2DP”, “remote_submix”, “USB”
+ Each module will contain the following sections:
+ “devicePorts”: a list of device descriptors for all input and output devices accessible via this
+ module.
+ This contains both permanently attached devices and removable devices.
+ “mixPorts”: listing all output and input streams exposed by the audio HAL
+ “routes”: list of possible connections between input and output devices or between stream and
+ devices.
+ "route": is defined by an attribute:
+ -"type": <mux|mix> means all sources are mutual exclusive (mux) or can be mixed (mix)
+ -"sink": the sink involved in this route
+ -"sources": all the sources than can be connected to the sink via vis route
+ “attachedDevices”: permanently attached devices.
+ The attachedDevices section is a list of devices names. The names correspond to device names
+ defined in <devicePorts> section.
+ “defaultOutputDevice”: device to be used by default when no policy rule applies
+ -->
+ <modules>
+ <!-- Primary Audio HAL -->
+ <module name="primary" halVersion="3.0">
+ <attachedDevices>
+ <item>Speaker</item>
+ <item>Built-In Mic</item>
+ <item>Built-In Back Mic</item>
+ </attachedDevices>
+ <defaultOutputDevice>Speaker</defaultOutputDevice>
+ <mixPorts>
+ <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="deep_buffer" role="source"
+ flags="AUDIO_OUTPUT_FLAG_DEEP_BUFFER">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="compressed_offload" role="source"
+ flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING">
+ <profile name="" format="AUDIO_FORMAT_MP3"
+ samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
+ <profile name="" format="AUDIO_FORMAT_AAC"
+ samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
+ <profile name="" format="AUDIO_FORMAT_AAC_LC"
+ samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
+ </mixPort>
+ <mixPort name="voice_tx" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+ </mixPort>
+ <mixPort name="primary input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
+ </mixPort>
+ <mixPort name="voice_rx" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <!-- Output devices declaration, i.e. Sink DEVICE PORT -->
+ <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ </devicePort>
+ <devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ <gains>
+ <gain name="gain_1" mode="AUDIO_GAIN_MODE_JOINT"
+ minValueMB="-8400"
+ maxValueMB="4000"
+ defaultValueMB="0"
+ stepValueMB="100"/>
+ </gains>
+ </devicePort>
+ <devicePort tagName="Wired Headset" type="AUDIO_DEVICE_OUT_WIRED_HEADSET" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="Wired Headphones" type="AUDIO_DEVICE_OUT_WIRED_HEADPHONE" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+ </devicePort>
+ <devicePort tagName="BT SCO Headset" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+ </devicePort>
+ <devicePort tagName="BT SCO Car Kit" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+ </devicePort>
+ <devicePort tagName="Telephony Tx" type="AUDIO_DEVICE_OUT_TELEPHONY_TX" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+ </devicePort>
+
+ <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
+ </devicePort>
+ <devicePort tagName="Built-In Back Mic" type="AUDIO_DEVICE_IN_BACK_MIC" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
+ </devicePort>
+ <devicePort tagName="Wired Headset Mic" type="AUDIO_DEVICE_IN_WIRED_HEADSET" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
+ </devicePort>
+ <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ </devicePort>
+ <devicePort tagName="Telephony Rx" type="AUDIO_DEVICE_IN_TELEPHONY_RX" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ </devicePort>
+ </devicePorts>
+ <!-- route declaration, i.e. list all available sources for a given sink -->
+ <routes>
+ <route type="mix" sink="Earpiece"
+ sources="primary output,deep_buffer,BT SCO Headset Mic"/>
+ <route type="mix" sink="Speaker"
+ sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
+ <route type="mix" sink="Wired Headset"
+ sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
+ <route type="mix" sink="Wired Headphones"
+ sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
+ <route type="mix" sink="Telephony Tx"
+ sources="voice_tx"/>
+ <route type="mix" sink="primary input"
+ sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic"/>
+ <route type="mix" sink="Telephony Tx"
+ sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic"/>
+ <route type="mix" sink="voice_rx"
+ sources="Telephony Rx"/>
+ </routes>
+
+ </module>
+
+ <!-- HDMI Audio HAL -->
+ <module description="HDMI Audio HAL" name="hdmi" version="2.0">
+ <mixPorts>
+ <mixPort name="hdmi output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="HDMI Out" type="AUDIO_DEVICE_OUT_AUX_DIGITAL" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="HDMI Out"
+ sources="hdmi output"/>
+ </routes>
+ </module>
+
+ <!-- A2dp Audio HAL -->
+ <xi:include href="a2dp_audio_policy_configuration.xml"/>
+
+ <!-- Usb Audio HAL -->
+ <xi:include href="usb_audio_policy_configuration.xml"/>
+
+ <!-- Remote Submix Audio HAL -->
+ <xi:include href="r_submix_audio_policy_configuration.xml"/>
+
+ </modules>
+ <!-- End of Modules section -->
+
+ <!-- Volume section -->
+
+ <xi:include href="audio_policy_volumes.xml"/>
+ <xi:include href="default_volume_tables.xml"/>
+
+ <!-- End of Volume section -->
+
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/config/audio_policy_volumes.xml b/services/audiopolicy/config/audio_policy_volumes.xml
new file mode 100644
index 0000000..43a47b0
--- /dev/null
+++ b/services/audiopolicy/config/audio_policy_volumes.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<!-- Volume section defines a volume curve for a given use case and device category.
+It contains a list of points of this curve expressing the attenuation in Millibels for a given
+volume index from 0 to 100.
+<volume stream=”AUDIO_STREAM_MUSIC” deviceCategory=””>
+<point>0,-9600</point>
+<point>100,0</point>
+</volume>
+-->
+
+<volumes>
+ <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-2400</point>
+ <point>33,-1600</point>
+ <point>66,-800</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_EARPIECE">
+ <point>0,-2400</point>
+ <point>33,-1600</point>
+ <point>66,-800</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>1,-3000</point>
+ <point>33,-2600</point>
+ <point>66,-2200</point>
+ <point>100,-1800</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+ ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_HEADSET"
+ ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>1,-2970</point>
+ <point>33,-2010</point>
+ <point>66,-1020</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+ ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_HEADSET"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ALARM" deviceCategory="DEVICE_CATEGORY_HEADSET"
+ ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ALARM" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>1,-2970</point>
+ <point>33,-2010</point>
+ <point>66,-1020</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_ALARM" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+ ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ALARM" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_NOTIFICATION" deviceCategory="DEVICE_CATEGORY_HEADSET"
+ ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_NOTIFICATION" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>1,-2970</point>
+ <point>33,-2010</point>
+ <point>66,-1020</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_NOTIFICATION" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+ ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_NOTIFICATION" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_BLUETOOTH_SCO" deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_BLUETOOTH_SCO" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-2400</point>
+ <point>33,-1600</point>
+ <point>66,-800</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_BLUETOOTH_SCO" deviceCategory="DEVICE_CATEGORY_EARPIECE">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_BLUETOOTH_SCO" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ENFORCED_AUDIBLE" deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>1,-3000</point>
+ <point>33,-2600</point>
+ <point>66,-2200</point>
+ <point>100,-1800</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_ENFORCED_AUDIBLE" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ENFORCED_AUDIBLE" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+ ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ENFORCED_AUDIBLE" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_DTMF" deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>1,-3000</point>
+ <point>33,-2600</point>
+ <point>66,-2200</point>
+ <point>100,-1800</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_DTMF" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_DTMF" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+ ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_DTMF" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_TTS" deviceCategory="DEVICE_CATEGORY_HEADSET"
+ ref="SILENT_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_TTS" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_TTS" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+ ref="SILENT_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_TTS" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="SILENT_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_HEADSET"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_HEADSET"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_PATCH" deviceCategory="DEVICE_CATEGORY_HEADSET"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_PATCH" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_PATCH" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_PATCH" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+</volumes>
+
diff --git a/services/audiopolicy/config/default_volume_tables.xml b/services/audiopolicy/config/default_volume_tables.xml
new file mode 100644
index 0000000..9a22b1d
--- /dev/null
+++ b/services/audiopolicy/config/default_volume_tables.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<!-- Default Volume Tables included by Audio Policy Configuration file -->
+<!-- Full Default Volume table for all device category -->
+<volumes>
+ <reference name="FULL_SCALE_VOLUME_CURVE">
+ <!-- Full Scale reference Volume Curve -->
+ <point>0,0</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="SILENT_VOLUME_CURVE">
+ <point>0,-9600</point>
+ <point>100,-9600</point>
+ </reference>
+ <reference name="DEFAULT_SYSTEM_VOLUME_CURVE">
+ <!-- Default System reference Volume Curve -->
+ <point>1,-2400</point>
+ <point>33,-1800</point>
+ <point>66,-1200</point>
+ <point>100,-600</point>
+ </reference>
+ <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+ <!-- Default Media reference Volume Curve -->
+ <point>1,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE">
+ <!--Default Volume Curve -->
+ <point>1,-4950</point>
+ <point>33,-3350</point>
+ <point>66,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE">
+ <!-- Default is Speaker Media Volume Curve -->
+ <point>1,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE">
+ <!--Default Volume Curve -->
+ <point>1,-4950</point>
+ <point>33,-3350</point>
+ <point>66,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE">
+ <!-- Default is Ext Media System Volume Curve -->
+ <point>1,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-2100</point>
+ <point>100,-1000</point>
+ </reference>
+</volumes>
diff --git a/services/audiopolicy/config/r_submix_audio_policy_configuration.xml b/services/audiopolicy/config/r_submix_audio_policy_configuration.xml
new file mode 100644
index 0000000..dc2a5ec
--- /dev/null
+++ b/services/audiopolicy/config/r_submix_audio_policy_configuration.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<!-- Remote Submix Audio Policy Configuration file -->
+<module name="r_submix" halVersion="2.0">
+ <attachedDevices>
+ <item>Remote Submix In</item>
+ </attachedDevices>
+ <mixPorts>
+ <mixPort name="r_submix output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="r_submix input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="Remote Submix Out" type="AUDIO_DEVICE_OUT_REMOTE_SUBMIX" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="Remote Submix In" type="AUDIO_DEVICE_IN_REMOTE_SUBMIX" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="Remote Submix Out"
+ sources="r_submix output"/>
+ <route type="mix" sink="r_submix input"
+ sources="Remote Submix In"/>
+ </routes>
+</module>
diff --git a/services/audiopolicy/config/usb_audio_policy_configuration.xml b/services/audiopolicy/config/usb_audio_policy_configuration.xml
new file mode 100644
index 0000000..1630a94
--- /dev/null
+++ b/services/audiopolicy/config/usb_audio_policy_configuration.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<!-- USB Audio HAL Audio Policy Configuration file -->
+
+<module name="usb" halVersion="2.0">
+ <mixPorts>
+ <mixPort name="usb_accessory output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="usb_device output" role="source"/>
+ <mixPort name="usb_device input" role="sink"/>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="USB Host Out" type="AUDIO_DEVICE_OUT_USB_ACCESSORY" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="USB Device Out" type="AUDIO_DEVICE_OUT_USB_DEVICE" role="sink"/>
+ <devicePort tagName="USB Device In" type="AUDIO_DEVICE_IN_USB_DEVICE" role="source"/>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="USB Host Out"
+ sources="usb_accessory output"/>
+ <route type="mix" sink="USB Device Out"
+ sources="usb_device output"/>
+ <route type="mix" sink="usb_device input"
+ sources="USB Device In"/>
+ </routes>
+</module>
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
index e73e543..567ff9e 100755
--- a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
@@ -133,37 +133,6 @@
virtual status_t setDeviceConnectionState(const android::sp<android::DeviceDescriptor> devDesc,
audio_policy_dev_state_t state) = 0;
- /**
- * Translate a volume index given by the UI to an amplification value in dB for a stream type
- * and a device category.
- *
- * @param[in] deviceCategory for which the conversion is requested.
- * @param[in] stream type for which the conversion is requested.
- * @param[in] indexInUi index received from the UI to be translated.
- *
- * @return amplification value in dB matching the UI index for this given device and stream.
- */
- virtual float volIndexToDb(Volume::device_category deviceCategory, audio_stream_type_t stream,
- int indexInUi) = 0;
-
- /**
- * Initialize the min / max index of volume applicable for a given stream type. These indexes
- * will be used upon conversion of UI index to volume amplification.
- *
- * @param[in] stream type for which the indexes need to be set
- * @param[in] indexMin Minimum index allowed for this stream.
- * @param[in] indexMax Maximum index allowed for this stream.
- */
- virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax) = 0;
-
- /**
- * Initialize volume curves for each strategy and device category
- *
- * @param[in] isSpeakerDrcEnabled true on devices that use DRC on the DEVICE_CATEGORY_SPEAKER
- path to boost soft sounds, used to adjust volume curves accordingly
- */
- virtual void initializeVolumeCurves(bool isSpeakerDrcEnabled) = 0;
-
protected:
virtual ~AudioPolicyManagerInterface() {}
};
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
index 6d43df2..846fa48 100755
--- a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
@@ -16,6 +16,7 @@
#pragma once
+#include <IVolumeCurvesCollection.h>
#include <AudioGain.h>
#include <AudioPort.h>
#include <AudioPatch.h>
@@ -25,7 +26,6 @@
#include <AudioOutputDescriptor.h>
#include <AudioPolicyMix.h>
#include <SoundTriggerSession.h>
-#include <StreamDescriptor.h>
namespace android {
@@ -51,7 +51,7 @@
virtual const DeviceVector &getAvailableInputDevices() const = 0;
- virtual StreamDescriptorCollection &getStreamDescriptors() = 0;
+ virtual IVolumeCurvesCollection &getVolumeCurves() = 0;
virtual const sp<DeviceDescriptor> &getDefaultOutputDevice() const = 0;
diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk
index b18c520..e6b5f85 100755
--- a/services/audiopolicy/engineconfigurable/Android.mk
+++ b/services/audiopolicy/engineconfigurable/Android.mk
@@ -41,7 +41,8 @@
LOCAL_STATIC_LIBRARIES := \
libmedia_helper \
libaudiopolicypfwwrapper \
- libaudiopolicycomponents
+ libaudiopolicycomponents \
+ libxml2
LOCAL_SHARED_LIBRARIES := \
libcutils \
diff --git a/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h b/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
index 74daba5..759d0c9 100755
--- a/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
+++ b/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
@@ -111,13 +111,12 @@
* Set the strategy to be followed by a stream.
*
* @param[in] stream: name of the stream for which the strategy to use has to be set
- * @param[in] strategy to follow for the given stream.
+ * @param[in] volumeProfile to follow for the given stream.
*
- * @return true if the strategy were set correclty for this stream, false otherwise.
+ * @return true if the profile was set correclty for this stream, false otherwise.
*/
virtual bool setVolumeProfileForStream(const audio_stream_type_t &stream,
- Volume::device_category category,
- const VolumeCurvePoints &points) = 0;
+ const audio_stream_type_t &volumeProfile) = 0;
/**
* Set the strategy to be followed by a usage.
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk
index e9b1902..e15e418 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk
@@ -7,6 +7,7 @@
#
################################################################################################
+ifeq (1, 0)
LOCAL_PATH := $(call my-dir)
@@ -60,14 +61,6 @@
LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE)
include $(BUILD_PREBUILT)
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem-Volume.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
######### Policy PFW Settings #########
include $(CLEAR_VARS)
LOCAL_MODULE := parameter-framework.policy
@@ -103,3 +96,5 @@
LOCAL_SRC_FILES := Settings/$(LOCAL_MODULE_STEM)
include $(BUILD_PREBUILT)
endif # pfw_rebuild_settings
+
+endif # ifeq (1, 0)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/PolicyConfigurableDomains.xml b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/PolicyConfigurableDomains.xml
index 8cb0723..8c3917a 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/PolicyConfigurableDomains.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/PolicyConfigurableDomains.xml
@@ -52,18 +52,21 @@
<Configuration Name="BluetoothA2dp">
<CompoundRule Type="All">
<SelectionCriterionRule SelectionCriterion="ForceUseForMedia" MatchesWhen="IsNot" Value="ForceNoBtA2dp"/>
+ <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="IsNot" Value="ForceBtSco"/>
<SelectionCriterionRule SelectionCriterion="AvailableOutputDevices" MatchesWhen="Includes" Value="BluetoothA2dp"/>
</CompoundRule>
</Configuration>
<Configuration Name="BluetoothA2dpHeadphone">
<CompoundRule Type="All">
<SelectionCriterionRule SelectionCriterion="ForceUseForMedia" MatchesWhen="IsNot" Value="ForceNoBtA2dp"/>
+ <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="IsNot" Value="ForceBtSco"/>
<SelectionCriterionRule SelectionCriterion="AvailableOutputDevices" MatchesWhen="Includes" Value="BluetoothA2dpHeadphones"/>
</CompoundRule>
</Configuration>
<Configuration Name="BluetoothA2dpSpeaker">
<CompoundRule Type="All">
<SelectionCriterionRule SelectionCriterion="ForceUseForMedia" MatchesWhen="IsNot" Value="ForceNoBtA2dp"/>
+ <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="IsNot" Value="ForceBtSco"/>
<SelectionCriterionRule SelectionCriterion="AvailableOutputDevices" MatchesWhen="Includes" Value="BluetoothA2dpSpeaker"/>
</CompoundRule>
</Configuration>
@@ -119,6 +122,7 @@
<CompoundRule Type="All">
<SelectionCriterionRule SelectionCriterion="AvailableOutputDevices" MatchesWhen="Includes" Value="Speaker"/>
<SelectionCriterionRule SelectionCriterion="ForceUseForHdmiSystemAudio" MatchesWhen="IsNot" Value="ForceHdmiSystemEnforced"/>
+ <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="IsNot" Value="ForceBtSco"/>
</CompoundRule>
</Configuration>
<Configuration Name="Default">
@@ -902,10 +906,7 @@
<SelectionCriterionRule SelectionCriterion="TelephonyMode" MatchesWhen="IsNot" Value="InCall"/>
<SelectionCriterionRule SelectionCriterion="TelephonyMode" MatchesWhen="IsNot" Value="InCommunication"/>
<SelectionCriterionRule SelectionCriterion="ForceUseForMedia" MatchesWhen="IsNot" Value="ForceNoBtA2dp"/>
- <CompoundRule Type="Any">
- <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceBtSco"/>
- <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceNone"/>
- </CompoundRule>
+ <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceNone"/>
</CompoundRule>
</Configuration>
<Configuration Name="BluetoothA2dpHeadphones">
@@ -914,10 +915,7 @@
<SelectionCriterionRule SelectionCriterion="TelephonyMode" MatchesWhen="IsNot" Value="InCall"/>
<SelectionCriterionRule SelectionCriterion="TelephonyMode" MatchesWhen="IsNot" Value="InCommunication"/>
<SelectionCriterionRule SelectionCriterion="ForceUseForMedia" MatchesWhen="IsNot" Value="ForceNoBtA2dp"/>
- <CompoundRule Type="Any">
- <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceBtSco"/>
- <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceNone"/>
- </CompoundRule>
+ <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceNone"/>
</CompoundRule>
</Configuration>
<Configuration Name="BluetoothA2dpSpeaker">
@@ -1314,10 +1312,10 @@
<BitParameter Name="bluetooth_a2dp">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/bluetooth_a2dp_headphones">
- <BitParameter Name="bluetooth_a2dp_headphones">1</BitParameter>
+ <BitParameter Name="bluetooth_a2dp_headphones">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/bluetooth_a2dp_speaker">
- <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
+ <BitParameter Name="bluetooth_a2dp_speaker">1</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
@@ -1924,7 +1922,7 @@
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/speaker">
- <BitParameter Name="speaker">0</BitParameter>
+ <BitParameter Name="speaker">1</BitParameter>
</ConfigurableElement>
</Configuration>
</Settings>
@@ -8197,6 +8195,22 @@
<ConfigurableElement Path="/Policy/policy/input_sources/hotword/applicable_input_device/mask/spdif"/>
<ConfigurableElement Path="/Policy/policy/input_sources/hotword/applicable_input_device/mask/bluetooth_a2dp"/>
<ConfigurableElement Path="/Policy/policy/input_sources/hotword/applicable_input_device/mask/loopback"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/in"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/communication"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/ambient"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/hdmi"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/telephony_rx"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/back_mic"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/remote_submix"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/anlg_dock_headset"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/dgtl_dock_headset"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/usb_accessory"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/fm_tuner"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/tv_tuner"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/line"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/spdif"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/bluetooth_a2dp"/>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/loopback"/>
<ConfigurableElement Path="/Policy/policy/input_sources/fm_tuner/applicable_input_device/mask/in"/>
<ConfigurableElement Path="/Policy/policy/input_sources/fm_tuner/applicable_input_device/mask/communication"/>
<ConfigurableElement Path="/Policy/policy/input_sources/fm_tuner/applicable_input_device/mask/ambient"/>
@@ -8733,6 +8747,54 @@
<ConfigurableElement Path="/Policy/policy/input_sources/hotword/applicable_input_device/mask/loopback">
<BitParameter Name="loopback">0</BitParameter>
</ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/in">
+ <BitParameter Name="in">1</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/communication">
+ <BitParameter Name="communication">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/ambient">
+ <BitParameter Name="ambient">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/hdmi">
+ <BitParameter Name="hdmi">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/telephony_rx">
+ <BitParameter Name="telephony_rx">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/back_mic">
+ <BitParameter Name="back_mic">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/remote_submix">
+ <BitParameter Name="remote_submix">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/dgtl_dock_headset">
+ <BitParameter Name="dgtl_dock_headset">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/usb_accessory">
+ <BitParameter Name="usb_accessory">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/fm_tuner">
+ <BitParameter Name="fm_tuner">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/tv_tuner">
+ <BitParameter Name="tv_tuner">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/line">
+ <BitParameter Name="line">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/spdif">
+ <BitParameter Name="spdif">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/bluetooth_a2dp">
+ <BitParameter Name="bluetooth_a2dp">0</BitParameter>
+ </ConfigurableElement>
+ <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/loopback">
+ <BitParameter Name="loopback">0</BitParameter>
+ </ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/input_sources/fm_tuner/applicable_input_device/mask/in">
<BitParameter Name="in">1</BitParameter>
</ConfigurableElement>
@@ -8893,7 +8955,7 @@
<BitParameter Name="bluetooth_a2dp">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/input_sources/mic/applicable_input_device/mask/wired_headset">
- <BitParameter Name="wired_headset">1</BitParameter>
+ <BitParameter Name="wired_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/input_sources/mic/applicable_input_device/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -9439,7 +9501,7 @@
<BitParameter Name="usb_device">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/builtin_mic">
- <BitParameter Name="builtin_mic">0</BitParameter>
+ <BitParameter Name="builtin_mic">1</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/back_mic">
<BitParameter Name="back_mic">0</BitParameter>
@@ -9508,1544 +9570,56 @@
</Configuration>
</Configurations>
<ConfigurableElements>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
+ <ConfigurableElement Path="/Policy/policy/streams/voice_call/applicable_volume_profile/volume_profile"/>
+ <ConfigurableElement Path="/Policy/policy/streams/system/applicable_volume_profile/volume_profile"/>
+ <ConfigurableElement Path="/Policy/policy/streams/ring/applicable_volume_profile/volume_profile"/>
+ <ConfigurableElement Path="/Policy/policy/streams/music/applicable_volume_profile/volume_profile"/>
+ <ConfigurableElement Path="/Policy/policy/streams/alarm/applicable_volume_profile/volume_profile"/>
+ <ConfigurableElement Path="/Policy/policy/streams/notification/applicable_volume_profile/volume_profile"/>
+ <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/applicable_volume_profile/volume_profile"/>
+ <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/applicable_volume_profile/volume_profile"/>
+ <ConfigurableElement Path="/Policy/policy/streams/tts/applicable_volume_profile/volume_profile"/>
+ <ConfigurableElement Path="/Policy/policy/streams/accessibility/applicable_volume_profile/volume_profile"/>
+ <ConfigurableElement Path="/Policy/policy/streams/rerouting/applicable_volume_profile/volume_profile"/>
+ <ConfigurableElement Path="/Policy/policy/streams/patch/applicable_volume_profile/volume_profile"/>
</ConfigurableElements>
<Settings>
<Configuration Name="Calibration">
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/voice_call/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">voice_call</EnumParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/system/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">system</EnumParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/ring/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">ring</EnumParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/music/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">music</EnumParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/alarm/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">alarm</EnumParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/notification/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">notification</EnumParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">bluetooth_sco</EnumParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">enforced_audible</EnumParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/tts/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">tts</EnumParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/accessibility/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">accessibility</EnumParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/rerouting/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">rerouting</EnumParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-16.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-8.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-30.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-26.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-22.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-21.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-10.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-49.50000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-33.50000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-35.69921875</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-26.10156250</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-13.19921875</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-49.50000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-33.50000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-27.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-10.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-56.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-34.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-11.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-49.50000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-33.50000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-35.69921875</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-26.10156250</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-13.19921875</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-49.50000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-33.50000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-27.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-10.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-49.50000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-33.50000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-35.69921875</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-26.10156250</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-13.19921875</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-49.50000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-33.50000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-27.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-10.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-16.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-8.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-30.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-26.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-22.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-27.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-10.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">2</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-68.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-34.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">2</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">2</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-56.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-34.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-11.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">2</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">2</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">2</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">2</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">2</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">2</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">2</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">2</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/patch/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">patch</EnumParameter>
</ConfigurableElement>
</Configuration>
</Settings>
@@ -11063,234 +9637,17 @@
</Configuration>
</Configurations>
<ConfigurableElements>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/0/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/1/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/2/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/3/index"/>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
+ <ConfigurableElement Path="/Policy/policy/streams/dtmf/applicable_volume_profile/volume_profile"/>
</ConfigurableElements>
<Settings>
<Configuration Name="InCall">
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-30.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-26.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-22.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-27.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-10.00000000</FixedPointParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/dtmf/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">voice_call</EnumParameter>
</ConfigurableElement>
</Configuration>
<Configuration Name="OutOfCall">
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-16.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-8.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/0/index">
- <IntegerParameter Name="index">0</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/0/index">
- <IntegerParameter Name="index">1</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/1/index">
- <IntegerParameter Name="index">33</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/2/index">
- <IntegerParameter Name="index">66</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
- <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/3/index">
- <IntegerParameter Name="index">100</IntegerParameter>
- </ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
- <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
+ <ConfigurableElement Path="/Policy/policy/streams/dtmf/applicable_volume_profile/volume_profile">
+ <EnumParameter Name="volume_profile">dtmf</EnumParameter>
</ConfigurableElement>
</Configuration>
</Settings>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_input_source.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_input_source.pfw
index d4bc370..07a3c81 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_input_source.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_input_source.pfw
@@ -186,6 +186,23 @@
spdif = 0
bluetooth_a2dp = 0
loopback = 0
+ component: /Policy/policy/input_sources/unprocessed/applicable_input_device/mask
+ in = 1
+ communication = 0
+ ambient = 0
+ hdmi = 0
+ telephony_rx = 0
+ back_mic = 0
+ remote_submix = 0
+ anlg_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ fm_tuner = 0
+ tv_tuner = 0
+ line = 0
+ spdif = 0
+ bluetooth_a2dp = 0
+ loopback = 0
component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
in = 1
communication = 0
@@ -239,7 +256,7 @@
bluetooth_sco_headset = 1
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
- wired_headset = 1
+ wired_headset = 0
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 1
@@ -484,11 +501,14 @@
back_mic = 1
conf: Default
+ #
+ # Fallback on the default input device which can be builtin mic for example
+ #
component: /Policy/policy/input_sources/voice_communication/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 0
- builtin_mic = 0
+ builtin_mic = 1
back_mic = 0
domain: RemoteSubmix
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_media.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_media.pfw
index 38bede5..006ac60 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_media.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_media.pfw
@@ -34,6 +34,7 @@
conf: BluetoothA2dp
ForceUseForMedia IsNot ForceNoBtA2dp
+ ForceUseForCommunication IsNot ForceBtSco
AvailableOutputDevices Includes BluetoothA2dp
component: /Policy/policy/strategies/media/selected_output_devices/mask
@@ -53,6 +54,7 @@
conf: BluetoothA2dpHeadphone
ForceUseForMedia IsNot ForceNoBtA2dp
+ ForceUseForCommunication IsNot ForceBtSco
AvailableOutputDevices Includes BluetoothA2dpHeadphones
component: /Policy/policy/strategies/media/selected_output_devices/mask
@@ -72,6 +74,7 @@
conf: BluetoothA2dpSpeaker
ForceUseForMedia IsNot ForceNoBtA2dp
+ ForceUseForCommunication IsNot ForceBtSco
AvailableOutputDevices Includes BluetoothA2dpSpeaker
component: /Policy/policy/strategies/media/selected_output_devices/mask
@@ -263,6 +266,7 @@
# If hdmi system audio mode is on, remove speaker out of output list.
#
ForceUseForHdmiSystemAudio IsNot ForceHdmiSystemEnforced
+ ForceUseForCommunication IsNot ForceBtSco
component: /Policy/policy/strategies/media/selected_output_devices/mask
speaker = 1
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_phone.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_phone.pfw
index 7b01491..ae70914 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_phone.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_phone.pfw
@@ -92,9 +92,7 @@
TelephonyMode IsNot InCall
TelephonyMode IsNot InCommunication
ForceUseForMedia IsNot ForceNoBtA2dp
- ANY
- ForceUseForCommunication Is ForceBtSco
- ForceUseForCommunication Is ForceNone
+ ForceUseForCommunication Is ForceNone
component: /Policy/policy/strategies/phone/selected_output_devices/mask
earpiece = 0
@@ -124,9 +122,7 @@
TelephonyMode IsNot InCall
TelephonyMode IsNot InCommunication
ForceUseForMedia IsNot ForceNoBtA2dp
- ANY
- ForceUseForCommunication Is ForceBtSco
- ForceUseForCommunication Is ForceNone
+ ForceUseForCommunication Is ForceNone
component: /Policy/policy/strategies/phone/selected_output_devices/mask
earpiece = 0
@@ -166,8 +162,8 @@
bluetooth_sco_headset = 0
bluetooth_sco_carkit = 0
bluetooth_a2dp = 0
- bluetooth_a2dp_headphones = 1
- bluetooth_a2dp_speaker = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 1
hdmi = 0
angl_dock_headset = 0
dgtl_dock_headset = 0
@@ -463,6 +459,9 @@
speaker = 1
conf: Default
+ #
+ # Fallback on default output device which can be speaker for example
+ #
component: /Policy/policy/strategies/phone/selected_output_devices/mask
earpiece = 0
wired_headset = 0
@@ -480,6 +479,6 @@
usb_device = 0
telephony_tx = 0
line = 0
- speaker = 0
+ speaker = 1
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/volumes.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/volumes.pfw
index 1049564..7db4537 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/volumes.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/volumes.pfw
@@ -1,462 +1,18 @@
supDomain: VolumeProfilesForStream
domain: Calibration
conf: Calibration
- component: /Policy/policy/streams
- component: voice_call/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -18.0
- 2/index = 66
- 2/db_attenuation = -12.0
- 3/index = 100
- 3/db_attenuation = -6.0
- component: speaker_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -16.0
- 2/index = 66
- 2/db_attenuation = -8.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: earpiece_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -18.0
- 2/index = 66
- 2/db_attenuation = -12.0
- 3/index = 100
- 3/db_attenuation = -6.0
- component: extmedia_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
-
- component: system/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -30.0
- 1/index = 33
- 1/db_attenuation = -26.0
- 2/index = 66
- 2/db_attenuation = -22.0
- 3/index = 100
- 3/db_attenuation = -18.0
- component: speaker_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -18.0
- 2/index = 66
- 2/db_attenuation = -12.0
- 3/index = 100
- 3/db_attenuation = -6.0
- component: earpiece_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -18.0
- 2/index = 66
- 2/db_attenuation = -12.0
- 3/index = 100
- 3/db_attenuation = -6.0
- component: extmedia_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -21.0
- 3/index = 100
- 3/db_attenuation = -10.0
-
- component: ring/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -49.5
- 1/index = 33
- 1/db_attenuation = -33.5
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: speaker_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -35.7
- 1/index = 33
- 1/db_attenuation = -26.1
- 2/index = 66
- 2/db_attenuation = -13.2
- 3/index = 100
- 3/db_attenuation = 0.0
- component: earpiece_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -49.5
- 1/index = 33
- 1/db_attenuation = -33.5
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: extmedia_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -27.0
- 3/index = 100
- 3/db_attenuation = -10.0
-
- component: music/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: speaker_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -56.0
- 1/index = 33
- 1/db_attenuation = -34.0
- 2/index = 66
- 2/db_attenuation = -11.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: earpiece_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: extmedia_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
-
- component: alarm/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -49.5
- 1/index = 33
- 1/db_attenuation = -33.5
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: speaker_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -35.7
- 1/index = 33
- 1/db_attenuation = -26.1
- 2/index = 66
- 2/db_attenuation = -13.2
- 3/index = 100
- 3/db_attenuation = 0.0
- component: earpiece_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -49.5
- 1/index = 33
- 1/db_attenuation = -33.5
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: extmedia_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -27.0
- 3/index = 100
- 3/db_attenuation = -10.0
-
- component: notification/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -49.5
- 1/index = 33
- 1/db_attenuation = -33.5
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: speaker_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -35.7
- 1/index = 33
- 1/db_attenuation = -26.1
- 2/index = 66
- 2/db_attenuation = -13.2
- 3/index = 100
- 3/db_attenuation = 0.0
- component: earpiece_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -49.5
- 1/index = 33
- 1/db_attenuation = -33.5
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: extmedia_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -27.0
- 3/index = 100
- 3/db_attenuation = -10.0
-
- component: bluetooth_sco/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -18.0
- 2/index = 66
- 2/db_attenuation = -12.0
- 3/index = 100
- 3/db_attenuation = -6.0
- component: speaker_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -16.0
- 2/index = 66
- 2/db_attenuation = -8.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: earpiece_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -18.0
- 2/index = 66
- 2/db_attenuation = -12.0
- 3/index = 100
- 3/db_attenuation = -6.0
- component: extmedia_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
-
- component: enforced_audible/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -30.0
- 1/index = 33
- 1/db_attenuation = -26.0
- 2/index = 66
- 2/db_attenuation = -22.0
- 3/index = 100
- 3/db_attenuation = -18.0
- component: speaker_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -18.0
- 2/index = 66
- 2/db_attenuation = -12.0
- 3/index = 100
- 3/db_attenuation = -6.0
- component: earpiece_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -18.0
- 2/index = 66
- 2/db_attenuation = -12.0
- 3/index = 100
- 3/db_attenuation = -6.0
- component: extmedia_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -27.0
- 3/index = 100
- 3/db_attenuation = -10.0
-
- component: tts/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = -96.0
- 1/index = 1
- 1/db_attenuation = -96.0
- 2/index = 2
- 2/db_attenuation = -96.0
- 3/index = 100
- 3/db_attenuation = -96.0
- component: speaker_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = -96.0
- 1/index = 33
- 1/db_attenuation = -68.0
- 2/index = 66
- 2/db_attenuation = -34.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: earpiece_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = -96.0
- 1/index = 1
- 1/db_attenuation = -96.0
- 2/index = 2
- 2/db_attenuation = -96.0
- 3/index = 100
- 3/db_attenuation = -96.0
- component: extmedia_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = -96.0
- 1/index = 1
- 1/db_attenuation = -96.0
- 2/index = 2
- 2/db_attenuation = -96.0
- 3/index = 100
- 3/db_attenuation = -96.0
-
- component: accessibility/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: speaker_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -56.0
- 1/index = 33
- 1/db_attenuation = -34.0
- 2/index = 66
- 2/db_attenuation = -11.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: earpiece_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: extmedia_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
-
- component: rerouting/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = 0.0
- 1/index = 1
- 1/db_attenuation = 0.0
- 2/index = 2
- 2/db_attenuation = 0.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: speaker_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = 0.0
- 1/index = 1
- 1/db_attenuation = 0.0
- 2/index = 2
- 2/db_attenuation = 0.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: earpiece_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = 0.0
- 1/index = 1
- 1/db_attenuation = 0.0
- 2/index = 2
- 2/db_attenuation = 0.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: extmedia_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = 0.0
- 1/index = 1
- 1/db_attenuation = 0.0
- 2/index = 2
- 2/db_attenuation = 0.0
- 3/index = 100
- 3/db_attenuation = 0.0
-
- component: patch/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = 0.0
- 1/index = 1
- 1/db_attenuation = 0.0
- 2/index = 2
- 2/db_attenuation = 0.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: speaker_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = 0.0
- 1/index = 1
- 1/db_attenuation = 0.0
- 2/index = 2
- 2/db_attenuation = 0.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: earpiece_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = 0.0
- 1/index = 1
- 1/db_attenuation = 0.0
- 2/index = 2
- 2/db_attenuation = 0.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: extmedia_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = 0.0
- 1/index = 1
- 1/db_attenuation = 0.0
- 2/index = 2
- 2/db_attenuation = 0.0
- 3/index = 100
- 3/db_attenuation = 0.0
+ /Policy/policy/streams/voice_call/applicable_volume_profile/volume_profile = voice_call
+ /Policy/policy/streams/system/applicable_volume_profile/volume_profile = system
+ /Policy/policy/streams/ring/applicable_volume_profile/volume_profile = ring
+ /Policy/policy/streams/music/applicable_volume_profile/volume_profile = music
+ /Policy/policy/streams/alarm/applicable_volume_profile/volume_profile = alarm
+ /Policy/policy/streams/notification/applicable_volume_profile/volume_profile = notification
+ /Policy/policy/streams/bluetooth_sco/applicable_volume_profile/volume_profile = bluetooth_sco
+ /Policy/policy/streams/enforced_audible/applicable_volume_profile/volume_profile = enforced_audible
+ /Policy/policy/streams/tts/applicable_volume_profile/volume_profile = tts
+ /Policy/policy/streams/accessibility/applicable_volume_profile/volume_profile = accessibility
+ /Policy/policy/streams/rerouting/applicable_volume_profile/volume_profile = rerouting
+ /Policy/policy/streams/patch/applicable_volume_profile/volume_profile = patch
domain: Dtmf
conf: InCall
@@ -464,82 +20,9 @@
TelephonyMode Is InCall
TelephonyMode Is InCommunication
- component: /Policy/policy/streams
- component: dtmf/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -30.0
- 1/index = 33
- 1/db_attenuation = -26.0
- 2/index = 66
- 2/db_attenuation = -22.0
- 3/index = 100
- 3/db_attenuation = -18.0
- component: speaker_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -18.0
- 2/index = 66
- 2/db_attenuation = -12.0
- 3/index = 100
- 3/db_attenuation = -6.0
- component: earpiece_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -18.0
- 2/index = 66
- 2/db_attenuation = -12.0
- 3/index = 100
- 3/db_attenuation = -6.0
- component: extmedia_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -27.0
- 3/index = 100
- 3/db_attenuation = -10.0
+ /Policy/policy/streams/dtmf/applicable_volume_profile/volume_profile = voice_call
conf: OutOfCall
- component: /Policy/policy/streams
- component: dtmf/volume_profiles
- component: headset_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -18.0
- 2/index = 66
- 2/db_attenuation = -12.0
- 3/index = 100
- 3/db_attenuation = -6.0
- component: speaker_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -16.0
- 2/index = 66
- 2/db_attenuation = -8.0
- 3/index = 100
- 3/db_attenuation = 0.0
- component: earpiece_device_category/curve_points
- 0/index = 0
- 0/db_attenuation = -24.0
- 1/index = 33
- 1/db_attenuation = -18.0
- 2/index = 66
- 2/db_attenuation = -12.0
- 3/index = 100
- 3/db_attenuation = -6.0
- component: extmedia_device_category/curve_points
- 0/index = 1
- 0/db_attenuation = -58.0
- 1/index = 33
- 1/db_attenuation = -40.0
- 2/index = 66
- 2/db_attenuation = -17.0
- 3/index = 100
- 3/db_attenuation = 0.0
+ /Policy/policy/streams/dtmf/applicable_volume_profile/volume_profile = dtmf
+
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-CommonTypes.xml b/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-CommonTypes.xml
index 821d6ad..6d6145a 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-CommonTypes.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-CommonTypes.xml
@@ -6,8 +6,6 @@
profile. It must match with the output device enum parameter.
-->
<!--#################### GLOBAL COMPONENTS BEGIN ####################-->
- <!-- Common Types defintion -->
- <xi:include href="PolicySubsystem-Volume.xml"/>
<!--#################### GLOBAL COMPONENTS END ####################-->
@@ -30,7 +28,7 @@
<BitParameter Name="usb_accessory" Size="1" Pos="13"/>
<BitParameter Name="usb_device" Size="1" Pos="14"/>
<BitParameter Name="remote_submix" Size="1" Pos="15"/>
- <BitParameter Name="telephony_tx" Size="1" Pos="26"/>
+ <BitParameter Name="telephony_tx" Size="1" Pos="16"/>
<BitParameter Name="line" Size="1" Pos="17"/>
<BitParameter Name="hdmi_arc" Size="1" Pos="18"/>
<BitParameter Name="spdif" Size="1" Pos="19"/>
@@ -111,8 +109,9 @@
<BitParameter Name="voice_recognition" Size="1" Pos="6"/>
<BitParameter Name="voice_communication" Size="1" Pos="7"/>
<BitParameter Name="remote_submix" Size="1" Pos="8"/>
- <BitParameter Name="fm_tuner" Size="1" Pos="9"/>
- <BitParameter Name="hotword" Size="1" Pos="10"/>
+ <BitParameter Name="unprocessed" Size="1" Pos="9"/>
+ <BitParameter Name="fm_tuner" Size="1" Pos="10"/>
+ <BitParameter Name="hotword" Size="1" Pos="11"/>
</BitParameterBlock>
</ComponentType>
@@ -142,10 +141,28 @@
<!--#################### STREAM COMMON TYPES BEGIN ####################-->
+ <ComponentType Name="VolumeProfileType">
+ <EnumParameter Name="volume_profile" Size="32">
+ <ValuePair Literal="voice_call" Numerical="0"/>
+ <ValuePair Literal="system" Numerical="1"/>
+ <ValuePair Literal="ring" Numerical="2"/>
+ <ValuePair Literal="music" Numerical="3"/>
+ <ValuePair Literal="alarm" Numerical="4"/>
+ <ValuePair Literal="notification" Numerical="5"/>
+ <ValuePair Literal="bluetooth_sco" Numerical="6"/>
+ <ValuePair Literal="enforced_audible" Numerical="7"/>
+ <ValuePair Literal="dtmf" Numerical="8"/>
+ <ValuePair Literal="tts" Numerical="9"/>
+ <ValuePair Literal="accessibility" Numerical="10"/>
+ <ValuePair Literal="rerouting" Numerical="11"/>
+ <ValuePair Literal="patch" Numerical="12"/>
+ </EnumParameter>
+ </ComponentType>
+
<ComponentType Name="Stream">
- <Component Name="applicable_strategy" Type="Strategy" Mapping="Stream:'%1'"/>
- <Component Name="volume_profiles" Type="VolumeCurvesCategories"
- Description="A volume profile is refered by the stream type."/>
+ <Component Name="applicable_strategy" Type="Strategy"/>
+ <Component Name="applicable_volume_profile" Type="VolumeProfileType"
+ Description="Volume profile followed by a given stream type."/>
</ComponentType>
<!--#################### STREAM COMMON TYPES END ####################-->
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-Volume.xml b/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-Volume.xml
deleted file mode 100755
index cf39cc2..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-Volume.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ComponentTypeSet xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
- <ComponentType Name="VolumeCurvePoints">
- <ParameterBlock Name="curve_points" ArrayLength="4" Mapping="VolumeProfile:'%1'"
- Description="4 points to define the volume attenuation curve, each
- characterized by the volume index (from 0 to 100) at which
- they apply, and the attenuation in dB at that index.
- We use 100 steps to avoid rounding errors when computing
- the volume">
- <IntegerParameter Name="index" Size="32"/>
- <FixedPointParameter Name="db_attenuation" Size="16" Integral="7" Fractional="8"/>
- </ParameterBlock>
- </ComponentType>
-
- <ComponentType Name="VolumeCurvesCategories">
- <Component Name="headset_device_category" Type="VolumeCurvePoints" Mapping="Category:0"/>
- <Component Name="speaker_device_category" Type="VolumeCurvePoints" Mapping="Category:1"/>
- <Component Name="earpiece_device_category" Type="VolumeCurvePoints" Mapping="Category:2"/>
- <Component Name="extmedia_device_category" Type="VolumeCurvePoints" Mapping="Category:3"/>
- </ComponentType>
-
-</ComponentTypeSet>
-
-
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem.xml b/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem.xml
index b21f6ae..e35511c 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem.xml
@@ -38,29 +38,29 @@
<ComponentType Name="Streams" Description="associated to audio_stream_type_t definition,
identifier mapping must match the value of the enum">
- <Component Name="voice_call" Type="Stream" Mapping="Amend1:VoiceCall,Identifier:0"/>
- <Component Name="system" Type="Stream" Mapping="Amend1:System,Identifier:1"/>
- <Component Name="ring" Type="Stream" Mapping="Amend1:Ring,Identifier:2"/>
- <Component Name="music" Type="Stream" Mapping="Amend1:Music,Identifier:3"/>
- <Component Name="alarm" Type="Stream" Mapping="Amend1:Alarm,Identifier:4"/>
+ <Component Name="voice_call" Type="Stream" Mapping="Stream:VoiceCall,Identifier:0"/>
+ <Component Name="system" Type="Stream" Mapping="Stream:System,Identifier:1"/>
+ <Component Name="ring" Type="Stream" Mapping="Stream:Ring,Identifier:2"/>
+ <Component Name="music" Type="Stream" Mapping="Stream:Music,Identifier:3"/>
+ <Component Name="alarm" Type="Stream" Mapping="Stream:Alarm,Identifier:4"/>
<Component Name="notification" Type="Stream"
- Mapping="Amend1:Notification,Identifier:5"/>
+ Mapping="Stream:Notification,Identifier:5"/>
<Component Name="bluetooth_sco" Type="Stream"
- Mapping="Amend1:BluetoothSco,Identifier:6"/>
+ Mapping="Stream:BluetoothSco,Identifier:6"/>
<Component Name="enforced_audible" Type="Stream"
- Mapping="Amend1:EnforceAudible,Identifier:7"
+ Mapping="Stream:EnforceAudible,Identifier:7"
Description="Sounds that cannot be muted by user and must
be routed to speaker"/>
- <Component Name="dtmf" Type="Stream" Mapping="Amend1:Dtmf,Identifier:8"/>
- <Component Name="tts" Type="Stream" Mapping="Amend1:Tts,Identifier:9"
+ <Component Name="dtmf" Type="Stream" Mapping="Stream:Dtmf,Identifier:8"/>
+ <Component Name="tts" Type="Stream" Mapping="Stream:Tts,Identifier:9"
Description="Transmitted Through Speaker.
Plays over speaker only, silent on other devices"/>
<Component Name="accessibility" Type="Stream"
- Mapping="Amend1:Accessibility,Identifier:10"
+ Mapping="Stream:Accessibility,Identifier:10"
Description="For accessibility talk back prompts"/>
- <Component Name="rerouting" Type="Stream" Mapping="Amend1:Rerouting,Identifier:11"
+ <Component Name="rerouting" Type="Stream" Mapping="Stream:Rerouting,Identifier:11"
Description="For dynamic policy output mixes"/>
- <Component Name="patch" Type="Stream" Mapping="Amend1:Patch,Identifier:12"
+ <Component Name="patch" Type="Stream" Mapping="Stream:Patch,Identifier:12"
Description="For internal audio flinger tracks. Fixed volume"/>
</ComponentType>
@@ -120,6 +120,8 @@
Mapping="Amend1:VoiceCommunication,Identifier:7"/>
<Component Name="remote_submix" Type="InputSource"
Mapping="Amend1:RemoteSubmix,Identifier:8"/>
+ <Component Name="unprocessed" Type="InputSource"
+ Mapping="Amend1:Unprocessed,Identifier:9"/>
<Component Name="fm_tuner" Type="InputSource" Mapping="Amend1:FmTuner,Identifier:1998"/>
<Component Name="hotword" Type="InputSource" Mapping="Amend1:Hotword,Identifier:1999"/>
</ComponentType>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
index a523656..c65de92 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
@@ -8,7 +8,6 @@
PolicySubsystem.cpp \
Strategy.cpp \
InputSource.cpp \
- VolumeProfile.cpp \
Stream.cpp \
Usage.cpp
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
index 497d555..ccb10ae 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
@@ -30,24 +30,16 @@
context),
mPolicySubsystem(static_cast<const PolicySubsystem *>(
instanceConfigurableElement->getBelongingSubsystem())),
- mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
- mApplicableInputDevice(mDefaultApplicableInputDevice)
+ mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
{
mId = static_cast<audio_source_t>(context.getItemAsInteger(MappingKeyIdentifier));
// Declares the strategy to audio policy engine
mPolicyPluginInterface->addInputSource(getFormattedMappingValue(), mId);
}
-bool InputSource::receiveFromHW(string & /*error*/)
-{
- blackboardWrite(&mApplicableInputDevice, sizeof(mApplicableInputDevice));
- return true;
-}
-
bool InputSource::sendToHW(string & /*error*/)
{
uint32_t applicableInputDevice;
blackboardRead(&applicableInputDevice, sizeof(applicableInputDevice));
- mApplicableInputDevice = applicableInputDevice;
- return mPolicyPluginInterface->setDeviceForInputSource(mId, mApplicableInputDevice);
+ return mPolicyPluginInterface->setDeviceForInputSource(mId, applicableInputDevice);
}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h
index 67c5b50..0db4f70 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h
@@ -32,7 +32,6 @@
const CMappingContext &context);
protected:
- virtual bool receiveFromHW(std::string &error);
virtual bool sendToHW(std::string &error);
private:
@@ -44,6 +43,4 @@
android::AudioPolicyPluginInterface *mPolicyPluginInterface;
audio_source_t mId; /**< input source identifier to link with audio.h. */
- uint32_t mApplicableInputDevice; /**< applicable input device for this strategy. */
- static const uint32_t mDefaultApplicableInputDevice = 0; /**< default input device. */
};
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
index bf3906d..6412134 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
@@ -20,7 +20,6 @@
#include "Strategy.h"
#include "Stream.h"
#include "InputSource.h"
-#include "VolumeProfile.h"
#include "Usage.h"
#include <AudioPolicyPluginInterface.h>
#include <AudioPolicyEngineInstance.h>
@@ -40,7 +39,6 @@
const char *const PolicySubsystem::mStrategyComponentName = "Strategy";
const char *const PolicySubsystem::mInputSourceComponentName = "InputSource";
const char *const PolicySubsystem::mUsageComponentName = "Usage";
-const char *const PolicySubsystem::mVolumeProfileComponentName = "VolumeProfile";
PolicySubsystem::PolicySubsystem(const std::string &name)
: CSubsystem(name),
@@ -67,7 +65,7 @@
addSubsystemObjectFactory(
new TSubsystemObjectFactory<Stream>(
mStreamComponentName,
- (1 << MappingKeyAmend1) | (1 << MappingKeyIdentifier))
+ (1 << MappingKeyIdentifier))
);
addSubsystemObjectFactory(
new TSubsystemObjectFactory<Strategy>(
@@ -84,11 +82,6 @@
mInputSourceComponentName,
(1 << MappingKeyAmend1) | (1 << MappingKeyIdentifier))
);
- addSubsystemObjectFactory(
- new TSubsystemObjectFactory<VolumeProfile>(
- mVolumeProfileComponentName,
- (1 << MappingKeyAmend1) | (1 << MappingKeyIdentifier) | (1 << MappingKeyIdentifier))
- );
}
// Retrieve Route interface
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.h
index 3c26fe1..e3143a5 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.h
@@ -56,5 +56,4 @@
static const char *const mStrategyComponentName;
static const char *const mInputSourceComponentName;
static const char *const mUsageComponentName;
- static const char *const mVolumeProfileComponentName;
};
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
index 1848813..5c536d5 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
@@ -31,8 +31,7 @@
context),
mPolicySubsystem(static_cast<const PolicySubsystem *>(
instanceConfigurableElement->getBelongingSubsystem())),
- mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
- mApplicableOutputDevice(mDefaultApplicableOutputDevice)
+ mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
{
mId = static_cast<routing_strategy>(context.getItemAsInteger(MappingKeyIdentifier));
@@ -40,12 +39,6 @@
mPolicyPluginInterface->addStrategy(getFormattedMappingValue(), mId);
}
-bool Strategy::receiveFromHW(string & /*error*/)
-{
- blackboardWrite(&mApplicableOutputDevice, sizeof(mApplicableOutputDevice));
- return true;
-}
-
bool Strategy::sendToHW(string & /*error*/)
{
uint32_t applicableOutputDevice;
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h
index 9a9b3e4..cbb72e2 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h
@@ -32,7 +32,6 @@
const CMappingContext &context);
protected:
- virtual bool receiveFromHW(std::string &error);
virtual bool sendToHW(std::string &error);
private:
@@ -44,6 +43,4 @@
android::AudioPolicyPluginInterface *mPolicyPluginInterface;
android::routing_strategy mId; /**< strategy identifier to link with audio.h.*/
- uint32_t mApplicableOutputDevice; /**< applicable output device for this strategy. */
- static const uint32_t mDefaultApplicableOutputDevice = 0; /**< default output device. */
};
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.cpp
index 575b0bb..4387634 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.cpp
@@ -24,15 +24,10 @@
Stream::Stream(const string &mappingValue,
CInstanceConfigurableElement *instanceConfigurableElement,
const CMappingContext &context)
- : CFormattedSubsystemObject(instanceConfigurableElement,
- mappingValue,
- MappingKeyAmend1,
- (MappingKeyAmendEnd - MappingKeyAmend1 + 1),
- context),
+ : CSubsystemObject(instanceConfigurableElement),
mPolicySubsystem(static_cast<const PolicySubsystem *>(
instanceConfigurableElement->getBelongingSubsystem())),
- mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
- mApplicableStrategy(mDefaultApplicableStrategy)
+ mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
{
mId = static_cast<audio_stream_type_t>(context.getItemAsInteger(MappingKeyIdentifier));
@@ -40,17 +35,17 @@
mPolicyPluginInterface->addStream(getFormattedMappingValue(), mId);
}
-bool Stream::receiveFromHW(string & /*error*/)
-{
- blackboardWrite(&mApplicableStrategy, sizeof(mApplicableStrategy));
- return true;
-}
-
bool Stream::sendToHW(string & /*error*/)
{
- uint32_t applicableStrategy;
- blackboardRead(&applicableStrategy, sizeof(applicableStrategy));
- mApplicableStrategy = applicableStrategy;
- return mPolicyPluginInterface->setStrategyForStream(mId,
- static_cast<routing_strategy>(mApplicableStrategy));
+ Applicable params;
+ blackboardRead(¶ms, sizeof(params));
+
+ mPolicyPluginInterface->setStrategyForStream(mId,
+ static_cast<routing_strategy>(params.strategy));
+
+ mPolicyPluginInterface->setVolumeProfileForStream(mId,
+ static_cast<audio_stream_type_t>(params.volumeProfile));
+
+ return true;
+
}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.h
index 7d90c36..4b0e081 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.h
@@ -16,7 +16,7 @@
#pragma once
-#include "FormattedSubsystemObject.h"
+#include "SubsystemObject.h"
#include "InstanceConfigurableElement.h"
#include "MappingContext.h"
#include <AudioPolicyPluginInterface.h>
@@ -24,15 +24,21 @@
class PolicySubsystem;
-class Stream : public CFormattedSubsystemObject
+class Stream : public CSubsystemObject
{
+private:
+ struct Applicable
+ {
+ uint32_t strategy; /**< applicable strategy for this stream. */
+ uint32_t volumeProfile; /**< applicable strategy for this stream. */
+ } __attribute__((packed));
+
public:
Stream(const std::string &mappingValue,
CInstanceConfigurableElement *instanceConfigurableElement,
const CMappingContext &context);
protected:
- virtual bool receiveFromHW(std::string &error);
virtual bool sendToHW(std::string &error);
private:
@@ -42,8 +48,5 @@
* Interface to communicate with Audio Policy Engine.
*/
android::AudioPolicyPluginInterface *mPolicyPluginInterface;
-
audio_stream_type_t mId; /**< stream type identifier to link with audio.h. */
- uint32_t mApplicableStrategy; /**< applicable strategy for this stream. */
- static const uint32_t mDefaultApplicableStrategy = 0; /**< default strategy. */
};
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
index 1916b9b..eb7d78f 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
@@ -31,8 +31,7 @@
context),
mPolicySubsystem(static_cast<const PolicySubsystem *>(
instanceConfigurableElement->getBelongingSubsystem())),
- mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
- mApplicableStrategy(mDefaultApplicableStrategy)
+ mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
{
mId = static_cast<audio_usage_t>(context.getItemAsInteger(MappingKeyIdentifier));
@@ -40,17 +39,10 @@
mPolicyPluginInterface->addUsage(getFormattedMappingValue(), mId);
}
-bool Usage::receiveFromHW(string & /*error*/)
-{
- blackboardWrite(&mApplicableStrategy, sizeof(mApplicableStrategy));
- return true;
-}
-
bool Usage::sendToHW(string & /*error*/)
{
uint32_t applicableStrategy;
blackboardRead(&applicableStrategy, sizeof(applicableStrategy));
- mApplicableStrategy = applicableStrategy;
return mPolicyPluginInterface->setStrategyForUsage(mId,
- static_cast<routing_strategy>(mApplicableStrategy));
+ static_cast<routing_strategy>(applicableStrategy));
}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h
index 8e9b638..3b82f8c 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h
@@ -32,7 +32,6 @@
const CMappingContext &context);
protected:
- virtual bool receiveFromHW(std::string &error);
virtual bool sendToHW(std::string &error);
private:
@@ -44,6 +43,4 @@
android::AudioPolicyPluginInterface *mPolicyPluginInterface;
audio_usage_t mId; /**< usage identifier to link with audio.h. */
- uint32_t mApplicableStrategy; /**< applicable strategy for this usage. */
- static const uint32_t mDefaultApplicableStrategy = 0; /**< default strategy. */
};
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.cpp
deleted file mode 100755
index 5c155c8..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.cpp
+++ /dev/null
@@ -1,75 +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.
- */
-
-#include "VolumeProfile.h"
-#include "PolicyMappingKeys.h"
-#include "PolicySubsystem.h"
-#include "ParameterBlockType.h"
-#include <Volume.h>
-#include <math.h>
-
-using std::string;
-
-VolumeProfile::VolumeProfile(const string &mappingValue,
- CInstanceConfigurableElement *instanceConfigurableElement,
- const CMappingContext &context)
- : CFormattedSubsystemObject(instanceConfigurableElement,
- mappingValue,
- MappingKeyAmend1,
- (MappingKeyAmendEnd - MappingKeyAmend1 + 1),
- context),
- mPolicySubsystem(static_cast<const PolicySubsystem *>(
- instanceConfigurableElement->getBelongingSubsystem())),
- mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
-{
- uint32_t categoryKey = context.getItemAsInteger(MappingKeyCategory);
- if (categoryKey >= Volume::DEVICE_CATEGORY_CNT) {
- mCategory = Volume::DEVICE_CATEGORY_SPEAKER;
- } else {
- mCategory = static_cast<Volume::device_category>(categoryKey);
- }
- mId = static_cast<audio_stream_type_t>(context.getItemAsInteger(MappingKeyIdentifier));
-
- // (no exception support, defer the error)
- if (instanceConfigurableElement->getType() != CInstanceConfigurableElement::EParameterBlock) {
- return;
- }
- // Get actual element type
- const CParameterBlockType *parameterType = static_cast<const CParameterBlockType *>(
- instanceConfigurableElement->getTypeElement());
- mPoints = parameterType->getArrayLength();
-}
-
-bool VolumeProfile::receiveFromHW(string & /*error*/)
-{
- return true;
-}
-
-bool VolumeProfile::sendToHW(string & /*error*/)
-{
- Point points[mPoints];
- blackboardRead(&points, sizeof(Point) * mPoints);
-
- VolumeCurvePoints pointsVector;
- for (size_t i = 0; i < mPoints; i++) {
- VolumeCurvePoint curvePoint;
- curvePoint.mIndex = points[i].index;
- curvePoint.mDBAttenuation = static_cast<float>(points[i].dbAttenuation) /
- (1UL << gFractional);
- pointsVector.push_back(curvePoint);
- }
- return mPolicyPluginInterface->setVolumeProfileForStream(mId, mCategory, pointsVector);
-}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.h
deleted file mode 100755
index a00ae84..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.h
+++ /dev/null
@@ -1,64 +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.
- */
-
-#pragma once
-
-#include "FormattedSubsystemObject.h"
-#include "InstanceConfigurableElement.h"
-#include "MappingContext.h"
-#include <Volume.h>
-#include <AudioPolicyPluginInterface.h>
-#include <string>
-
-class PolicySubsystem;
-
-class VolumeProfile : public CFormattedSubsystemObject
-{
-private:
- struct Point
- {
- int index;
- /** Volume is using FixedPointParameter until float parameters are available. */
- int16_t dbAttenuation;
- } __attribute__((packed));
-
-public:
- VolumeProfile(const std::string &mappingValue,
- CInstanceConfigurableElement *instanceConfigurableElement,
- const CMappingContext &context);
-
-protected:
- virtual bool receiveFromHW(std::string &error);
- virtual bool sendToHW(std::string &error);
-
-private:
- const PolicySubsystem *mPolicySubsystem; /**< Route subsytem plugin. */
-
- /**
- * Interface to communicate with Audio Policy Engine.
- */
- android::AudioPolicyPluginInterface *mPolicyPluginInterface;
-
- /**
- * volume profile identifier, which is in fact a stream type to link with audio.h.
- */
- audio_stream_type_t mId;
-
- size_t mPoints;
- Volume::device_category mCategory;
-
- static const uint32_t gFractional = 8; /**< Beware to align with the structure. */
-};
diff --git a/services/audiopolicy/engineconfigurable/src/Collection.h b/services/audiopolicy/engineconfigurable/src/Collection.h
index 8f17b15..b72ded8 100755
--- a/services/audiopolicy/engineconfigurable/src/Collection.h
+++ b/services/audiopolicy/engineconfigurable/src/Collection.h
@@ -47,6 +47,7 @@
class Collection : public std::map<Key, Element<Key> *>
{
private:
+ typedef std::map<Key, Element<Key> *> Base;
typedef Element<Key> T;
typedef typename std::map<Key, T *>::iterator CollectionIterator;
typedef typename std::map<Key, T *>::const_iterator CollectionConstIterator;
@@ -127,7 +128,7 @@
for (it = (*this).begin(); it != (*this).end(); ++it) {
delete it->second;
}
- (*this).clear();
+ Base::clear();
}
private:
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 733cdf6..ed807c6 100755
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -106,27 +106,13 @@
status_t Engine::initCheck()
{
- if (mPolicyParameterMgr != NULL && mPolicyParameterMgr->start() != NO_ERROR) {
+ if (mPolicyParameterMgr == NULL || mPolicyParameterMgr->start() != NO_ERROR) {
ALOGE("%s: could not start Policy PFW", __FUNCTION__);
- delete mPolicyParameterMgr;
- mPolicyParameterMgr = NULL;
return NO_INIT;
}
return (mApmObserver != NULL)? NO_ERROR : NO_INIT;
}
-bool Engine::setVolumeProfileForStream(const audio_stream_type_t &streamType,
- Volume::device_category deviceCategory,
- const VolumeCurvePoints &points)
-{
- Stream *stream = getFromCollection<audio_stream_type_t>(streamType);
- if (stream == NULL) {
- ALOGE("%s: stream %d not found", __FUNCTION__, streamType);
- return false;
- }
- return stream->setVolumeProfile(deviceCategory, points) == NO_ERROR;
-}
-
template <typename Key>
Element<Key> *Engine::getFromCollection(const Key &key) const
{
@@ -188,6 +174,18 @@
return mPolicyEngine->getPropertyForKey<audio_devices_t, routing_strategy>(strategy);
}
+bool Engine::PluginInterfaceImpl::setVolumeProfileForStream(const audio_stream_type_t &stream,
+ const audio_stream_type_t &profile)
+{
+ if (mPolicyEngine->setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream,
+ profile)) {
+ mPolicyEngine->mApmObserver->getVolumeCurves().switchVolumeCurve(profile, stream);
+ return true;
+ }
+ return false;
+}
+
+
template <typename Property, typename Key>
bool Engine::setPropertyForKey(const Property &property, const Key &key)
{
@@ -199,32 +197,6 @@
return element->template set<Property>(property) == NO_ERROR;
}
-float Engine::volIndexToDb(Volume::device_category category,
- audio_stream_type_t streamType,
- int indexInUi)
-{
- Stream *stream = getFromCollection<audio_stream_type_t>(streamType);
- if (stream == NULL) {
- ALOGE("%s: Element indexed by key=%d not found", __FUNCTION__, streamType);
- return 1.0f;
- }
- return stream->volIndexToDb(category, indexInUi);
-}
-
-status_t Engine::initStreamVolume(audio_stream_type_t streamType,
- int indexMin, int indexMax)
-{
- Stream *stream = getFromCollection<audio_stream_type_t>(streamType);
- if (stream == NULL) {
- ALOGE("%s: Stream Type %d not found", __FUNCTION__, streamType);
- return BAD_TYPE;
- }
- mApmObserver->getStreamDescriptors().setVolumeIndexMin(streamType, indexMin);
- mApmObserver->getStreamDescriptors().setVolumeIndexMax(streamType, indexMax);
-
- return stream->initVolume(indexMin, indexMax);
-}
-
status_t Engine::setPhoneState(audio_mode_t mode)
{
return mPolicyParameterMgr->setPhoneState(mode);
@@ -246,10 +218,17 @@
return mPolicyParameterMgr->getForceUse(usage);
}
-status_t Engine::setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state,
- const char *deviceAddress)
+status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+ audio_policy_dev_state_t /*state*/)
{
- return mPolicyParameterMgr->setDeviceConnectionState(devices, state, deviceAddress);
+ if (audio_is_output_device(devDesc->type())) {
+ return mPolicyParameterMgr->setAvailableOutputDevices(
+ mApmObserver->getAvailableOutputDevices().types());
+ } else if (audio_is_input_device(devDesc->type())) {
+ return mPolicyParameterMgr->setAvailableInputDevices(
+ mApmObserver->getAvailableInputDevices().types());
+ }
+ return BAD_TYPE;
}
template <>
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index 6fa7a13..bc5e035 100755
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -86,22 +86,7 @@
virtual android::status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
audio_policy_dev_state_t state)
{
- return mPolicyEngine->setDeviceConnectionState(devDesc->type(), state,
- devDesc->mAddress);
- }
- virtual status_t initStreamVolume(audio_stream_type_t stream,
- int indexMin, int indexMax)
- {
- return mPolicyEngine->initStreamVolume(stream, indexMin, indexMax);
- }
-
- virtual void initializeVolumeCurves(bool /*isSpeakerDrcEnabled*/) {}
-
- virtual float volIndexToDb(Volume::device_category deviceCategory,
- audio_stream_type_t stream,
- int indexInUi)
- {
- return mPolicyEngine->volIndexToDb(deviceCategory, stream, indexInUi);
+ return mPolicyEngine->setDeviceConnectionState(devDesc, state);
}
private:
@@ -142,11 +127,7 @@
stream);
}
virtual bool setVolumeProfileForStream(const audio_stream_type_t &stream,
- Volume::device_category deviceCategory,
- const VolumeCurvePoints &points)
- {
- return mPolicyEngine->setVolumeProfileForStream(stream, deviceCategory, points);
- }
+ const audio_stream_type_t &volumeProfile);
virtual bool setStrategyForUsage(const audio_usage_t &usage, routing_strategy strategy)
{
@@ -172,7 +153,7 @@
void setObserver(AudioPolicyManagerObserver *observer);
bool setVolumeProfileForStream(const audio_stream_type_t &stream,
- Volume::device_category deviceCategory,
+ device_category deviceCategory,
const VolumeCurvePoints &points);
status_t initCheck();
@@ -180,14 +161,8 @@
audio_mode_t getPhoneState() const;
status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config);
audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const;
- status_t setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state,
- const char *deviceAddress);
-
- float volIndexToDb(Volume::device_category category,
- audio_stream_type_t stream,
- int indexInUi);
- status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
-
+ status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+ audio_policy_dev_state_t state);
StrategyCollection mStrategyCollection; /**< Strategies indexed by their enum id. */
StreamCollection mStreamCollection; /**< Streams indexed by their enum id. */
UsageCollection mUsageCollection; /**< Usages indexed by their enum id. */
diff --git a/services/audiopolicy/engineconfigurable/src/Stream.cpp b/services/audiopolicy/engineconfigurable/src/Stream.cpp
index bea2c19..0ed364f 100755
--- a/services/audiopolicy/engineconfigurable/src/Stream.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Stream.cpp
@@ -62,92 +62,22 @@
return mApplicableStrategy;
}
-status_t Element<audio_stream_type_t>::setVolumeProfile(Volume::device_category category,
- const VolumeCurvePoints &points)
+template <>
+status_t Element<audio_stream_type_t>::set<audio_stream_type_t>(audio_stream_type_t volumeProfile)
{
- ALOGD("%s: adding volume profile for %s for device category %d, points nb =%d", __FUNCTION__,
- getName().c_str(), category, points.size());
- mVolumeProfiles[category] = points;
-
- for (size_t i = 0; i < points.size(); i++) {
- ALOGV("%s: %s cat=%d curve index =%d Index=%d dBAttenuation=%f",
- __FUNCTION__, getName().c_str(), category, i, points[i].mIndex,
- points[i].mDBAttenuation);
- }
- return NO_ERROR;
-}
-
-status_t Element<audio_stream_type_t>::initVolume(int indexMin, int indexMax)
-{
- ALOGV("initStreamVolume() stream %s, min %d, max %d", getName().c_str(), indexMin, indexMax);
- if (indexMin < 0 || indexMin >= indexMax) {
- ALOGW("initStreamVolume() invalid index limits for stream %s, min %d, max %d",
- getName().c_str(), indexMin, indexMax);
+ if (volumeProfile >= AUDIO_STREAM_CNT) {
return BAD_VALUE;
}
- mIndexMin = indexMin;
- mIndexMax = indexMax;
-
+ mVolumeProfile = volumeProfile;
+ ALOGD("%s: 0x%X for Stream %s", __FUNCTION__, mVolumeProfile, getName().c_str());
return NO_ERROR;
}
-float Element<audio_stream_type_t>::volIndexToDb(Volume::device_category deviceCategory,
- int indexInUi)
+template <>
+audio_stream_type_t Element<audio_stream_type_t>::get<audio_stream_type_t>() const
{
- VolumeProfileConstIterator it = mVolumeProfiles.find(deviceCategory);
- if (it == mVolumeProfiles.end()) {
- ALOGE("%s: device category %d not found for stream %s", __FUNCTION__, deviceCategory,
- getName().c_str());
- return 1.0f;
- }
- const VolumeCurvePoints curve = mVolumeProfiles[deviceCategory];
- if (curve.size() != Volume::VOLCNT) {
- ALOGE("%s: invalid profile for category %d and for stream %s", __FUNCTION__, deviceCategory,
- getName().c_str());
- return 1.0f;
- }
-
- // the volume index in the UI is relative to the min and max volume indices for this stream type
- int nbSteps = 1 + curve[Volume::VOLMAX].mIndex -
- curve[Volume::VOLMIN].mIndex;
-
- if (mIndexMax - mIndexMin == 0) {
- ALOGE("%s: Invalid volume indexes Min=Max=%d", __FUNCTION__, mIndexMin);
- return 1.0f;
- }
- int volIdx = (nbSteps * (indexInUi - mIndexMin)) /
- (mIndexMax - mIndexMin);
-
- // find what part of the curve this index volume belongs to, or if it's out of bounds
- int segment = 0;
- if (volIdx < curve[Volume::VOLMIN].mIndex) { // out of bounds
- return 0.0f;
- } else if (volIdx < curve[Volume::VOLKNEE1].mIndex) {
- segment = 0;
- } else if (volIdx < curve[Volume::VOLKNEE2].mIndex) {
- segment = 1;
- } else if (volIdx <= curve[Volume::VOLMAX].mIndex) {
- segment = 2;
- } else { // out of bounds
- return 1.0f;
- }
-
- // linear interpolation in the attenuation table in dB
- float decibels = curve[segment].mDBAttenuation +
- ((float)(volIdx - curve[segment].mIndex)) *
- ( (curve[segment+1].mDBAttenuation -
- curve[segment].mDBAttenuation) /
- ((float)(curve[segment+1].mIndex -
- curve[segment].mIndex)) );
-
- ALOGV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f]",
- curve[segment].mIndex, volIdx,
- curve[segment+1].mIndex,
- curve[segment].mDBAttenuation,
- decibels,
- curve[segment+1].mDBAttenuation);
-
- return decibels;
+ ALOGV("%s: 0x%X for Stream %s", __FUNCTION__, mVolumeProfile, getName().c_str());
+ return mVolumeProfile;
}
} // namespace audio_policy
diff --git a/services/audiopolicy/engineconfigurable/src/Stream.h b/services/audiopolicy/engineconfigurable/src/Stream.h
index 8c39dc6..6902003 100755
--- a/services/audiopolicy/engineconfigurable/src/Stream.h
+++ b/services/audiopolicy/engineconfigurable/src/Stream.h
@@ -18,7 +18,6 @@
#include "Element.h"
#include "EngineDefinition.h"
-#include <Volume.h>
#include <RoutingStrategy.h>
#include <map>
@@ -32,17 +31,10 @@
template <>
class Element<audio_stream_type_t>
{
-private:
- typedef std::map<Volume::device_category, VolumeCurvePoints> VolumeProfiles;
- typedef VolumeProfiles::iterator VolumeProfileIterator;
- typedef VolumeProfiles::const_iterator VolumeProfileConstIterator;
-
public:
Element(const std::string &name)
: mName(name),
- mApplicableStrategy(STRATEGY_MEDIA),
- mIndexMin(0),
- mIndexMax(1)
+ mApplicableStrategy(STRATEGY_MEDIA)
{}
~Element() {}
@@ -79,12 +71,6 @@
template <typename Property>
status_t set(Property property);
- status_t setVolumeProfile(Volume::device_category category, const VolumeCurvePoints &points);
-
- float volIndexToDb(Volume::device_category deviceCategory, int indexInUi);
-
- status_t initVolume(int indexMin, int indexMax);
-
private:
/* Copy facilities are put private to disable copy. */
Element(const Element &object);
@@ -95,16 +81,7 @@
routing_strategy mApplicableStrategy; /**< Applicable strategy for this stream. */
- /**
- * Collection of volume profiles indexed by the stream type.
- * Volume is the only reason why the stream profile was not removed from policy when introducing
- * attributes.
- */
- VolumeProfiles mVolumeProfiles;
-
- int mIndexMin;
-
- int mIndexMax;
+ audio_stream_type_t mVolumeProfile; /**< Volume Profile followed by this stream. */
};
typedef Element<audio_stream_type_t> Stream;
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index cfe49d4..cc4d4db 100755
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "APM::AudioPolicyEngine/PFWWrapper"
+//#define LOG_NDEBUG 0
#include "ParameterManagerWrapper.h"
#include "audio_policy_criteria_conf.h"
@@ -88,7 +89,6 @@
__FUNCTION__, gAudioPolicyCriteriaVendorConfFilePath,
gAudioPolicyCriteriaConfFilePath);
}
- ALOGD("%s: ParameterManagerWrapper instantiated!", __FUNCTION__);
}
ParameterManagerWrapper::~ParameterManagerWrapper()
@@ -118,7 +118,7 @@
void ParameterManagerWrapper::addCriterionType(const string &typeName, bool isInclusive)
{
ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) == mPolicyCriterionTypes.end(),
- "CriterionType " << typeName << " already added");
+ "CriterionType %s already added", typeName.c_str());
ALOGD("%s: Adding new criterionType %s", __FUNCTION__, typeName.c_str());
mPolicyCriterionTypes[typeName] = mPfwConnector->createSelectionCriterionType(isInclusive);
@@ -130,7 +130,7 @@
const string &literalValue)
{
ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) != mPolicyCriterionTypes.end(),
- "CriterionType " << typeName.c_str() << "not found");
+ "CriterionType %s not found", typeName.c_str());
ALOGV("%s: Adding new value pair (%d,%s) for criterionType %s", __FUNCTION__,
numericValue, literalValue.c_str(), typeName.c_str());
ISelectionCriterionTypeInterface *criterionType = mPolicyCriterionTypes[typeName];
@@ -224,8 +224,8 @@
{
parameterManagerElementSupported<T>();
typename std::map<string, T *>::iterator it = elementsMap.find(name);
- ALOG_ASSERT(it != elementsMap.end(), "Element " << name << " not found");
- return it->second;
+ ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str());
+ return it != elementsMap.end() ? it->second : NULL;
}
template <typename T>
@@ -233,8 +233,8 @@
{
parameterManagerElementSupported<T>();
typename std::map<string, T *>::const_iterator it = elementsMap.find(name);
- ALOG_ASSERT(it != elementsMap.end(), "Element " << name << " not found");
- return it->second;
+ ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str());
+ return it != elementsMap.end() ? it->second : NULL;
}
void ParameterManagerWrapper::loadCriteria(cnode *root)
@@ -254,8 +254,8 @@
void ParameterManagerWrapper::addCriterion(const string &name, const string &typeName,
const string &defaultLiteralValue)
{
- ALOG_ASSERT(mPolicyCriteria.find(criterionName) == mPolicyCriteria.end(),
- "Route Criterion " << criterionName << " already added");
+ ALOG_ASSERT(mPolicyCriteria.find(name) == mPolicyCriteria.end(),
+ "Route Criterion %s already added", name.c_str());
ISelectionCriterionTypeInterface *criterionType =
getElement<ISelectionCriterionTypeInterface>(typeName, mPolicyCriterionTypes);
@@ -278,7 +278,7 @@
const char *criterionName = root->name;
ALOG_ASSERT(mPolicyCriteria.find(criterionName) == mPolicyCriteria.end(),
- "Criterion " << criterionName << " already added");
+ "Criterion %s already added", criterionName);
string paramKeyName = "";
string path = "";
@@ -335,7 +335,12 @@
status_t ParameterManagerWrapper::setPhoneState(audio_mode_t mode)
{
- ISelectionCriterionInterface *criterion = mPolicyCriteria[gPhoneStateCriterionTag];
+ ISelectionCriterionInterface *criterion =
+ getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
+ if (criterion == NULL) {
+ ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str());
+ return BAD_VALUE;
+ }
if (!isValueValidForCriterion(criterion, static_cast<int>(mode))) {
return BAD_VALUE;
}
@@ -348,6 +353,10 @@
{
const ISelectionCriterionInterface *criterion =
getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
+ if (criterion == NULL) {
+ ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str());
+ return AUDIO_MODE_NORMAL;
+ }
return static_cast<audio_mode_t>(criterion->getCriterionState());
}
@@ -359,7 +368,12 @@
return BAD_VALUE;
}
- ISelectionCriterionInterface *criterion = mPolicyCriteria[gForceUseCriterionTag[usage]];
+ ISelectionCriterionInterface *criterion =
+ getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
+ if (criterion == NULL) {
+ ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str());
+ return BAD_VALUE;
+ }
if (!isValueValidForCriterion(criterion, static_cast<int>(config))) {
return BAD_VALUE;
}
@@ -376,6 +390,10 @@
}
const ISelectionCriterionInterface *criterion =
getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
+ if (criterion == NULL) {
+ ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str());
+ return AUDIO_POLICY_FORCE_NONE;
+ }
return static_cast<audio_policy_forced_cfg_t>(criterion->getCriterionState());
}
@@ -387,41 +405,28 @@
return interface->getLiteralValue(valueToCheck, literalValue);
}
-status_t ParameterManagerWrapper::setDeviceConnectionState(audio_devices_t devices,
- audio_policy_dev_state_t state,
- const char */*deviceAddres*/)
+status_t ParameterManagerWrapper::setAvailableInputDevices(audio_devices_t inputDevices)
{
- ISelectionCriterionInterface *criterion = NULL;
-
- if (audio_is_output_devices(devices)) {
- criterion = mPolicyCriteria[gOutputDeviceCriterionTag];
- } else if (devices & AUDIO_DEVICE_BIT_IN) {
- criterion = mPolicyCriteria[gInputDeviceCriterionTag];
- } else {
- return BAD_TYPE;
- }
+ ISelectionCriterionInterface *criterion =
+ getElement<ISelectionCriterionInterface>(gInputDeviceCriterionTag, mPolicyCriteria);
if (criterion == NULL) {
- ALOGE("%s: no criterion found for devices", __FUNCTION__);
+ ALOGE("%s: no criterion found for %s", __FUNCTION__, gInputDeviceCriterionTag.c_str());
return DEAD_OBJECT;
}
+ criterion->setCriterionState(inputDevices & ~AUDIO_DEVICE_BIT_IN);
+ applyPlatformConfiguration();
+ return NO_ERROR;
+}
- int32_t previousDevices = criterion->getCriterionState();
- switch (state)
- {
- case AUDIO_POLICY_DEVICE_STATE_AVAILABLE:
- criterion->setCriterionState(previousDevices |= devices);
- break;
-
- case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE:
- if (devices & AUDIO_DEVICE_BIT_IN) {
- devices &= ~AUDIO_DEVICE_BIT_IN;
- }
- criterion->setCriterionState(previousDevices &= ~devices);
- break;
-
- default:
- return BAD_VALUE;
+status_t ParameterManagerWrapper::setAvailableOutputDevices(audio_devices_t outputDevices)
+{
+ ISelectionCriterionInterface *criterion =
+ getElement<ISelectionCriterionInterface>(gOutputDeviceCriterionTag, mPolicyCriteria);
+ if (criterion == NULL) {
+ ALOGE("%s: no criterion found for %s", __FUNCTION__, gOutputDeviceCriterionTag.c_str());
+ return DEAD_OBJECT;
}
+ criterion->setCriterionState(outputDevices);
applyPlatformConfiguration();
return NO_ERROR;
}
diff --git a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
index 3c5f2c0..4c1acfe 100755
--- a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
@@ -103,18 +103,22 @@
audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const;
/**
- * Set the connection state of device(s).
- * It will set the associated policy parameter framework criterion.
+ * Set the available input devices i.e. set the associated policy parameter framework criterion
*
- * @param[in] devices mask of devices for which the state has changed.
- * @param[in] state of availability of this(these) device(s).
- * @param[in] deviceAddress: the mask might not be enough, as it may represents a type of
- * device, so address of the device will help precise identification.
+ * @param[in] inputDevices mask of available input devices.
*
* @return NO_ERROR if devices criterion updated correctly, error code otherwise.
*/
- status_t setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state,
- const char *deviceAddress);
+ status_t setAvailableInputDevices(audio_devices_t inputDevices);
+
+ /**
+ * Set the available output devices i.e. set the associated policy parameter framework criterion
+ *
+ * @param[in] outputDevices mask of available output devices.
+ *
+ * @return NO_ERROR if devices criterion updated correctly, error code otherwise.
+ */
+ status_t setAvailableOutputDevices(audio_devices_t outputDevices);
private:
/**
diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk
index 8d43b89..bb12714 100755
--- a/services/audiopolicy/enginedefault/Android.mk
+++ b/services/audiopolicy/enginedefault/Android.mk
@@ -8,8 +8,6 @@
LOCAL_SRC_FILES := \
src/Engine.cpp \
src/EngineInstance.cpp \
- src/Gains.cpp \
-
audio_policy_engine_includes_common := \
$(LOCAL_PATH)/include \
@@ -34,9 +32,11 @@
LOCAL_MODULE := libaudiopolicyenginedefault
LOCAL_MODULE_TAGS := optional
+
LOCAL_STATIC_LIBRARIES := \
libmedia_helper \
- libaudiopolicycomponents
+ libaudiopolicycomponents \
+ libxml2
LOCAL_SHARED_LIBRARIES += \
libcutils \
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 0686414..37f79fe 100755
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -25,7 +25,6 @@
#endif
#include "Engine.h"
-#include "Gains.h"
#include <AudioPolicyManagerObserver.h>
#include <AudioPort.h>
#include <IOProfile.h>
@@ -63,57 +62,6 @@
return (mApmObserver != NULL) ? NO_ERROR : NO_INIT;
}
-float Engine::volIndexToDb(Volume::device_category category, audio_stream_type_t streamType,
- int indexInUi)
-{
- const StreamDescriptor &streamDesc = mApmObserver->getStreamDescriptors().valueAt(streamType);
- return Gains::volIndexToDb(category, streamDesc, indexInUi);
-}
-
-
-status_t Engine::initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax)
-{
- ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
- if (indexMin < 0 || indexMin >= indexMax) {
- ALOGW("initStreamVolume() invalid index limits for stream %d, min %d, max %d",
- stream , indexMin, indexMax);
- return BAD_VALUE;
- }
- mApmObserver->getStreamDescriptors().setVolumeIndexMin(stream, indexMin);
- mApmObserver->getStreamDescriptors().setVolumeIndexMax(stream, indexMax);
- return NO_ERROR;
-}
-
-void Engine::initializeVolumeCurves(bool isSpeakerDrcEnabled)
-{
- StreamDescriptorCollection &streams = mApmObserver->getStreamDescriptors();
-
- for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
- for (int j = 0; j < Volume::DEVICE_CATEGORY_CNT; j++) {
- streams.setVolumeCurvePoint(static_cast<audio_stream_type_t>(i),
- static_cast<Volume::device_category>(j),
- Gains::sVolumeProfiles[i][j]);
- }
- }
-
- // Check availability of DRC on speaker path: if available, override some of the speaker curves
- if (isSpeakerDrcEnabled) {
- streams.setVolumeCurvePoint(AUDIO_STREAM_SYSTEM, Volume::DEVICE_CATEGORY_SPEAKER,
- Gains::sDefaultSystemVolumeCurveDrc);
- streams.setVolumeCurvePoint(AUDIO_STREAM_RING, Volume::DEVICE_CATEGORY_SPEAKER,
- Gains::sSpeakerSonificationVolumeCurveDrc);
- streams.setVolumeCurvePoint(AUDIO_STREAM_ALARM, Volume::DEVICE_CATEGORY_SPEAKER,
- Gains::sSpeakerSonificationVolumeCurveDrc);
- streams.setVolumeCurvePoint(AUDIO_STREAM_NOTIFICATION, Volume::DEVICE_CATEGORY_SPEAKER,
- Gains::sSpeakerSonificationVolumeCurveDrc);
- streams.setVolumeCurvePoint(AUDIO_STREAM_MUSIC, Volume::DEVICE_CATEGORY_SPEAKER,
- Gains::sSpeakerMediaVolumeCurveDrc);
- streams.setVolumeCurvePoint(AUDIO_STREAM_ACCESSIBILITY, Volume::DEVICE_CATEGORY_SPEAKER,
- Gains::sSpeakerMediaVolumeCurveDrc);
- }
-}
-
-
status_t Engine::setPhoneState(audio_mode_t state)
{
ALOGV("setPhoneState() state %d", state);
@@ -131,20 +79,14 @@
// store previous phone state for management of sonification strategy below
int oldState = mPhoneState;
mPhoneState = state;
- StreamDescriptorCollection &streams = mApmObserver->getStreamDescriptors();
- // are we entering or starting a call
+
if (!is_state_in_call(oldState) && is_state_in_call(state)) {
ALOGV(" Entering call in setPhoneState()");
- for (int j = 0; j < Volume::DEVICE_CATEGORY_CNT; j++) {
- streams.setVolumeCurvePoint(AUDIO_STREAM_DTMF, static_cast<Volume::device_category>(j),
- Gains::sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j]);
- }
+ mApmObserver->getVolumeCurves().switchVolumeCurve(AUDIO_STREAM_VOICE_CALL,
+ AUDIO_STREAM_DTMF);
} else if (is_state_in_call(oldState) && !is_state_in_call(state)) {
ALOGV(" Exiting call in setPhoneState()");
- for (int j = 0; j < Volume::DEVICE_CATEGORY_CNT; j++) {
- streams.setVolumeCurvePoint(AUDIO_STREAM_DTMF, static_cast<Volume::device_category>(j),
- Gains::sVolumeProfiles[AUDIO_STREAM_DTMF][j]);
- }
+ mApmObserver->getVolumeCurves().restoreOriginVolumeCurve(AUDIO_STREAM_DTMF);
}
return NO_ERROR;
}
@@ -663,6 +605,7 @@
break;
case AUDIO_SOURCE_VOICE_RECOGNITION:
+ case AUDIO_SOURCE_UNPROCESSED:
case AUDIO_SOURCE_HOTWORD:
if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO &&
availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 56a4748..8b6eaf6 100755
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -18,7 +18,6 @@
#include "AudioPolicyManagerInterface.h"
-#include "Gains.h"
#include <AudioGain.h>
#include <policy.h>
@@ -93,19 +92,6 @@
{
return NO_ERROR;
}
- virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax)
- {
- return mPolicyEngine->initStreamVolume(stream, indexMin, indexMax);
- }
- virtual void initializeVolumeCurves(bool isSpeakerDrcEnabled)
- {
- return mPolicyEngine->initializeVolumeCurves(isSpeakerDrcEnabled);
- }
- virtual float volIndexToDb(Volume::device_category deviceCategory,
- audio_stream_type_t stream,int indexInUi)
- {
- return mPolicyEngine->volIndexToDb(deviceCategory, stream, indexInUi);
- }
private:
Engine *mPolicyEngine;
} mManagerInterface;
@@ -140,12 +126,6 @@
routing_strategy getStrategyForUsage(audio_usage_t usage);
audio_devices_t getDeviceForStrategy(routing_strategy strategy) const;
audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const;
-
- float volIndexToDb(Volume::device_category category,
- audio_stream_type_t stream, int indexInUi);
- status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
- void initializeVolumeCurves(bool isSpeakerDrcEnabled);
-
audio_mode_t mPhoneState; /**< current phone state. */
/** current forced use configuration. */
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 5ff1c0b..758673b 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -24,6 +24,8 @@
#define ALOGVV(a...) do { } while(0)
#endif
+#define AUDIO_POLICY_XML_CONFIG_FILE "/system/etc/audio_policy_configuration.xml"
+
#include <inttypes.h>
#include <math.h>
@@ -37,8 +39,12 @@
#include <media/AudioPolicyHelper.h>
#include <soundtrigger/SoundTrigger.h>
#include "AudioPolicyManager.h"
-#include "audio_policy_conf.h"
+#ifndef USE_XML_AUDIO_POLICY_CONF
#include <ConfigParsingUtils.h>
+#include <StreamDescriptor.h>
+#endif
+#include <Serializer.h>
+#include "TypeConverter.h"
#include <policy.h>
namespace android {
@@ -190,6 +196,10 @@
}
}
+ if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
+ cleanUpForDevice(devDesc);
+ }
+
mpClientInterface->onAudioPortListUpdate();
return NO_ERROR;
} // end if is output device
@@ -266,6 +276,10 @@
updateCallRouting(newDevice);
}
+ if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
+ cleanUpForDevice(devDesc);
+ }
+
mpClientInterface->onAudioPortListUpdate();
return NO_ERROR;
} // end if is input device
@@ -410,7 +424,9 @@
if (activeInput != 0) {
sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
if (activeDesc->getModuleHandle() == txSourceDeviceDesc->getModuleHandle()) {
- audio_session_t activeSession = activeDesc->mSessions.itemAt(0);
+ //FIXME: consider all active sessions
+ AudioSessionCollection activeSessions = activeDesc->getActiveAudioSessions();
+ audio_session_t activeSession = activeSessions.keyAt(0);
stopInput(activeInput, activeSession);
releaseInput(activeInput, activeSession);
}
@@ -583,7 +599,7 @@
sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
audio_devices_t newDevice = getNewInputDevice(activeInput);
// Force new input selection if the new device can not be reached via current input
- if (activeDesc->mProfile->mSupportedDevices.types() & (newDevice & ~AUDIO_DEVICE_BIT_IN)) {
+ if (activeDesc->mProfile->getSupportedDevices().types() & (newDevice & ~AUDIO_DEVICE_BIT_IN)) {
setInputDevice(activeInput, newDevice);
} else {
closeInput(activeInput);
@@ -628,15 +644,15 @@
continue;
}
// reject profiles not corresponding to a device currently available
- if ((mAvailableOutputDevices.types() & curProfile->mSupportedDevices.types()) == 0) {
+ if ((mAvailableOutputDevices.types() & curProfile->getSupportedDevicesType()) == 0) {
continue;
}
// if several profiles are compatible, give priority to one with offload capability
- if (profile != 0 && ((curProfile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0)) {
+ if (profile != 0 && ((curProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0)) {
continue;
}
profile = curProfile;
- if ((profile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ if ((profile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
break;
}
}
@@ -690,9 +706,9 @@
stream_type_to_audio_attributes(*stream, &attributes);
}
sp<SwAudioOutputDescriptor> desc;
- if (mPolicyMixes.getOutputForAttr(attributes, desc) == NO_ERROR) {
+ if (mPolicyMixes.getOutputForAttr(attributes, uid, desc) == NO_ERROR) {
ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr");
- if (!audio_is_linear_pcm(format)) {
+ if (!audio_has_proportional_frames(format)) {
return BAD_VALUE;
}
*stream = streamTypefromAttributesInt(&attributes);
@@ -832,15 +848,15 @@
goto non_direct_output;
}
- // Do not allow offloading if one non offloadable effect is enabled. This prevents from
- // creating an offloaded track and tearing it down immediately after start when audioflinger
- // detects there is an active non offloadable effect.
+ // Do not allow offloading if one non offloadable effect is enabled or MasterMono is enabled.
+ // This prevents creating an offloaded track and tearing it down immediately after start
+ // when audioflinger detects there is an active non offloadable effect.
// FIXME: We should check the audio session here but we do not have it in this context.
// This may prevent offloading in rare situations where effects are left active by apps
// in the background.
if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
- !mEffects.isNonOffloadableEffectEnabled()) {
+ !(mEffects.isNonOffloadableEffectEnabled() || mMasterMono)) {
profile = getProfileForDirectOutput(device,
samplingRate,
format,
@@ -857,7 +873,7 @@
outputDesc = desc;
// reuse direct output if currently open and configured with same parameters
if ((samplingRate == outputDesc->mSamplingRate) &&
- (format == outputDesc->mFormat) &&
+ audio_formats_match(format, outputDesc->mFormat) &&
(channelMask == outputDesc->mChannelMask)) {
outputDesc->mDirectOpenCount++;
ALOGV("getOutput() reusing direct output %d", mOutputs.keyAt(i));
@@ -873,7 +889,7 @@
// if the selected profile is offloaded and no offload info was specified,
// create a default one
audio_offload_info_t defaultOffloadInfo = AUDIO_INFO_INITIALIZER;
- if ((profile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && !offloadInfo) {
+ if ((profile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && !offloadInfo) {
flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
defaultOffloadInfo.sample_rate = samplingRate;
defaultOffloadInfo.channel_mask = channelMask;
@@ -908,7 +924,7 @@
// only accept an output with the requested parameters
if (status != NO_ERROR ||
(samplingRate != 0 && samplingRate != config.sample_rate) ||
- (format != AUDIO_FORMAT_DEFAULT && format != config.format) ||
+ (format != AUDIO_FORMAT_DEFAULT && !audio_formats_match(format, config.format)) ||
(channelMask != 0 && channelMask != config.channel_mask)) {
ALOGV("getOutput() failed opening direct output: output %d samplingRate %d %d,"
"format %d %d, channelMask %04x %04x", output, samplingRate,
@@ -973,8 +989,9 @@
// devices (the list was previously build by getOutputsForDevice()).
// The priority is as follows:
// 1: the output with the highest number of requested policy flags
- // 2: the primary output
- // 3: the first output in the list
+ // 2: the output with the bit depth the closest to the requested one
+ // 3: the primary output
+ // 4: the first output in the list
if (outputs.size() == 0) {
return 0;
@@ -984,8 +1001,11 @@
}
int maxCommonFlags = 0;
- audio_io_handle_t outputFlags = 0;
- audio_io_handle_t outputPrimary = 0;
+ audio_io_handle_t outputForFlags = 0;
+ audio_io_handle_t outputForPrimary = 0;
+ audio_io_handle_t outputForFormat = 0;
+ audio_format_t bestFormat = AUDIO_FORMAT_INVALID;
+ audio_format_t bestFormatForFlags = AUDIO_FORMAT_INVALID;
for (size_t i = 0; i < outputs.size(); i++) {
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(outputs[i]);
@@ -993,31 +1013,48 @@
// if a valid format is specified, skip output if not compatible
if (format != AUDIO_FORMAT_INVALID) {
if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
- if (format != outputDesc->mFormat) {
+ if (!audio_formats_match(format, outputDesc->mFormat)) {
continue;
}
} else if (!audio_is_linear_pcm(format)) {
continue;
}
+ if (AudioPort::isBetterFormatMatch(
+ outputDesc->mFormat, bestFormat, format)) {
+ outputForFormat = outputs[i];
+ bestFormat = outputDesc->mFormat;
+ }
}
- int commonFlags = popcount(outputDesc->mProfile->mFlags & flags);
- if (commonFlags > maxCommonFlags) {
- outputFlags = outputs[i];
- maxCommonFlags = commonFlags;
+ int commonFlags = popcount(outputDesc->mProfile->getFlags() & flags);
+ if (commonFlags >= maxCommonFlags) {
+ if (commonFlags == maxCommonFlags) {
+ if (AudioPort::isBetterFormatMatch(
+ outputDesc->mFormat, bestFormatForFlags, format)) {
+ outputForFlags = outputs[i];
+ bestFormatForFlags = outputDesc->mFormat;
+ }
+ } else {
+ outputForFlags = outputs[i];
+ maxCommonFlags = commonFlags;
+ bestFormatForFlags = outputDesc->mFormat;
+ }
ALOGV("selectOutput() commonFlags for output %d, %04x", outputs[i], commonFlags);
}
- if (outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
- outputPrimary = outputs[i];
+ if (outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ outputForPrimary = outputs[i];
}
}
}
- if (outputFlags != 0) {
- return outputFlags;
+ if (outputForFlags != 0) {
+ return outputForFlags;
}
- if (outputPrimary != 0) {
- return outputPrimary;
+ if (outputForFormat != 0) {
+ return outputForFormat;
+ }
+ if (outputForPrimary != 0) {
+ return outputForPrimary;
}
return outputs[0];
@@ -1143,7 +1180,7 @@
// apply volume rules for current stream and device if necessary
checkAndSetVolume(stream,
- mStreams.valueFor(stream).getVolumeIndex(device),
+ mVolumeCurves->getVolumeIndex(stream, device),
outputDesc,
device);
@@ -1321,7 +1358,6 @@
audio_devices_t device;
// handle legacy remote submix case where the address was not always specified
String8 address = String8("");
- bool isSoundTrigger = false;
audio_source_t inputSource = attr->source;
audio_source_t halInputSource;
AudioMix *policyMix = NULL;
@@ -1376,30 +1412,45 @@
} else {
*inputType = API_INPUT_LEGACY;
}
- // adapt channel selection to input source
- switch (inputSource) {
- case AUDIO_SOURCE_VOICE_UPLINK:
- channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
- break;
- case AUDIO_SOURCE_VOICE_DOWNLINK:
- channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
- break;
- case AUDIO_SOURCE_VOICE_CALL:
- channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
- break;
- default:
- break;
- }
- if (inputSource == AUDIO_SOURCE_HOTWORD) {
- ssize_t index = mSoundTriggerSessions.indexOfKey(session);
- if (index >= 0) {
- *input = mSoundTriggerSessions.valueFor(session);
- isSoundTrigger = true;
- flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
- ALOGV("SoundTrigger capture on session %d input %d", session, *input);
- } else {
- halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
- }
+
+ }
+
+ *input = getInputForDevice(device, address, session, uid, inputSource,
+ samplingRate, format, channelMask, flags,
+ policyMix);
+ if (*input == AUDIO_IO_HANDLE_NONE) {
+ mInputRoutes.removeRoute(session);
+ return INVALID_OPERATION;
+ }
+ ALOGV("getInputForAttr() returns input type = %d", *inputType);
+ return NO_ERROR;
+}
+
+
+audio_io_handle_t AudioPolicyManager::getInputForDevice(audio_devices_t device,
+ String8 address,
+ audio_session_t session,
+ uid_t uid,
+ audio_source_t inputSource,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags,
+ AudioMix *policyMix)
+{
+ audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+ audio_source_t halInputSource = inputSource;
+ bool isSoundTrigger = false;
+
+ if (inputSource == AUDIO_SOURCE_HOTWORD) {
+ ssize_t index = mSoundTriggerSessions.indexOfKey(session);
+ if (index >= 0) {
+ input = mSoundTriggerSessions.valueFor(session);
+ isSoundTrigger = true;
+ flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
+ ALOGV("SoundTrigger capture on session %d input %d", session, input);
+ } else {
+ halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
}
}
@@ -1419,25 +1470,63 @@
} else if (profileFlags != AUDIO_INPUT_FLAG_NONE) {
profileFlags = AUDIO_INPUT_FLAG_NONE; // retry
} else { // fail
- ALOGW("getInputForAttr() could not find profile for device 0x%X, samplingRate %u,"
- "format %#x, channelMask 0x%X, flags %#x",
+ ALOGW("getInputForDevice() could not find profile for device 0x%X,"
+ "samplingRate %u, format %#x, channelMask 0x%X, flags %#x",
device, samplingRate, format, channelMask, flags);
- return BAD_VALUE;
+ return input;
}
}
if (profile->getModuleHandle() == 0) {
ALOGE("getInputForAttr(): HW module %s not opened", profile->getModuleName());
- return NO_INIT;
+ return input;
}
+ sp<AudioSession> audioSession = new AudioSession(session,
+ inputSource,
+ format,
+ samplingRate,
+ channelMask,
+ flags,
+ uid,
+ isSoundTrigger,
+ policyMix, mpClientInterface);
+
+// TODO enable input reuse
+#if 0
+ // reuse an open input if possible
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
+ // reuse input if it shares the same profile and same sound trigger attribute
+ if (profile == desc->mProfile &&
+ isSoundTrigger == desc->isSoundTrigger()) {
+
+ sp<AudioSession> as = desc->getAudioSession(session);
+ if (as != 0) {
+ // do not allow unmatching properties on same session
+ if (as->matches(audioSession)) {
+ as->changeOpenCount(1);
+ } else {
+ ALOGW("getInputForDevice() record with different attributes"
+ " exists for session %d", session);
+ return input;
+ }
+ } else {
+ desc->addAudioSession(session, audioSession);
+ }
+ ALOGV("getInputForDevice() reusing input %d", mInputs.keyAt(i));
+ return mInputs.keyAt(i);
+ }
+ }
+#endif
+
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
config.sample_rate = profileSamplingRate;
config.channel_mask = profileChannelMask;
config.format = profileFormat;
status_t status = mpClientInterface->openInput(profile->getModuleHandle(),
- input,
+ &input,
&config,
&device,
address,
@@ -1445,37 +1534,31 @@
profileFlags);
// only accept input with the exact requested set of parameters
- if (status != NO_ERROR || *input == AUDIO_IO_HANDLE_NONE ||
+ if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE ||
(profileSamplingRate != config.sample_rate) ||
- (profileFormat != config.format) ||
+ !audio_formats_match(profileFormat, config.format) ||
(profileChannelMask != config.channel_mask)) {
- ALOGW("getInputForAttr() failed opening input: samplingRate %d, format %d,"
- " channelMask %x",
+ ALOGW("getInputForAttr() failed opening input: samplingRate %d"
+ ", format %d, channelMask %x",
samplingRate, format, channelMask);
- if (*input != AUDIO_IO_HANDLE_NONE) {
- mpClientInterface->closeInput(*input);
+ if (input != AUDIO_IO_HANDLE_NONE) {
+ mpClientInterface->closeInput(input);
}
- return BAD_VALUE;
+ return AUDIO_IO_HANDLE_NONE;
}
sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(profile);
- inputDesc->mInputSource = inputSource;
- inputDesc->mRefCount = 0;
- inputDesc->mOpenRefCount = 1;
inputDesc->mSamplingRate = profileSamplingRate;
inputDesc->mFormat = profileFormat;
inputDesc->mChannelMask = profileChannelMask;
inputDesc->mDevice = device;
- inputDesc->mSessions.add(session);
- inputDesc->mIsSoundTrigger = isSoundTrigger;
inputDesc->mPolicyMix = policyMix;
+ inputDesc->addAudioSession(session, audioSession);
- ALOGV("getInputForAttr() returns input type = %d", *inputType);
-
- addInput(*input, inputDesc);
+ addInput(input, inputDesc);
mpClientInterface->onAudioPortListUpdate();
- return NO_ERROR;
+ return input;
}
status_t AudioPolicyManager::startInput(audio_io_handle_t input,
@@ -1489,8 +1572,8 @@
}
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
- index = inputDesc->mSessions.indexOf(session);
- if (index < 0) {
+ sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
+ if (audioSession == 0) {
ALOGW("startInput() unknown session %d on input %d", session, input);
return BAD_VALUE;
}
@@ -1505,11 +1588,14 @@
// If the already active input uses AUDIO_SOURCE_HOTWORD then it is closed,
// otherwise the active input continues and the new input cannot be started.
sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
- if ((activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) &&
+ if ((activeDesc->inputSource() == AUDIO_SOURCE_HOTWORD) &&
!activeDesc->hasPreemptedSession(session)) {
ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput);
- audio_session_t activeSession = activeDesc->mSessions.itemAt(0);
- SortedVector<audio_session_t> sessions = activeDesc->getPreemptedSessions();
+ //FIXME: consider all active sessions
+ AudioSessionCollection activeSessions = activeDesc->getActiveAudioSessions();
+ audio_session_t activeSession = activeSessions.keyAt(0);
+ SortedVector<audio_session_t> sessions =
+ activeDesc->getPreemptedSessions();
sessions.add(activeSession);
inputDesc->setPreemptedSessions(sessions);
stopInput(activeInput, activeSession);
@@ -1533,7 +1619,7 @@
// Routing?
mInputRoutes.incRouteActivity(session);
- if (inputDesc->mRefCount == 0 || mInputRoutes.hasRouteChanged(session)) {
+ if (!inputDesc->isActive() || mInputRoutes.hasRouteChanged(session)) {
// if input maps to a dynamic policy with an activity listener, notify of state change
if ((inputDesc->mPolicyMix != NULL)
&& ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
@@ -1564,9 +1650,9 @@
}
}
- ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource);
+ ALOGV("AudioPolicyManager::startInput() input source = %d", audioSession->inputSource());
- inputDesc->mRefCount++;
+ audioSession->changeActiveCount(1);
return NO_ERROR;
}
@@ -1581,23 +1667,23 @@
}
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
- index = inputDesc->mSessions.indexOf(session);
+ sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
if (index < 0) {
ALOGW("stopInput() unknown session %d on input %d", session, input);
return BAD_VALUE;
}
- if (inputDesc->mRefCount == 0) {
+ if (audioSession->activeCount() == 0) {
ALOGW("stopInput() input %d already stopped", input);
return INVALID_OPERATION;
}
- inputDesc->mRefCount--;
+ audioSession->changeActiveCount(-1);
// Routing?
mInputRoutes.decRouteActivity(session);
- if (inputDesc->mRefCount == 0) {
+ if (!inputDesc->isActive()) {
// if input maps to a dynamic policy with an activity listener, notify of state change
if ((inputDesc->mPolicyMix != NULL)
&& ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
@@ -1634,6 +1720,7 @@
void AudioPolicyManager::releaseInput(audio_io_handle_t input,
audio_session_t session)
{
+
ALOGV("releaseInput() %d", input);
ssize_t index = mInputs.indexOfKey(input);
if (index < 0) {
@@ -1647,18 +1734,23 @@
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
ALOG_ASSERT(inputDesc != 0);
- index = inputDesc->mSessions.indexOf(session);
+ sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
if (index < 0) {
ALOGW("releaseInput() unknown session %d on input %d", session, input);
return;
}
- inputDesc->mSessions.remove(session);
- if (inputDesc->mOpenRefCount == 0) {
- ALOGW("releaseInput() invalid open ref count %d", inputDesc->mOpenRefCount);
+
+ if (audioSession->openCount() == 0) {
+ ALOGW("releaseInput() invalid open count %d on session %d",
+ audioSession->openCount(), session);
return;
}
- inputDesc->mOpenRefCount--;
- if (inputDesc->mOpenRefCount > 0) {
+
+ if (audioSession->changeOpenCount(-1) == 0) {
+ inputDesc->removeAudioSession(session);
+ }
+
+ if (inputDesc->getOpenRefCount() > 0) {
ALOGV("releaseInput() exit > 0");
return;
}
@@ -1683,6 +1775,7 @@
mpClientInterface->closeInput(mInputs.keyAt(input_index));
}
mInputs.clear();
+ SoundTrigger::setCaptureState(false);
nextAudioPortGeneration();
if (patchRemoved) {
@@ -1695,10 +1788,9 @@
int indexMax)
{
ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
- mEngine->initStreamVolume(stream, indexMin, indexMax);
- //FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now
+ mVolumeCurves->initStreamVolume(stream, indexMin, indexMax);
if (stream == AUDIO_STREAM_MUSIC) {
- mEngine->initStreamVolume(AUDIO_STREAM_ACCESSIBILITY, indexMin, indexMax);
+ mVolumeCurves->initStreamVolume(AUDIO_STREAM_ACCESSIBILITY, indexMin, indexMax);
}
}
@@ -1707,8 +1799,8 @@
audio_devices_t device)
{
- if ((index < mStreams.valueFor(stream).getVolumeIndexMin()) ||
- (index > mStreams.valueFor(stream).getVolumeIndexMax())) {
+ if ((index < mVolumeCurves->getVolumeIndexMin(stream)) ||
+ (index > mVolumeCurves->getVolumeIndexMax(stream))) {
return BAD_VALUE;
}
if (!audio_is_output_device(device)) {
@@ -1716,7 +1808,7 @@
}
// Force max volume if stream cannot be muted
- if (!mStreams.canBeMuted(stream)) index = mStreams.valueFor(stream).getVolumeIndexMax();
+ if (!mVolumeCurves->canBeMuted(stream)) index = mVolumeCurves->getVolumeIndexMax(stream);
ALOGV("setStreamVolumeIndex() stream %d, device %04x, index %d",
stream, device, index);
@@ -1724,30 +1816,30 @@
// if device is AUDIO_DEVICE_OUT_DEFAULT set default value and
// clear all device specific values
if (device == AUDIO_DEVICE_OUT_DEFAULT) {
- mStreams.clearCurrentVolumeIndex(stream);
+ mVolumeCurves->clearCurrentVolumeIndex(stream);
}
- mStreams.addCurrentVolumeIndex(stream, device, index);
+ mVolumeCurves->addCurrentVolumeIndex(stream, device, index);
// update volume on all outputs whose current device is also selected by the same
// strategy as the device specified by the caller
- audio_devices_t strategyDevice = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
-
+ audio_devices_t selectedDevices = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
+ // it is possible that the requested device is not selected by the strategy (e.g an explicit
+ // audio patch is active causing getDevicesForStream() to return this device. We must make
+ // sure that the device passed is part of the devices considered when applying volume below.
+ selectedDevices |= device;
//FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now
audio_devices_t accessibilityDevice = AUDIO_DEVICE_NONE;
if (stream == AUDIO_STREAM_MUSIC) {
- mStreams.addCurrentVolumeIndex(AUDIO_STREAM_ACCESSIBILITY, device, index);
+ mVolumeCurves->addCurrentVolumeIndex(AUDIO_STREAM_ACCESSIBILITY, device, index);
accessibilityDevice = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, true /*fromCache*/);
}
- if ((device != AUDIO_DEVICE_OUT_DEFAULT) &&
- (device & (strategyDevice | accessibilityDevice)) == 0) {
- return NO_ERROR;
- }
+
status_t status = NO_ERROR;
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device());
- if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & strategyDevice) != 0)) {
+ if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & selectedDevices) != 0)) {
status_t volStatus = checkAndSetVolume(stream, index, desc, curDevice);
if (volStatus != NO_ERROR) {
status = volStatus;
@@ -1780,7 +1872,7 @@
}
device = Volume::getDeviceForVolume(device);
- *index = mStreams.valueFor(stream).getVolumeIndex(device);
+ *index = mVolumeCurves->getVolumeIndex(stream, device);
ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index);
return NO_ERROR;
}
@@ -1872,23 +1964,9 @@
{
for (size_t i = 0; i < mInputs.size(); i++) {
const sp<AudioInputDescriptor> inputDescriptor = mInputs.valueAt(i);
- if (inputDescriptor->mRefCount == 0) {
- continue;
- }
- if (inputDescriptor->mInputSource == (int)source) {
+ if (inputDescriptor->isSourceActive(source)) {
return true;
}
- // AUDIO_SOURCE_HOTWORD is equivalent to AUDIO_SOURCE_VOICE_RECOGNITION only if it
- // corresponds to an active capture triggered by a hardware hotword recognition
- if ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
- (inputDescriptor->mInputSource == AUDIO_SOURCE_HOTWORD)) {
- // FIXME: we should not assume that the first session is the active one and keep
- // activity count per session. Same in startInput().
- ssize_t index = mSoundTriggerSessions.indexOfKey(inputDescriptor->mSessions.itemAt(0));
- if (index >= 0) {
- return true;
- }
- }
}
return false;
}
@@ -1931,7 +2009,7 @@
return INVALID_OPERATION;
}
- ALOGV("registerPolicyMixes() num mixes %d", mixes.size());
+ ALOGV("registerPolicyMixes() num mixes %zu", mixes.size());
for (size_t i = 0; i < mixes.size(); i++) {
String8 address = mixes[i].mRegistrationId;
@@ -1978,7 +2056,7 @@
return INVALID_OPERATION;
}
- ALOGV("unregisterPolicyMixes() num mixes %d", mixes.size());
+ ALOGV("unregisterPolicyMixes() num mixes %zu", mixes.size());
for (size_t i = 0; i < mixes.size(); i++) {
String8 address = mixes[i].mRegistrationId;
@@ -2039,15 +2117,17 @@
result.append(buffer);
snprintf(buffer, SIZE, " TTS output %s\n", mTtsOutputAvailable ? "available" : "not available");
result.append(buffer);
+ snprintf(buffer, SIZE, " Master mono: %s\n", mMasterMono ? "on" : "off");
+ result.append(buffer);
write(fd, result.string(), result.size());
- mAvailableOutputDevices.dump(fd, String8("output"));
- mAvailableInputDevices.dump(fd, String8("input"));
+ mAvailableOutputDevices.dump(fd, String8("Available output"));
+ mAvailableInputDevices.dump(fd, String8("Available input"));
mHwModules.dump(fd);
mOutputs.dump(fd);
mInputs.dump(fd);
- mStreams.dump(fd);
+ mVolumeCurves->dump(fd);
mEffects.dump(fd);
mAudioPatches.dump(fd);
@@ -2066,6 +2146,10 @@
offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
offloadInfo.has_video);
+ if (mMasterMono) {
+ return false; // no offloading if mono is set.
+ }
+
// Check if offload has been disabled
char propValue[PROPERTY_VALUE_MAX];
if (property_get("audio.offload.disable", propValue, "0")) {
@@ -2082,6 +2166,15 @@
return false;
}
+ // Check if streaming is off, then only allow offload as of now.
+ // This is a temporary work around until the root cause is fixed in offload
+ // playback path.
+ if (offloadInfo.is_streaming)
+ {
+ ALOGV("isOffloadSupported: is_streaming == true, returning false");
+ return false;
+ }
+
//TODO: enable audio offloading with video when ready
const bool allowOffloadWithVideo =
property_get_bool("audio.offload.video", false /* default_value */);
@@ -2223,7 +2316,7 @@
patch->sources[0].type);
#if LOG_NDEBUG == 0
for (size_t i = 0; i < patch->num_sinks; i++) {
- ALOGV("createAudioPatch sink %d: id %d role %d type %d", i, patch->sinks[i].id,
+ ALOGV("createAudioPatch sink %zu: id %d role %d type %d", i, patch->sinks[i].id,
patch->sinks[i].role,
patch->sinks[i].type);
}
@@ -2392,7 +2485,7 @@
// - source and sink devices are on differnt HW modules OR
// - audio HAL version is < 3.0
if ((srcDeviceDesc->getModuleHandle() != sinkDeviceDesc->getModuleHandle()) ||
- (srcDeviceDesc->mModule->mHalVersion < AUDIO_DEVICE_API_VERSION_3_0)) {
+ (srcDeviceDesc->mModule->getHalVersion() < AUDIO_DEVICE_API_VERSION_3_0)) {
// support only one sink device for now to simplify output selection logic
if (patch->num_sinks > 1) {
return INVALID_OPERATION;
@@ -2588,6 +2681,7 @@
void AudioPolicyManager::releaseResourcesForUid(uid_t uid)
{
+ clearAudioSources(uid);
clearAudioPatches(uid);
clearSessionRoutes(uid);
}
@@ -2602,7 +2696,6 @@
}
}
-
void AudioPolicyManager::checkStrategyRoute(routing_strategy strategy,
audio_io_handle_t ouptutToSkip)
{
@@ -2668,7 +2761,7 @@
SortedVector<audio_io_handle_t> inputsToClose;
for (size_t i = 0; i < mInputs.size(); i++) {
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
- if (affectedSources.indexOf(inputDesc->mInputSource) >= 0) {
+ if (affectedSources.indexOf(inputDesc->inputSource()) >= 0) {
inputsToClose.add(inputDesc->mIoHandle);
}
}
@@ -2677,6 +2770,15 @@
}
}
+void AudioPolicyManager::clearAudioSources(uid_t uid)
+{
+ for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--) {
+ sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ if (sourceDesc->mUid == uid) {
+ stopAudioSource(mAudioSources.keyAt(i));
+ }
+ }
+}
status_t AudioPolicyManager::acquireSoundTriggerSession(audio_session_t *session,
audio_io_handle_t *ioHandle,
@@ -2689,16 +2791,219 @@
return mSoundTriggerSessions.acquireSession(*session, *ioHandle);
}
-status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source __unused,
- const audio_attributes_t *attributes __unused,
- audio_io_handle_t *handle __unused)
+status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
+ const audio_attributes_t *attributes,
+ audio_io_handle_t *handle,
+ uid_t uid)
{
- return INVALID_OPERATION;
+ ALOGV("%s source %p attributes %p handle %p", __FUNCTION__, source, attributes, handle);
+ if (source == NULL || attributes == NULL || handle == NULL) {
+ return BAD_VALUE;
+ }
+
+ *handle = AUDIO_IO_HANDLE_NONE;
+
+ if (source->role != AUDIO_PORT_ROLE_SOURCE ||
+ source->type != AUDIO_PORT_TYPE_DEVICE) {
+ ALOGV("%s INVALID_OPERATION source->role %d source->type %d", __FUNCTION__, source->role, source->type);
+ return INVALID_OPERATION;
+ }
+
+ sp<DeviceDescriptor> srcDeviceDesc =
+ mAvailableInputDevices.getDevice(source->ext.device.type,
+ String8(source->ext.device.address));
+ if (srcDeviceDesc == 0) {
+ ALOGV("%s source->ext.device.type %08x not found", __FUNCTION__, source->ext.device.type);
+ return BAD_VALUE;
+ }
+ sp<AudioSourceDescriptor> sourceDesc =
+ new AudioSourceDescriptor(srcDeviceDesc, attributes, uid);
+
+ struct audio_patch dummyPatch;
+ sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
+ sourceDesc->mPatchDesc = patchDesc;
+
+ status_t status = connectAudioSource(sourceDesc);
+ if (status == NO_ERROR) {
+ mAudioSources.add(sourceDesc->getHandle(), sourceDesc);
+ *handle = sourceDesc->getHandle();
+ }
+ return status;
+}
+
+status_t AudioPolicyManager::connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+{
+ ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+
+ // make sure we only have one patch per source.
+ disconnectAudioSource(sourceDesc);
+
+ routing_strategy strategy = (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
+ audio_stream_type_t stream = audio_attributes_to_stream_type(&sourceDesc->mAttributes);
+ sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->mDevice;
+
+ audio_devices_t sinkDevice = getDeviceForStrategy(strategy, true);
+ sp<DeviceDescriptor> sinkDeviceDesc =
+ mAvailableOutputDevices.getDevice(sinkDevice, String8(""));
+
+ audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ struct audio_patch *patch = &sourceDesc->mPatchDesc->mPatch;
+
+ if (srcDeviceDesc->getAudioPort()->mModule->getHandle() ==
+ sinkDeviceDesc->getAudioPort()->mModule->getHandle() &&
+ srcDeviceDesc->getAudioPort()->mModule->getHalVersion() >= AUDIO_DEVICE_API_VERSION_3_0 &&
+ srcDeviceDesc->getAudioPort()->mGains.size() > 0) {
+ ALOGV("%s AUDIO_DEVICE_API_VERSION_3_0", __FUNCTION__);
+ // create patch between src device and output device
+ // create Hwoutput and add to mHwOutputs
+ } else {
+ SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(sinkDevice, mOutputs);
+ audio_io_handle_t output =
+ selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
+ if (output == AUDIO_IO_HANDLE_NONE) {
+ ALOGV("%s no output for device %08x", __FUNCTION__, sinkDevice);
+ return INVALID_OPERATION;
+ }
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
+ if (outputDesc->isDuplicated()) {
+ ALOGV("%s output for device %08x is duplicated", __FUNCTION__, sinkDevice);
+ return INVALID_OPERATION;
+ }
+ // create a special patch with no sink and two sources:
+ // - the second source indicates to PatchPanel through which output mix this patch should
+ // be connected as well as the stream type for volume control
+ // - the sink is defined by whatever output device is currently selected for the output
+ // though which this patch is routed.
+ patch->num_sinks = 0;
+ patch->num_sources = 2;
+ srcDeviceDesc->toAudioPortConfig(&patch->sources[0], NULL);
+ outputDesc->toAudioPortConfig(&patch->sources[1], NULL);
+ patch->sources[1].ext.mix.usecase.stream = stream;
+ status_t status = mpClientInterface->createAudioPatch(patch,
+ &afPatchHandle,
+ 0);
+ ALOGV("%s patch panel returned %d patchHandle %d", __FUNCTION__,
+ status, afPatchHandle);
+ if (status != NO_ERROR) {
+ ALOGW("%s patch panel could not connect device patch, error %d",
+ __FUNCTION__, status);
+ return INVALID_OPERATION;
+ }
+ uint32_t delayMs = 0;
+ status = startSource(outputDesc, stream, sinkDevice, &delayMs);
+
+ if (status != NO_ERROR) {
+ mpClientInterface->releaseAudioPatch(sourceDesc->mPatchDesc->mAfPatchHandle, 0);
+ return status;
+ }
+ sourceDesc->mSwOutput = outputDesc;
+ if (delayMs != 0) {
+ usleep(delayMs * 1000);
+ }
+ }
+
+ sourceDesc->mPatchDesc->mAfPatchHandle = afPatchHandle;
+ addAudioPatch(sourceDesc->mPatchDesc->mHandle, sourceDesc->mPatchDesc);
+
+ return NO_ERROR;
}
status_t AudioPolicyManager::stopAudioSource(audio_io_handle_t handle __unused)
{
- return INVALID_OPERATION;
+ sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueFor(handle);
+ ALOGV("%s handle %d", __FUNCTION__, handle);
+ if (sourceDesc == 0) {
+ ALOGW("%s unknown source for handle %d", __FUNCTION__, handle);
+ return BAD_VALUE;
+ }
+ status_t status = disconnectAudioSource(sourceDesc);
+
+ mAudioSources.removeItem(handle);
+ return status;
+}
+
+status_t AudioPolicyManager::setMasterMono(bool mono)
+{
+ if (mMasterMono == mono) {
+ return NO_ERROR;
+ }
+ mMasterMono = mono;
+ // if enabling mono we close all offloaded devices, which will invalidate the
+ // corresponding AudioTrack. The AudioTrack client/MediaPlayer is responsible
+ // for recreating the new AudioTrack as non-offloaded PCM.
+ //
+ // If disabling mono, we leave all tracks as is: we don't know which clients
+ // and tracks are able to be recreated as offloaded. The next "song" should
+ // play back offloaded.
+ if (mMasterMono) {
+ Vector<audio_io_handle_t> offloaded;
+ for (size_t i = 0; i < mOutputs.size(); ++i) {
+ sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ if (desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ offloaded.push(desc->mIoHandle);
+ }
+ }
+ for (size_t i = 0; i < offloaded.size(); ++i) {
+ closeOutput(offloaded[i]);
+ }
+ }
+ // update master mono for all remaining outputs
+ for (size_t i = 0; i < mOutputs.size(); ++i) {
+ updateMono(mOutputs.keyAt(i));
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getMasterMono(bool *mono)
+{
+ *mono = mMasterMono;
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+{
+ ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+
+ sp<AudioPatch> patchDesc = mAudioPatches.valueFor(sourceDesc->mPatchDesc->mHandle);
+ if (patchDesc == 0) {
+ ALOGW("%s source has no patch with handle %d", __FUNCTION__,
+ sourceDesc->mPatchDesc->mHandle);
+ return BAD_VALUE;
+ }
+ removeAudioPatch(sourceDesc->mPatchDesc->mHandle);
+
+ audio_stream_type_t stream = audio_attributes_to_stream_type(&sourceDesc->mAttributes);
+ sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->mSwOutput.promote();
+ if (swOutputDesc != 0) {
+ stopSource(swOutputDesc, stream, false);
+ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+ } else {
+ sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->mHwOutput.promote();
+ if (hwOutputDesc != 0) {
+ // release patch between src device and output device
+ // close Hwoutput and remove from mHwOutputs
+ } else {
+ ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
+ }
+ }
+ return NO_ERROR;
+}
+
+sp<AudioSourceDescriptor> AudioPolicyManager::getSourceForStrategyOnOutput(
+ audio_io_handle_t output, routing_strategy strategy)
+{
+ sp<AudioSourceDescriptor> source;
+ for (size_t i = 0; i < mAudioSources.size(); i++) {
+ sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ routing_strategy sourceStrategy =
+ (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
+ sp<SwAudioOutputDescriptor> outputDesc = sourceDesc->mSwOutput.promote();
+ if (sourceStrategy == strategy && outputDesc != 0 && outputDesc->mIoHandle == output) {
+ source = sourceDesc;
+ break;
+ }
+ }
+ return source;
}
// ----------------------------------------------------------------------------
@@ -2716,13 +3021,42 @@
#endif //AUDIO_POLICY_TEST
mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
mA2dpSuspended(false),
- mSpeakerDrcEnabled(false),
mAudioPortGeneration(1),
mBeaconMuteRefCount(0),
mBeaconPlayingRefCount(0),
mBeaconMuted(false),
- mTtsOutputAvailable(false)
+ mTtsOutputAvailable(false),
+ mMasterMono(false)
{
+ mUidCached = getuid();
+ mpClientInterface = clientInterface;
+
+ // TODO: remove when legacy conf file is removed. true on devices that use DRC on the
+ // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
+ // Note: remove also speaker_drc_enabled from global configuration of XML config file.
+ bool speakerDrcEnabled = false;
+
+#ifdef USE_XML_AUDIO_POLICY_CONF
+ mVolumeCurves = new VolumeCurvesCollection();
+ AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
+ mDefaultOutputDevice, speakerDrcEnabled,
+ static_cast<VolumeCurvesCollection *>(mVolumeCurves));
+ PolicySerializer serializer;
+ if (serializer.deserialize(AUDIO_POLICY_XML_CONFIG_FILE, config) != NO_ERROR) {
+#else
+ mVolumeCurves = new StreamDescriptorCollection();
+ AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
+ mDefaultOutputDevice, speakerDrcEnabled);
+ if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) &&
+ (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR)) {
+#endif
+ ALOGE("could not load audio policy configuration file, setting defaults");
+ config.setDefault();
+ }
+ // must be done after reading the policy (since conditionned by Speaker Drc Enabling)
+ mVolumeCurves->initializeVolumeCurves(speakerDrcEnabled);
+
+ // Once policy config has been parsed, retrieve an instance of the engine and initialize it.
audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
if (!engineInstance) {
ALOGE("%s: Could not get an instance of policy engine", __FUNCTION__);
@@ -2738,32 +3072,14 @@
status_t status = mEngine->initCheck();
ALOG_ASSERT(status == NO_ERROR, "Policy engine not initialized(err=%d)", status);
- mUidCached = getuid();
- mpClientInterface = clientInterface;
-
- mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
- if (ConfigParsingUtils::loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE,
- mHwModules, mAvailableInputDevices, mAvailableOutputDevices,
- mDefaultOutputDevice, mSpeakerDrcEnabled) != NO_ERROR) {
- if (ConfigParsingUtils::loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE,
- mHwModules, mAvailableInputDevices, mAvailableOutputDevices,
- mDefaultOutputDevice, mSpeakerDrcEnabled) != NO_ERROR) {
- ALOGE("could not load audio policy configuration file, setting defaults");
- defaultAudioPolicyConfig();
- }
- }
// mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
-
- // must be done after reading the policy (since conditionned by Speaker Drc Enabling)
- mEngine->initializeVolumeCurves(mSpeakerDrcEnabled);
-
// open all output streams needed to access attached devices
audio_devices_t outputDeviceTypes = mAvailableOutputDevices.types();
audio_devices_t inputDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
for (size_t i = 0; i < mHwModules.size(); i++) {
- mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
+ mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->getName());
if (mHwModules[i]->mHandle == 0) {
- ALOGW("could not open HW module %s", mHwModules[i]->mName);
+ ALOGW("could not open HW module %s", mHwModules[i]->getName());
continue;
}
// open all output streams needed to access attached devices
@@ -2774,29 +3090,24 @@
{
const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j];
- if (outProfile->mSupportedDevices.isEmpty()) {
- ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName);
+ if (!outProfile->hasSupportedDevices()) {
+ ALOGW("Output profile contains no device on module %s", mHwModules[i]->getName());
continue;
}
- if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_TTS) != 0) {
+ if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
mTtsOutputAvailable = true;
}
- if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+ if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
continue;
}
- audio_devices_t profileType = outProfile->mSupportedDevices.types();
+ audio_devices_t profileType = outProfile->getSupportedDevicesType();
if ((profileType & mDefaultOutputDevice->type()) != AUDIO_DEVICE_NONE) {
profileType = mDefaultOutputDevice->type();
} else {
- // chose first device present in mSupportedDevices also part of
+ // chose first device present in profile's SupportedDevices also part of
// outputDeviceTypes
- for (size_t k = 0; k < outProfile->mSupportedDevices.size(); k++) {
- profileType = outProfile->mSupportedDevices[k]->type();
- if ((profileType & outputDeviceTypes) != 0) {
- break;
- }
- }
+ profileType = outProfile->getSupportedDeviceForType(outputDeviceTypes);
}
if ((profileType & outputDeviceTypes) == 0) {
continue;
@@ -2821,23 +3132,22 @@
if (status != NO_ERROR) {
ALOGW("Cannot open output stream for device %08x on hw module %s",
outputDesc->mDevice,
- mHwModules[i]->mName);
+ mHwModules[i]->getName());
} else {
outputDesc->mSamplingRate = config.sample_rate;
outputDesc->mChannelMask = config.channel_mask;
outputDesc->mFormat = config.format;
- for (size_t k = 0; k < outProfile->mSupportedDevices.size(); k++) {
- audio_devices_t type = outProfile->mSupportedDevices[k]->type();
- ssize_t index =
- mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]);
+ const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
+ for (size_t k = 0; k < supportedDevices.size(); k++) {
+ ssize_t index = mAvailableOutputDevices.indexOf(supportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
if (index >= 0 && !mAvailableOutputDevices[index]->isAttached()) {
mAvailableOutputDevices[index]->attach(mHwModules[i]);
}
}
if (mPrimaryOutput == 0 &&
- outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
mPrimaryOutput = outputDesc;
}
addOutput(output, outputDesc);
@@ -2852,25 +3162,20 @@
{
const sp<IOProfile> inProfile = mHwModules[i]->mInputProfiles[j];
- if (inProfile->mSupportedDevices.isEmpty()) {
- ALOGW("Input profile contains no device on module %s", mHwModules[i]->mName);
+ if (!inProfile->hasSupportedDevices()) {
+ ALOGW("Input profile contains no device on module %s", mHwModules[i]->getName());
continue;
}
- // chose first device present in mSupportedDevices also part of
+ // chose first device present in profile's SupportedDevices also part of
// inputDeviceTypes
- audio_devices_t profileType = AUDIO_DEVICE_NONE;
- for (size_t k = 0; k < inProfile->mSupportedDevices.size(); k++) {
- profileType = inProfile->mSupportedDevices[k]->type();
- if (profileType & inputDeviceTypes) {
- break;
- }
- }
+ audio_devices_t profileType = inProfile->getSupportedDeviceForType(inputDeviceTypes);
+
if ((profileType & inputDeviceTypes) == 0) {
continue;
}
- sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(inProfile);
+ sp<AudioInputDescriptor> inputDesc =
+ new AudioInputDescriptor(inProfile);
- inputDesc->mInputSource = AUDIO_SOURCE_MIC;
inputDesc->mDevice = profileType;
// find the address
@@ -2895,10 +3200,9 @@
AUDIO_INPUT_FLAG_NONE);
if (status == NO_ERROR) {
- for (size_t k = 0; k < inProfile->mSupportedDevices.size(); k++) {
- audio_devices_t type = inProfile->mSupportedDevices[k]->type();
- ssize_t index =
- mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
+ const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
+ for (size_t k = 0; k < supportedDevices.size(); k++) {
+ ssize_t index = mAvailableInputDevices.indexOf(supportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
if (index >= 0) {
sp<DeviceDescriptor> devDesc = mAvailableInputDevices[index];
@@ -2912,14 +3216,14 @@
} else {
ALOGW("Cannot open input stream for device %08x on hw module %s",
inputDesc->mDevice,
- mHwModules[i]->mName);
+ mHwModules[i]->getName());
}
}
}
// make sure all attached devices have been allocated a unique ID
for (size_t i = 0; i < mAvailableOutputDevices.size();) {
if (!mAvailableOutputDevices[i]->isAttached()) {
- ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->type());
+ ALOGW("Output device %08x unreachable", mAvailableOutputDevices[i]->type());
mAvailableOutputDevices.remove(mAvailableOutputDevices[i]);
continue;
}
@@ -2940,7 +3244,7 @@
i++;
}
// make sure default device is reachable
- if (mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) {
+ if (mDefaultOutputDevice == 0 || mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) {
ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->type());
}
@@ -3160,6 +3464,7 @@
{
outputDesc->setIoHandle(output);
mOutputs.add(output, outputDesc);
+ updateMono(output); // update mono status when adding to output list
nextAudioPortGeneration();
}
@@ -3180,7 +3485,7 @@
const String8 address /*in*/,
SortedVector<audio_io_handle_t>& outputs /*out*/) {
sp<DeviceDescriptor> devDesc =
- desc->mProfile->mSupportedDevices.getDevice(device, address);
+ desc->mProfile->getSupportedDeviceByAddress(device, address);
if (devDesc != 0) {
ALOGV("findIoHandlesByAddress(): adding opened output %d on same address %s",
desc->mIoHandle, address.string());
@@ -3198,7 +3503,7 @@
if (audio_device_is_digital(device)) {
// erase all current sample rates, formats and channel masks
- devDesc->clearCapabilities();
+ devDesc->clearAudioProfiles();
}
if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
@@ -3225,9 +3530,9 @@
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
{
sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
- if (profile->mSupportedDevices.types() & device) {
+ if (profile->supportDevice(device)) {
if (!device_distinguishes_on_address(device) ||
- address == profile->mSupportedDevices[0]->mAddress) {
+ profile->supportDeviceAddress(address)) {
profiles.add(profile);
ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i);
}
@@ -3235,7 +3540,7 @@
}
}
- ALOGV(" found %d profiles, %d outputs", profiles.size(), outputs.size());
+ ALOGV(" found %zu profiles, %zu outputs", profiles.size(), outputs.size());
if (profiles.isEmpty() && outputs.isEmpty()) {
ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
@@ -3294,55 +3599,14 @@
mpClientInterface->setParameters(output, String8(param));
free(param);
}
-
- // Here is where we step through and resolve any "dynamic" fields
- String8 reply;
- char *value;
- if (profile->mSamplingRates[0] == 0) {
- reply = mpClientInterface->getParameters(output,
- String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
- ALOGV("checkOutputsForDevice() supported sampling rates %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->loadSamplingRates(value + 1);
- }
- }
- if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
- reply = mpClientInterface->getParameters(output,
- String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
- ALOGV("checkOutputsForDevice() supported formats %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->loadFormats(value + 1);
- }
- }
- if (profile->mChannelMasks[0] == 0) {
- reply = mpClientInterface->getParameters(output,
- String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
- ALOGV("checkOutputsForDevice() supported channel masks %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->loadOutChannels(value + 1);
- }
- }
- if (((profile->mSamplingRates[0] == 0) &&
- (profile->mSamplingRates.size() < 2)) ||
- ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) &&
- (profile->mFormats.size() < 2)) ||
- ((profile->mChannelMasks[0] == 0) &&
- (profile->mChannelMasks.size() < 2))) {
+ updateAudioProfiles(output, profile->getAudioProfiles());
+ if (!profile->hasValidAudioProfile()) {
ALOGW("checkOutputsForDevice() missing param");
mpClientInterface->closeOutput(output);
output = AUDIO_IO_HANDLE_NONE;
- } else if (profile->mSamplingRates[0] == 0 || profile->mFormats[0] == 0 ||
- profile->mChannelMasks[0] == 0) {
+ } else if (profile->hasDynamicAudioProfile()) {
mpClientInterface->closeOutput(output);
- config.sample_rate = profile->pickSamplingRate();
- config.channel_mask = profile->pickChannelMask();
- config.format = profile->pickFormat();
+ profile->pickAudioProfile(config.sample_rate, config.channel_mask, config.format);
config.offload_info.sample_rate = config.sample_rate;
config.offload_info.channel_mask = config.channel_mask;
config.offload_info.format = config.format;
@@ -3463,21 +3727,10 @@
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
{
sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
- if (profile->mSupportedDevices.types() & device) {
+ if (profile->supportDevice(device)) {
ALOGV("checkOutputsForDevice(): "
"clearing direct output profile %zu on module %zu", j, i);
- if (profile->mSamplingRates[0] == 0) {
- profile->mSamplingRates.clear();
- profile->mSamplingRates.add(0);
- }
- if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
- profile->mFormats.clear();
- profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
- }
- if (profile->mChannelMasks[0] == 0) {
- profile->mChannelMasks.clear();
- profile->mChannelMasks.add(0);
- }
+ profile->clearAudioProfiles();
}
}
}
@@ -3495,14 +3748,14 @@
if (audio_device_is_digital(device)) {
// erase all current sample rates, formats and channel masks
- devDesc->clearCapabilities();
+ devDesc->clearAudioProfiles();
}
if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
// first list already open inputs that can be routed to this device
for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
desc = mInputs.valueAt(input_index);
- if (desc->mProfile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) {
+ if (desc->mProfile->supportDevice(device)) {
ALOGV("checkInputsForDevice(): adding opened input %d", mInputs.keyAt(input_index));
inputs.add(mInputs.keyAt(input_index));
}
@@ -3521,9 +3774,9 @@
{
sp<IOProfile> profile = mHwModules[module_idx]->mInputProfiles[profile_index];
- if (profile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) {
+ if (profile->supportDevice(device)) {
if (!device_distinguishes_on_address(device) ||
- address == profile->mSupportedDevices[0]->mAddress) {
+ profile->supportDeviceAddress(address)) {
profiles.add(profile);
ALOGV("checkInputsForDevice(): adding profile %zu from module %zu",
profile_index, module_idx);
@@ -3583,42 +3836,8 @@
mpClientInterface->setParameters(input, String8(param));
free(param);
}
-
- // Here is where we step through and resolve any "dynamic" fields
- String8 reply;
- char *value;
- if (profile->mSamplingRates[0] == 0) {
- reply = mpClientInterface->getParameters(input,
- String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
- ALOGV("checkInputsForDevice() direct input sup sampling rates %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->loadSamplingRates(value + 1);
- }
- }
- if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
- reply = mpClientInterface->getParameters(input,
- String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
- ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->loadFormats(value + 1);
- }
- }
- if (profile->mChannelMasks[0] == 0) {
- reply = mpClientInterface->getParameters(input,
- String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
- ALOGV("checkInputsForDevice() direct input sup channel masks %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->loadInChannels(value + 1);
- }
- }
- if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) ||
- ((profile->mFormats[0] == 0) && (profile->mFormats.size() < 2)) ||
- ((profile->mChannelMasks[0] == 0) && (profile->mChannelMasks.size() < 2))) {
+ updateAudioProfiles(input, profile->getAudioProfiles());
+ if (!profile->hasValidAudioProfile()) {
ALOGW("checkInputsForDevice() direct input missing param");
mpClientInterface->closeInput(input);
input = AUDIO_IO_HANDLE_NONE;
@@ -3651,8 +3870,7 @@
// check if one opened input is not needed any more after disconnecting one device
for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
desc = mInputs.valueAt(input_index);
- if (!(desc->mProfile->mSupportedDevices.types() & mAvailableInputDevices.types() &
- ~AUDIO_DEVICE_BIT_IN)) {
+ if (!(desc->mProfile->supportDevice(mAvailableInputDevices.types()))) {
ALOGV("checkInputsForDevice(): disconnecting adding input %d",
mInputs.keyAt(input_index));
inputs.add(mInputs.keyAt(input_index));
@@ -3667,21 +3885,10 @@
profile_index < mHwModules[module_index]->mInputProfiles.size();
profile_index++) {
sp<IOProfile> profile = mHwModules[module_index]->mInputProfiles[profile_index];
- if (profile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) {
+ if (profile->supportDevice(device)) {
ALOGV("checkInputsForDevice(): clearing direct input profile %zu on module %zu",
profile_index, module_index);
- if (profile->mSamplingRates[0] == 0) {
- profile->mSamplingRates.clear();
- profile->mSamplingRates.add(0);
- }
- if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
- profile->mFormats.clear();
- profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
- }
- if (profile->mChannelMasks[0] == 0) {
- profile->mChannelMasks.clear();
- profile->mChannelMasks.add(0);
- }
+ profile->clearAudioProfiles();
}
}
}
@@ -3841,6 +4048,11 @@
setStrategyMute(strategy, true, desc);
setStrategyMute(strategy, false, desc, MUTE_TIME_MS, newDevice);
}
+ sp<AudioSourceDescriptor> source =
+ getSourceForStrategyOnOutput(srcOutputs[i], strategy);
+ if (source != 0){
+ connectAudioSource(source);
+ }
}
// Move effects associated to this strategy from previous output to new output
@@ -4012,7 +4224,7 @@
}
}
- audio_devices_t device = getDeviceAndMixForInputSource(inputDesc->mInputSource);
+ audio_devices_t device = getDeviceAndMixForInputSource(inputDesc->inputSource());
return device;
}
@@ -4046,7 +4258,6 @@
devices |= AUDIO_DEVICE_OUT_SPEAKER;
devices &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
}
-
return devices;
}
@@ -4352,7 +4563,6 @@
patchDesc->mPatch = patch;
}
patchDesc->mAfPatchHandle = afPatchHandle;
- patchDesc->mUid = mUidCached;
if (patchHandle) {
*patchHandle = patchDesc->mHandle;
}
@@ -4424,7 +4634,7 @@
// AUDIO_SOURCE_HOTWORD is for internal use only:
// handled as AUDIO_SOURCE_VOICE_RECOGNITION by the audio HAL
if (patch.sinks[0].ext.mix.usecase.source == AUDIO_SOURCE_HOTWORD &&
- !inputDesc->mIsSoundTrigger) {
+ !inputDesc->isSoundTrigger()) {
patch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_VOICE_RECOGNITION;
}
patch.num_sinks = 1;
@@ -4457,7 +4667,6 @@
patchDesc->mPatch = patch;
}
patchDesc->mAfPatchHandle = afPatchHandle;
- patchDesc->mUid = mUidCached;
if (patchHandle) {
*patchHandle = patchDesc->mHandle;
}
@@ -4557,11 +4766,10 @@
}
float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
- int index,
- audio_devices_t device)
+ int index,
+ audio_devices_t device)
{
- float volumeDb = mEngine->volIndexToDb(Volume::getDeviceCategory(device), stream, index);
-
+ float volumeDb = mVolumeCurves->volIndexToDb(stream, Volume::getDeviceCategory(device), index);
// if a headset is connected, apply the following rules to ring tones and notifications
// to avoid sound level bursts in user's ears:
// - always attenuate ring tones and notifications volume by 6dB
@@ -4577,7 +4785,7 @@
|| (stream == AUDIO_STREAM_SYSTEM)
|| ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) &&
(mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) &&
- mStreams.canBeMuted(stream)) {
+ mVolumeCurves->canBeMuted(stream)) {
volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
// when the phone is ringing we must consider that music could have been paused just before
// by the music application and behave as if music was active if the last music track was
@@ -4586,8 +4794,9 @@
mLimitRingtoneVolume) {
audio_devices_t musicDevice = getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/);
float musicVolDB = computeVolume(AUDIO_STREAM_MUSIC,
- mStreams.valueFor(AUDIO_STREAM_MUSIC).getVolumeIndex(musicDevice),
- musicDevice);
+ mVolumeCurves->getVolumeIndex(AUDIO_STREAM_MUSIC,
+ musicDevice),
+ musicDevice);
float minVolDB = (musicVolDB > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
musicVolDB : SONIFICATION_HEADSET_VOLUME_MIN_DB;
if (volumeDb > minVolDB) {
@@ -4639,7 +4848,7 @@
float voiceVolume;
// Force voice volume to max for bluetooth SCO as volume is managed by the headset
if (stream == AUDIO_STREAM_VOICE_CALL) {
- voiceVolume = (float)index/(float)mStreams.valueFor(stream).getVolumeIndexMax();
+ voiceVolume = (float)index/(float)mVolumeCurves->getVolumeIndexMax(stream);
} else {
voiceVolume = 1.0;
}
@@ -4665,7 +4874,7 @@
continue;
}
checkAndSetVolume((audio_stream_type_t)stream,
- mStreams.valueFor((audio_stream_type_t)stream).getVolumeIndex(device),
+ mVolumeCurves->getVolumeIndex((audio_stream_type_t)stream, device),
outputDesc,
device,
delayMs,
@@ -4697,7 +4906,6 @@
int delayMs,
audio_devices_t device)
{
- const StreamDescriptor& streamDesc = mStreams.valueFor(stream);
if (device == AUDIO_DEVICE_NONE) {
device = outputDesc->device();
}
@@ -4707,7 +4915,7 @@
if (on) {
if (outputDesc->mMuteCount[stream] == 0) {
- if (streamDesc.canBeMuted() &&
+ if (mVolumeCurves->canBeMuted(stream) &&
((stream != AUDIO_STREAM_ENFORCED_AUDIBLE) ||
(mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) {
checkAndSetVolume(stream, 0, outputDesc, device, delayMs);
@@ -4722,7 +4930,7 @@
}
if (--outputDesc->mMuteCount[stream] == 0) {
checkAndSetVolume(stream,
- streamDesc.getVolumeIndex(device),
+ mVolumeCurves->getVolumeIndex(stream, device),
outputDesc,
device,
delayMs);
@@ -4779,39 +4987,6 @@
}
}
-
-
-void AudioPolicyManager::defaultAudioPolicyConfig(void)
-{
- sp<HwModule> module;
- sp<IOProfile> profile;
- sp<DeviceDescriptor> defaultInputDevice =
- new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
- mAvailableOutputDevices.add(mDefaultOutputDevice);
- mAvailableInputDevices.add(defaultInputDevice);
-
- module = new HwModule("primary");
-
- profile = new IOProfile(String8("primary"), AUDIO_PORT_ROLE_SOURCE);
- profile->attach(module);
- profile->mSamplingRates.add(44100);
- profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
- profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO);
- profile->mSupportedDevices.add(mDefaultOutputDevice);
- profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY;
- module->mOutputProfiles.add(profile);
-
- profile = new IOProfile(String8("primary"), AUDIO_PORT_ROLE_SINK);
- profile->attach(module);
- profile->mSamplingRates.add(8000);
- profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
- profile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO);
- profile->mSupportedDevices.add(defaultInputDevice);
- module->mInputProfiles.add(profile);
-
- mHwModules.add(module);
-}
-
audio_stream_type_t AudioPolicyManager::streamTypefromAttributesInt(const audio_attributes_t *attr)
{
// flags to stream type mapping
@@ -4935,4 +5110,91 @@
return is_state_in_call(state);
}
+void AudioPolicyManager::cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc)
+{
+ for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--) {
+ sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ if (sourceDesc->mDevice->equals(deviceDesc)) {
+ ALOGV("%s releasing audio source %d", __FUNCTION__, sourceDesc->getHandle());
+ stopAudioSource(sourceDesc->getHandle());
+ }
+ }
+
+ for (ssize_t i = (ssize_t)mAudioPatches.size() - 1; i >= 0; i--) {
+ sp<AudioPatch> patchDesc = mAudioPatches.valueAt(i);
+ bool release = false;
+ for (size_t j = 0; j < patchDesc->mPatch.num_sources && !release; j++) {
+ const struct audio_port_config *source = &patchDesc->mPatch.sources[j];
+ if (source->type == AUDIO_PORT_TYPE_DEVICE &&
+ source->ext.device.type == deviceDesc->type()) {
+ release = true;
+ }
+ }
+ for (size_t j = 0; j < patchDesc->mPatch.num_sinks && !release; j++) {
+ const struct audio_port_config *sink = &patchDesc->mPatch.sinks[j];
+ if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
+ sink->ext.device.type == deviceDesc->type()) {
+ release = true;
+ }
+ }
+ if (release) {
+ ALOGV("%s releasing patch %u", __FUNCTION__, patchDesc->mHandle);
+ releaseAudioPatch(patchDesc->mHandle, patchDesc->mUid);
+ }
+ }
+}
+
+void AudioPolicyManager::updateAudioProfiles(audio_io_handle_t ioHandle,
+ AudioProfileVector &profiles)
+{
+ String8 reply;
+ char *value;
+ // Format MUST be checked first to update the list of AudioProfile
+ if (profiles.hasDynamicFormat()) {
+ reply = mpClientInterface->getParameters(ioHandle,
+ String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+ ALOGV("%s: supported formats %s", __FUNCTION__, reply.string());
+ AudioParameter repliedParameters(reply);
+ if (repliedParameters.get(
+ String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS), reply) != NO_ERROR) {
+ ALOGE("%s: failed to retrieve format, bailing out", __FUNCTION__);
+ return;
+ }
+ profiles.setFormats(formatsFromString(reply.string()));
+ }
+ const FormatVector &supportedFormats = profiles.getSupportedFormats();
+
+ for (size_t formatIndex = 0; formatIndex < supportedFormats.size(); formatIndex++) {
+ audio_format_t format = supportedFormats[formatIndex];
+ ChannelsVector channelMasks;
+ SampleRateVector samplingRates;
+ AudioParameter requestedParameters;
+ requestedParameters.addInt(String8(AUDIO_PARAMETER_STREAM_FORMAT), format);
+
+ if (profiles.hasDynamicRateFor(format)) {
+ reply = mpClientInterface->getParameters(ioHandle,
+ requestedParameters.toString() + ";" +
+ AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES);
+ ALOGV("%s: supported sampling rates %s", __FUNCTION__, reply.string());
+ AudioParameter repliedParameters(reply);
+ if (repliedParameters.get(
+ String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES), reply) == NO_ERROR) {
+ samplingRates = samplingRatesFromString(reply.string());
+ }
+ }
+ if (profiles.hasDynamicChannelsFor(format)) {
+ reply = mpClientInterface->getParameters(ioHandle,
+ requestedParameters.toString() + ";" +
+ AUDIO_PARAMETER_STREAM_SUP_CHANNELS);
+ ALOGV("%s: supported channel masks %s", __FUNCTION__, reply.string());
+ AudioParameter repliedParameters(reply);
+ if (repliedParameters.get(
+ String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS), reply) == NO_ERROR) {
+ channelMasks = channelMasksFromString(reply.string());
+ }
+ }
+ profiles.addProfileFromHal(new AudioProfile(format, channelMasks, samplingRates));
+ }
+}
+
}; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index bbdf396..fb9b46b 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -24,6 +24,7 @@
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/SortedVector.h>
+#include <media/AudioParameter.h>
#include <media/AudioPolicy.h>
#include "AudioPolicyInterface.h"
@@ -32,7 +33,6 @@
#include <AudioGain.h>
#include <AudioPort.h>
#include <AudioPatch.h>
-#include <ConfigParsingUtils.h>
#include <DeviceDescriptor.h>
#include <IOProfile.h>
#include <HwModule.h>
@@ -41,8 +41,8 @@
#include <AudioPolicyMix.h>
#include <EffectDescriptor.h>
#include <SoundTriggerSession.h>
-#include <StreamDescriptor.h>
#include <SessionRoute.h>
+#include <VolumeCurve.h>
namespace android {
@@ -211,6 +211,8 @@
unsigned int *generation);
virtual status_t setAudioPortConfig(const struct audio_port_config *config);
+ virtual void releaseResourcesForUid(uid_t uid);
+
virtual status_t acquireSoundTriggerSession(audio_session_t *session,
audio_io_handle_t *ioHandle,
audio_devices_t *device);
@@ -225,14 +227,12 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle);
+ audio_io_handle_t *handle,
+ uid_t uid);
virtual status_t stopAudioSource(audio_io_handle_t handle);
- virtual void releaseResourcesForUid(uid_t uid);
-
- // Audio policy configuration file parsing (audio_policy.conf)
- // TODO candidates to be moved to ConfigParsingUtils
- void defaultAudioPolicyConfig(void);
+ virtual status_t setMasterMono(bool mono);
+ virtual status_t getMasterMono(bool *mono);
// return the strategy corresponding to a given stream type
routing_strategy getStrategy(audio_stream_type_t stream) const;
@@ -267,10 +267,7 @@
{
return mAvailableInputDevices;
}
- virtual StreamDescriptorCollection &getStreamDescriptors()
- {
- return mStreams;
- }
+ virtual IVolumeCurvesCollection &getVolumeCurves() { return *mVolumeCurves; }
virtual const sp<DeviceDescriptor> &getDefaultOutputDevice() const
{
return mDefaultOutputDevice;
@@ -498,6 +495,17 @@
status_t hasPrimaryOutput() const { return mPrimaryOutput != 0; }
+ status_t connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
+ status_t disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
+
+ sp<AudioSourceDescriptor> getSourceForStrategyOnOutput(audio_io_handle_t output,
+ routing_strategy strategy);
+
+ void cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc);
+
+ void clearAudioSources(uid_t uid);
+
+
uid_t mUidCached;
AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
sp<SwAudioOutputDescriptor> mPrimaryOutput; // primary output descriptor
@@ -515,7 +523,8 @@
SessionRouteMap mOutputRoutes = SessionRouteMap(SessionRouteMap::MAPTYPE_OUTPUT);
SessionRouteMap mInputRoutes = SessionRouteMap(SessionRouteMap::MAPTYPE_INPUT);
- StreamDescriptorCollection mStreams; // stream descriptors for volume control
+ IVolumeCurvesCollection *mVolumeCurves; // Volume Curves per use case and device category
+
bool mLimitRingtoneVolume; // limit ringtone volume to music volume if headset connected
audio_devices_t mDeviceForStrategy[NUM_STRATEGIES];
float mLastVoiceVolume; // last voice volume value sent to audio HAL
@@ -523,9 +532,6 @@
EffectDescriptorCollection mEffects; // list of registered audio effects
bool mA2dpSuspended; // true if A2DP output is suspended
sp<DeviceDescriptor> mDefaultOutputDevice; // output device selected by default at boot time
- bool mSpeakerDrcEnabled;// true on devices that use DRC on the DEVICE_CATEGORY_SPEAKER path
- // to boost soft sounds, used to adjust volume curves accordingly
-
HwModuleCollection mHwModules;
volatile int32_t mAudioPortGeneration;
@@ -537,6 +543,9 @@
sp<AudioPatch> mCallTxPatch;
sp<AudioPatch> mCallRxPatch;
+ HwAudioOutputCollection mHwOutputs;
+ AudioSourceCollection mAudioSources;
+
// for supporting "beacon" streams, i.e. streams that only play on speaker, and never
// when something other than STREAM_TTS (a.k.a. "Transmitted Through Speaker") is playing
enum {
@@ -550,6 +559,7 @@
bool mBeaconMuted; // has STREAM_TTS been muted
bool mTtsOutputAvailable; // true if a dedicated output for TTS stream is available
+ bool mMasterMono; // true if we wish to force all outputs to mono
AudioPolicyMixCollection mPolicyMixes; // list of registered mixes
#ifdef AUDIO_POLICY_TEST
@@ -572,6 +582,9 @@
// Audio Policy Engine Interface.
AudioPolicyManagerInterface *mEngine;
private:
+ // If any, resolve any "dynamic" fields of an Audio Profiles collection
+ void updateAudioProfiles(audio_io_handle_t ioHandle, AudioProfileVector &profiles);
+
// updates device caching and output for streams that can influence the
// routing of notifications
void handleNotificationRoutingForStream(audio_stream_type_t stream);
@@ -595,6 +608,18 @@
audio_channel_mask_t channelMask,
audio_output_flags_t flags,
const audio_offload_info_t *offloadInfo);
+ // internal method to return the input handle for the given device and format
+ audio_io_handle_t getInputForDevice(audio_devices_t device,
+ String8 address,
+ audio_session_t session,
+ uid_t uid,
+ audio_source_t inputSource,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags,
+ AudioMix *policyMix);
+
// internal function to derive a stream type value from audio attributes
audio_stream_type_t streamTypefromAttributesInt(const audio_attributes_t *attr);
// event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON
@@ -614,6 +639,11 @@
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name);
+ void updateMono(audio_io_handle_t output) {
+ AudioParameter param;
+ param.addInt(String8(AUDIO_PARAMETER_MONO_OUTPUT), (int)mMasterMono);
+ mpClientInterface->setParameters(output, param.toString());
+ }
};
};
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 489a9be..3d51f48 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -219,6 +219,12 @@
mAudioPolicyService->onDynamicPolicyMixStateUpdate(regId, state);
}
+void AudioPolicyService::AudioPolicyClient::onRecordingConfigurationUpdate(
+ int event, audio_session_t session, audio_source_t source)
+{
+ mAudioPolicyService->onRecordingConfigurationUpdate(event, session, source);
+}
+
audio_unique_id_t AudioPolicyService::AudioPolicyClient::newAudioUniqueId()
{
return AudioSystem::newAudioUniqueId();
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 282ddeb..ce77814 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -323,7 +323,8 @@
VOICE_CALL_SRC_TAG,
CAMCORDER_SRC_TAG,
VOICE_REC_SRC_TAG,
- VOICE_COMM_SRC_TAG
+ VOICE_COMM_SRC_TAG,
+ UNPROCESSED_SRC_TAG
};
// returns the audio_source_t enum corresponding to the input source name or
@@ -372,7 +373,7 @@
// Audio Effect Config parser
// ----------------------------------------------------------------------------
-size_t AudioPolicyEffects::growParamSize(char *param,
+size_t AudioPolicyEffects::growParamSize(char **param,
size_t size,
size_t *curSize,
size_t *totSize)
@@ -384,55 +385,82 @@
while (pos + size > *totSize) {
*totSize += ((*totSize + 7) / 8) * 4;
}
- param = (char *)realloc(param, *totSize);
+ *param = (char *)realloc(*param, *totSize);
+ if (*param == NULL) {
+ ALOGE("%s realloc error for size %zu", __func__, *totSize);
+ return 0;
+ }
}
*curSize = pos + size;
return pos;
}
+
size_t AudioPolicyEffects::readParamValue(cnode *node,
- char *param,
+ char **param,
size_t *curSize,
size_t *totSize)
{
+ size_t len = 0;
+ size_t pos;
+
if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) {
- size_t pos = growParamSize(param, sizeof(short), curSize, totSize);
- *(short *)((char *)param + pos) = (short)atoi(node->value);
- ALOGV("readParamValue() reading short %d", *(short *)((char *)param + pos));
- return sizeof(short);
- } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) {
- size_t pos = growParamSize(param, sizeof(int), curSize, totSize);
- *(int *)((char *)param + pos) = atoi(node->value);
- ALOGV("readParamValue() reading int %d", *(int *)((char *)param + pos));
- return sizeof(int);
- } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) {
- size_t pos = growParamSize(param, sizeof(float), curSize, totSize);
- *(float *)((char *)param + pos) = (float)atof(node->value);
- ALOGV("readParamValue() reading float %f",*(float *)((char *)param + pos));
- return sizeof(float);
- } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) {
- size_t pos = growParamSize(param, sizeof(bool), curSize, totSize);
- if (strncmp(node->value, "false", strlen("false") + 1) == 0) {
- *(bool *)((char *)param + pos) = false;
- } else {
- *(bool *)((char *)param + pos) = true;
+ pos = growParamSize(param, sizeof(short), curSize, totSize);
+ if (pos == 0) {
+ goto exit;
}
- ALOGV("readParamValue() reading bool %s",*(bool *)((char *)param + pos) ? "true" : "false");
- return sizeof(bool);
+ *(short *)(*param + pos) = (short)atoi(node->value);
+ ALOGV("readParamValue() reading short %d", *(short *)(*param + pos));
+ len = sizeof(short);
+ } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) {
+ pos = growParamSize(param, sizeof(int), curSize, totSize);
+ if (pos == 0) {
+ goto exit;
+ }
+ *(int *)(*param + pos) = atoi(node->value);
+ ALOGV("readParamValue() reading int %d", *(int *)(*param + pos));
+ len = sizeof(int);
+ } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) {
+ pos = growParamSize(param, sizeof(float), curSize, totSize);
+ if (pos == 0) {
+ goto exit;
+ }
+ *(float *)(*param + pos) = (float)atof(node->value);
+ ALOGV("readParamValue() reading float %f",*(float *)(*param + pos));
+ len = sizeof(float);
+ } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) {
+ pos = growParamSize(param, sizeof(bool), curSize, totSize);
+ if (pos == 0) {
+ goto exit;
+ }
+ if (strncmp(node->value, "true", strlen("true") + 1) == 0) {
+ *(bool *)(*param + pos) = true;
+ } else {
+ *(bool *)(*param + pos) = false;
+ }
+ ALOGV("readParamValue() reading bool %s",
+ *(bool *)(*param + pos) ? "true" : "false");
+ len = sizeof(bool);
} else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) {
- size_t len = strnlen(node->value, EFFECT_STRING_LEN_MAX);
+ len = strnlen(node->value, EFFECT_STRING_LEN_MAX);
if (*curSize + len + 1 > *totSize) {
*totSize = *curSize + len + 1;
- param = (char *)realloc(param, *totSize);
+ *param = (char *)realloc(*param, *totSize);
+ if (*param == NULL) {
+ len = 0;
+ ALOGE("%s realloc error for string len %zu", __func__, *totSize);
+ goto exit;
+ }
}
- strncpy(param + *curSize, node->value, len);
+ strncpy(*param + *curSize, node->value, len);
*curSize += len;
- param[*curSize] = '\0';
- ALOGV("readParamValue() reading string %s", param + *curSize - len);
- return len;
+ (*param)[*curSize] = '\0';
+ ALOGV("readParamValue() reading string %s", *param + *curSize - len);
+ } else {
+ ALOGW("readParamValue() unknown param type %s", node->name);
}
- ALOGW("readParamValue() unknown param type %s", node->name);
- return 0;
+exit:
+ return len;
}
effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root)
@@ -443,6 +471,12 @@
size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int);
effect_param_t *fx_param = (effect_param_t *)malloc(totSize);
+ if (fx_param == NULL) {
+ ALOGE("%s malloc error for effect structure of size %zu",
+ __func__, totSize);
+ return NULL;
+ }
+
param = config_find(root, PARAM_TAG);
value = config_find(root, VALUE_TAG);
if (param == NULL && value == NULL) {
@@ -451,8 +485,10 @@
if (param != NULL) {
// Note: that a pair of random strings is read as 0 0
int *ptr = (int *)fx_param->data;
+#if LOG_NDEBUG == 0
int *ptr2 = (int *)((char *)param + sizeof(effect_param_t));
- ALOGW("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2);
+ ALOGV("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2);
+#endif
*ptr++ = atoi(param->name);
*ptr = atoi(param->value);
fx_param->psize = sizeof(int);
@@ -461,7 +497,8 @@
}
}
if (param == NULL || value == NULL) {
- ALOGW("loadEffectParameter() invalid parameter description %s", root->name);
+ ALOGW("loadEffectParameter() invalid parameter description %s",
+ root->name);
goto error;
}
@@ -469,7 +506,8 @@
param = param->first_child;
while (param) {
ALOGV("loadEffectParameter() reading param of type %s", param->name);
- size_t size = readParamValue(param, (char *)fx_param, &curSize, &totSize);
+ size_t size =
+ readParamValue(param, (char **)&fx_param, &curSize, &totSize);
if (size == 0) {
goto error;
}
@@ -484,7 +522,8 @@
value = value->first_child;
while (value) {
ALOGV("loadEffectParameter() reading value of type %s", value->name);
- size_t size = readParamValue(value, (char *)fx_param, &curSize, &totSize);
+ size_t size =
+ readParamValue(value, (char **)&fx_param, &curSize, &totSize);
if (size == 0) {
goto error;
}
@@ -495,7 +534,7 @@
return fx_param;
error:
- delete fx_param;
+ free(fx_param);
return NULL;
}
@@ -505,11 +544,9 @@
while (node) {
ALOGV("loadEffectParameters() loading param %s", node->name);
effect_param_t *param = loadEffectParameter(node);
- if (param == NULL) {
- node = node->next;
- continue;
+ if (param != NULL) {
+ params.add(param);
}
- params.add(param);
node = node->next;
}
}
@@ -527,6 +564,7 @@
EffectDescVector *desc = new EffectDescVector();
while (node) {
size_t i;
+
for (i = 0; i < effects.size(); i++) {
if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) {
ALOGV("loadEffectConfig() found effect %s in list", node->name);
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index 3dec437..266a45e 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -170,10 +170,10 @@
void loadEffectParameters(cnode *root, Vector <effect_param_t *>& params);
effect_param_t *loadEffectParameter(cnode *root);
size_t readParamValue(cnode *node,
- char *param,
+ char **param,
size_t *curSize,
size_t *totSize);
- size_t growParamSize(char *param,
+ size_t growParamSize(char **param,
size_t size,
size_t *curSize,
size_t *totSize);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index ca365a5..fdd6dd2 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -164,13 +164,11 @@
ALOGV("getOutput()");
Mutex::Autolock _l(mLock);
- // if the caller is us, trust the specified uid
- if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) {
- uid_t newclientUid = IPCThreadState::self()->getCallingUid();
- if (uid != (uid_t)-1 && uid != newclientUid) {
- ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid);
- }
- uid = newclientUid;
+ const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ if (!isTrustedCallingUid(callingUid) || uid == (uid_t)-1) {
+ ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
+ "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
+ uid = callingUid;
}
return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, samplingRate,
format, channelMask, flags, selectedDeviceId, offloadInfo);
@@ -284,13 +282,11 @@
sp<AudioPolicyEffects>audioPolicyEffects;
status_t status;
AudioPolicyInterface::input_type_t inputType;
- // if the caller is us, trust the specified uid
- if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) {
- uid_t newclientUid = IPCThreadState::self()->getCallingUid();
- if (uid != (uid_t)-1 && uid != newclientUid) {
- ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid);
- }
- uid = newclientUid;
+ const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ if (!isTrustedCallingUid(callingUid) || uid == (uid_t)-1) {
+ ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
+ "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
+ uid = callingUid;
}
{
@@ -463,6 +459,7 @@
if (mAudioPolicyManager == NULL) {
return AUDIO_DEVICE_NONE;
}
+ Mutex::Autolock _l(mLock);
return mAudioPolicyManager->getDevicesForStream(stream);
}
@@ -485,6 +482,7 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
+ Mutex::Autolock _l(mEffectsLock);
return mAudioPolicyManager->registerEffect(desc, io, strategy, session, id);
}
@@ -493,6 +491,7 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
+ Mutex::Autolock _l(mEffectsLock);
return mAudioPolicyManager->unregisterEffect(id);
}
@@ -501,6 +500,7 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
+ Mutex::Autolock _l(mEffectsLock);
return mAudioPolicyManager->setEffectEnabled(id, enabled);
}
@@ -563,7 +563,9 @@
ALOGV("mAudioPolicyManager == NULL");
return false;
}
-
+ Mutex::Autolock _l(mLock);
+ Mutex::Autolock _le(mEffectsLock); // isOffloadSupported queries for
+ // non-offloadable effects
return mAudioPolicyManager->isOffloadSupported(info);
}
@@ -689,7 +691,8 @@
return NO_INIT;
}
- return mAudioPolicyManager->startAudioSource(source, attributes, handle);
+ return mAudioPolicyManager->startAudioSource(source, attributes, handle,
+ IPCThreadState::self()->getCallingUid());
}
status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle)
@@ -702,4 +705,25 @@
return mAudioPolicyManager->stopAudioSource(handle);
}
+status_t AudioPolicyService::setMasterMono(bool mono)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ Mutex::Autolock _l(mLock);
+ return mAudioPolicyManager->setMasterMono(mono);
+}
+
+status_t AudioPolicyService::getMasterMono(bool *mono)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ return mAudioPolicyManager->getMasterMono(mono);
+}
+
}; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index 13af3ef..08b2a3b 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
@@ -619,4 +619,14 @@
return INVALID_OPERATION;
}
+status_t AudioPolicyService::setMasterMono(bool mono)
+{
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::getMasterMono(bool *mono)
+{
+ return INVALID_OPERATION;
+}
+
}; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index c77cc45..363968cc 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -149,7 +149,10 @@
// connects to AudioPolicyService.
void AudioPolicyService::registerClient(const sp<IAudioPolicyServiceClient>& client)
{
-
+ if (client == 0) {
+ ALOGW("%s got NULL client", __FUNCTION__);
+ return;
+ }
Mutex::Autolock _l(mNotificationClientsLock);
uid_t uid = IPCThreadState::self()->getCallingUid();
@@ -212,19 +215,6 @@
mOutputCommandThread->updateAudioPatchListCommand();
}
-status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch,
- audio_patch_handle_t *handle,
- int delayMs)
-{
- return mAudioCommandThread->createAudioPatchCommand(patch, handle, delayMs);
-}
-
-status_t AudioPolicyService::clientReleaseAudioPatch(audio_patch_handle_t handle,
- int delayMs)
-{
- return mAudioCommandThread->releaseAudioPatchCommand(handle, delayMs);
-}
-
void AudioPolicyService::doOnAudioPatchListUpdate()
{
Mutex::Autolock _l(mNotificationClientsLock);
@@ -248,6 +238,34 @@
}
}
+void AudioPolicyService::onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source)
+{
+ mOutputCommandThread->recordingConfigurationUpdateCommand(event, session, source);
+}
+
+void AudioPolicyService::doOnRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source)
+{
+ Mutex::Autolock _l(mNotificationClientsLock);
+ for (size_t i = 0; i < mNotificationClients.size(); i++) {
+ mNotificationClients.valueAt(i)->onRecordingConfigurationUpdate(event, session, source);
+ }
+}
+
+status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs)
+{
+ return mAudioCommandThread->createAudioPatchCommand(patch, handle, delayMs);
+}
+
+status_t AudioPolicyService::clientReleaseAudioPatch(audio_patch_handle_t handle,
+ int delayMs)
+{
+ return mAudioCommandThread->releaseAudioPatchCommand(handle, delayMs);
+}
+
status_t AudioPolicyService::clientSetAudioPortConfig(const struct audio_port_config *config,
int delayMs)
{
@@ -293,7 +311,15 @@
String8 regId, int32_t state)
{
if (mAudioPolicyServiceClient != 0) {
- mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
+ mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
+ }
+}
+
+void AudioPolicyService::NotificationClient::onRecordingConfigurationUpdate(
+ int event, audio_session_t session, audio_source_t source)
+{
+ if (mAudioPolicyServiceClient != 0) {
+ mAudioPolicyServiceClient->onRecordingConfigurationUpdate(event, session, source);
}
}
@@ -423,7 +449,7 @@
bool AudioPolicyService::AudioCommandThread::threadLoop()
{
- nsecs_t waitTime = INT64_MAX;
+ nsecs_t waitTime = -1;
mLock.lock();
while (!exitPending())
@@ -555,7 +581,6 @@
case DYN_POLICY_MIX_STATE_UPDATE: {
DynPolicyMixStateUpdateData *data =
(DynPolicyMixStateUpdateData *)command->mParam.get();
- //###ALOGV("AudioCommandThread() processing dyn policy mix state update");
ALOGV("AudioCommandThread() processing dyn policy mix state update %s %d",
data->mRegId.string(), data->mState);
svc = mService.promote();
@@ -566,6 +591,19 @@
svc->doOnDynamicPolicyMixStateUpdate(data->mRegId, data->mState);
mLock.lock();
} break;
+ case RECORDING_CONFIGURATION_UPDATE: {
+ RecordingConfigurationUpdateData *data =
+ (RecordingConfigurationUpdateData *)command->mParam.get();
+ ALOGV("AudioCommandThread() processing recording configuration update");
+ svc = mService.promote();
+ if (svc == 0) {
+ break;
+ }
+ mLock.unlock();
+ svc->doOnRecordingConfigurationUpdate(data->mEvent, data->mSession,
+ data->mSource);
+ mLock.lock();
+ } break;
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
}
@@ -576,7 +614,7 @@
command->mCond.signal();
}
}
- waitTime = INT64_MAX;
+ waitTime = -1;
// release mLock before releasing strong reference on the service as
// AudioPolicyService destructor calls AudioCommandThread::exit() which
// acquires mLock.
@@ -598,7 +636,11 @@
// has a finite delay. So unless we are exiting it is safe to wait.
if (!exitPending()) {
ALOGV("AudioCommandThread() going to sleep");
- mWaitWorkCV.waitRelative(mLock, waitTime);
+ if (waitTime == -1) {
+ mWaitWorkCV.wait(mLock);
+ } else {
+ mWaitWorkCV.waitRelative(mLock, waitTime);
+ }
}
}
// release delayed commands wake lock before quitting
@@ -822,6 +864,21 @@
sendCommand(command);
}
+void AudioPolicyService::AudioCommandThread::recordingConfigurationUpdateCommand(
+ int event, audio_session_t session, audio_source_t source)
+{
+ sp<AudioCommand>command = new AudioCommand();
+ command->mCommand = RECORDING_CONFIGURATION_UPDATE;
+ RecordingConfigurationUpdateData *data = new RecordingConfigurationUpdateData();
+ data->mEvent = event;
+ data->mSession = session;
+ data->mSource = source;
+ command->mParam = data;
+ ALOGV("AudioCommandThread() adding recording configuration update event %d, source %d",
+ event, source);
+ sendCommand(command);
+}
+
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
{
{
@@ -968,6 +1025,10 @@
} break;
+ case RECORDING_CONFIGURATION_UPDATE: {
+
+ } break;
+
case START_TONE:
case STOP_TONE:
default:
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index a0d5aa2..a91c560 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -202,6 +202,9 @@
audio_io_handle_t *handle);
virtual status_t stopAudioSource(audio_io_handle_t handle);
+ virtual status_t setMasterMono(bool mono);
+ virtual status_t getMasterMono(bool *mono);
+
status_t doStopOutput(audio_io_handle_t output,
audio_stream_type_t stream,
audio_session_t session);
@@ -225,6 +228,10 @@
void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
void doOnDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+ void onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source);
+ void doOnRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source);
private:
AudioPolicyService() ANDROID_API;
@@ -256,7 +263,8 @@
UPDATE_AUDIOPORT_LIST,
UPDATE_AUDIOPATCH_LIST,
SET_AUDIOPORT_CONFIG,
- DYN_POLICY_MIX_STATE_UPDATE
+ DYN_POLICY_MIX_STATE_UPDATE,
+ RECORDING_CONFIGURATION_UPDATE
};
AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -295,6 +303,9 @@
status_t setAudioPortConfigCommand(const struct audio_port_config *config,
int delayMs);
void dynamicPolicyMixStateUpdateCommand(String8 regId, int32_t state);
+ void recordingConfigurationUpdateCommand(
+ int event, audio_session_t session,
+ audio_source_t source);
void insertCommand_l(AudioCommand *command, int delayMs = 0);
private:
@@ -385,6 +396,13 @@
int32_t mState;
};
+ class RecordingConfigurationUpdateData : public AudioCommandData {
+ public:
+ int mEvent;
+ audio_session_t mSession;
+ audio_source_t mSource;
+ };
+
Mutex mLock;
Condition mWaitWorkCV;
Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
@@ -491,6 +509,8 @@
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);
virtual audio_unique_id_t newAudioUniqueId();
@@ -509,6 +529,9 @@
void onAudioPortListUpdate();
void onAudioPatchListUpdate();
void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+ void onRecordingConfigurationUpdate(
+ int event, audio_session_t session,
+ audio_source_t source);
void setAudioPortCallbacksEnabled(bool enabled);
// IBinder::DeathRecipient
@@ -530,6 +553,10 @@
mutable Mutex mLock; // prevents concurrent access to AudioPolicy manager functions changing
// device connection state or routing
+ mutable Mutex mEffectsLock; // serialize access to Effect state within APM.
+ // Note: lock acquisition order is always mLock > mEffectsLock:
+ // mLock protects AudioPolicyManager methods that can call into audio flinger
+ // and possibly back in to audio policy service and acquire mEffectsLock.
sp<AudioCommandThread> mAudioCommandThread; // audio commands thread
sp<AudioCommandThread> mTonePlaybackThread; // tone playback thread
sp<AudioCommandThread> mOutputCommandThread; // process stop and release output
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 45900c4..d416353 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -22,7 +22,6 @@
LOCAL_SRC_FILES:= \
CameraService.cpp \
- CameraDeviceFactory.cpp \
CameraFlashlight.cpp \
common/Camera2ClientBase.cpp \
common/CameraDeviceBase.cpp \
@@ -35,14 +34,10 @@
api1/client2/StreamingProcessor.cpp \
api1/client2/JpegProcessor.cpp \
api1/client2/CallbackProcessor.cpp \
- api1/client2/ZslProcessor.cpp \
- api1/client2/ZslProcessorInterface.cpp \
- api1/client2/BurstCapture.cpp \
api1/client2/JpegCompressor.cpp \
api1/client2/CaptureSequencer.cpp \
- api1/client2/ZslProcessor3.cpp \
+ api1/client2/ZslProcessor.cpp \
api2/CameraDeviceClient.cpp \
- device2/Camera2Device.cpp \
device3/Camera3Device.cpp \
device3/Camera3Stream.cpp \
device3/Camera3IOStreamBase.cpp \
@@ -51,6 +46,7 @@
device3/Camera3ZslStream.cpp \
device3/Camera3DummyStream.cpp \
device3/StatusTracker.cpp \
+ device3/Camera3BufferManager.cpp \
gui/RingBufferConsumer.cpp \
utils/CameraTraces.cpp \
utils/AutoConditionLock.cpp
diff --git a/services/camera/libcameraservice/CameraDeviceFactory.cpp b/services/camera/libcameraservice/CameraDeviceFactory.cpp
deleted file mode 100644
index 6589e27..0000000
--- a/services/camera/libcameraservice/CameraDeviceFactory.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// #define LOG_NDEBUG 0
-#define LOG_TAG "CameraDeviceFactory"
-#include <utils/Log.h>
-
-#include "CameraService.h"
-#include "CameraDeviceFactory.h"
-#include "common/CameraDeviceBase.h"
-#include "device2/Camera2Device.h"
-#include "device3/Camera3Device.h"
-
-namespace android {
-
-wp<CameraService> CameraDeviceFactory::sService;
-
-sp<CameraDeviceBase> CameraDeviceFactory::createDevice(int cameraId) {
-
- sp<CameraService> svc = sService.promote();
- if (svc == 0) {
- ALOGE("%s: No service registered", __FUNCTION__);
- return NULL;
- }
-
- int deviceVersion = svc->getDeviceVersion(cameraId, /*facing*/NULL);
-
- sp<CameraDeviceBase> device;
-
- switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_2_0:
- case CAMERA_DEVICE_API_VERSION_2_1:
- device = new Camera2Device(cameraId);
- break;
- case CAMERA_DEVICE_API_VERSION_3_0:
- case CAMERA_DEVICE_API_VERSION_3_1:
- case CAMERA_DEVICE_API_VERSION_3_2:
- case CAMERA_DEVICE_API_VERSION_3_3:
- device = new Camera3Device(cameraId);
- break;
- default:
- ALOGE("%s: Camera %d: Unknown HAL device version %d",
- __FUNCTION__, cameraId, deviceVersion);
- device = NULL;
- break;
- }
-
- ALOGV_IF(device != 0, "Created a new camera device for version %d",
- deviceVersion);
-
- return device;
-}
-
-void CameraDeviceFactory::registerService(wp<CameraService> service) {
- ALOGV("%s: Registered service %p", __FUNCTION__,
- service.promote().get());
-
- sService = service;
-}
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/CameraDeviceFactory.h b/services/camera/libcameraservice/CameraDeviceFactory.h
deleted file mode 100644
index 236dc56..0000000
--- a/services/camera/libcameraservice/CameraDeviceFactory.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SERVERS_CAMERA_CAMERADEVICEFACTORY_H
-#define ANDROID_SERVERS_CAMERA_CAMERADEVICEFACTORY_H
-
-#include <utils/RefBase.h>
-
-namespace android {
-
-class CameraDeviceBase;
-class CameraService;
-
-/**
- * Create the right instance of Camera2Device or Camera3Device
- * automatically based on the device version.
- */
-class CameraDeviceFactory : public virtual RefBase {
- public:
- static void registerService(wp<CameraService> service);
-
- // Prerequisite: Call registerService.
- static sp<CameraDeviceBase> createDevice(int cameraId);
- private:
- CameraDeviceFactory(wp<CameraService> service);
-
- static wp<CameraService> sService;
-};
-
-}; // namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index 406c1c4..0afd945 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -27,7 +27,7 @@
#include "gui/IGraphicBufferConsumer.h"
#include "gui/BufferQueue.h"
#include "camera/camera2/CaptureRequest.h"
-#include "CameraDeviceFactory.h"
+#include "device3/Camera3Device.h"
namespace android {
@@ -78,7 +78,7 @@
deviceVersion = info.device_version;
}
- if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
+ if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_0) {
CameraDeviceClientFlashControl *flashControl =
new CameraDeviceClientFlashControl(*mCameraModule,
*mCallbacks);
@@ -193,8 +193,6 @@
}
bool CameraFlashlight::hasFlashUnit(const String8& cameraId) {
- status_t res;
-
Mutex::Autolock l(mLock);
return hasFlashUnitLocked(cameraId);
}
@@ -302,7 +300,8 @@
/////////////////////////////////////////////////////////////////////
ModuleFlashControl::ModuleFlashControl(CameraModule& cameraModule,
const camera_module_callbacks_t& callbacks) :
- mCameraModule(&cameraModule) {
+ mCameraModule(&cameraModule) {
+ (void) callbacks;
}
ModuleFlashControl::~ModuleFlashControl() {
@@ -478,7 +477,7 @@
}
sp<CameraDeviceBase> device =
- CameraDeviceFactory::createDevice(atoi(cameraId.string()));
+ new Camera3Device(atoi(cameraId.string()));
if (device == NULL) {
return NO_MEMORY;
}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index a560b93..f0bcc0b 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -46,6 +46,7 @@
#include <utils/Log.h>
#include <utils/String16.h>
#include <utils/Trace.h>
+#include <private/android_filesystem_config.h>
#include <system/camera_vendor_tags.h>
#include <system/camera_metadata.h>
#include <system/camera.h>
@@ -55,7 +56,10 @@
#include "api1/Camera2Client.h"
#include "api2/CameraDeviceClient.h"
#include "utils/CameraTraces.h"
-#include "CameraDeviceFactory.h"
+
+namespace {
+ const char* kPermissionServiceName = "permission";
+}; // namespace anonymous
namespace android {
@@ -124,8 +128,10 @@
// should be ok for now.
static CameraService *gCameraService;
-CameraService::CameraService() : mEventLog(DEFAULT_EVENT_LOG_LENGTH), mAllowedUsers(),
- mSoundRef(0), mModule(0), mFlashlight(0) {
+CameraService::CameraService() :
+ mEventLog(DEFAULT_EVENT_LOG_LENGTH),
+ mSoundRef(0), mModule(nullptr),
+ mNumberOfCameras(0), mNumberOfNormalCameras(0) {
ALOGI("CameraService started (pid=%d)", getpid());
gCameraService = this;
@@ -152,8 +158,6 @@
if (err < 0) {
ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err));
logServiceError("Could not load camera HAL module", err);
- mNumberOfCameras = 0;
- mNumberOfNormalCameras = 0;
return;
}
@@ -164,7 +168,6 @@
strerror(-err));
logServiceError("Could not initialize camera HAL module", err);
- mNumberOfCameras = 0;
delete mModule;
mModule = nullptr;
return;
@@ -247,8 +250,6 @@
mModule->setCallbacks(this);
}
- CameraDeviceFactory::registerService(this);
-
CameraService::pingCameraServiceProxy();
}
@@ -316,10 +317,8 @@
clientToDisconnect = removeClientLocked(id);
// Notify the client of disconnection
- if (clientToDisconnect != nullptr) {
- clientToDisconnect->notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
- CaptureResultExtras{});
- }
+ clientToDisconnect->notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
+ CaptureResultExtras{});
}
ALOGI("%s: Client for camera ID %s evicted due to device status change from HAL",
@@ -367,7 +366,8 @@
res = setTorchStatusLocked(cameraId, newStatus);
if (res) {
- ALOGE("%s: Failed to set the torch status", __FUNCTION__, (uint32_t)newStatus);
+ ALOGE("%s: Failed to set the torch status to %d: %s (%d)", __FUNCTION__,
+ (uint32_t)newStatus, strerror(-res), res);
return;
}
@@ -484,7 +484,6 @@
Vector<Size> sizes;
Vector<Size> jpegSizes;
Vector<int32_t> formats;
- const char* supportedPreviewFormats;
{
shimParams.getSupportedPreviewSizes(/*out*/sizes);
shimParams.getSupportedPreviewFormats(/*out*/formats);
@@ -562,7 +561,7 @@
int facing;
status_t ret = OK;
if (mModule->getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_0 ||
- getDeviceVersion(cameraId, &facing) <= CAMERA_DEVICE_API_VERSION_2_1 ) {
+ getDeviceVersion(cameraId, &facing) < CAMERA_DEVICE_API_VERSION_3_0) {
/**
* Backwards compatibility mode for old HALs:
* - Convert CameraInfo into static CameraMetadata properties.
@@ -728,8 +727,6 @@
return -EOPNOTSUPP;
}
break;
- case CAMERA_DEVICE_API_VERSION_2_0:
- case CAMERA_DEVICE_API_VERSION_2_1:
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
case CAMERA_DEVICE_API_VERSION_3_2:
@@ -787,13 +784,13 @@
status_t CameraService::initializeShimMetadata(int cameraId) {
int uid = getCallingUid();
- String16 internalPackageName("media");
+ String16 internalPackageName("cameraserver");
String8 id = String8::format("%d", cameraId);
status_t ret = NO_ERROR;
sp<Client> tmp = nullptr;
if ((ret = connectHelper<ICameraClient,Client>(sp<ICameraClient>{nullptr}, id,
- static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED), internalPackageName, uid, API_1,
- false, true, tmp)) != NO_ERROR) {
+ static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED), internalPackageName, uid,
+ USE_CALLING_PID, API_1, false, true, tmp)) != NO_ERROR) {
ALOGE("%s: Error %d (%s) initializing shim metadata.", __FUNCTION__, ret, strerror(ret));
return ret;
}
@@ -860,22 +857,52 @@
return INVALID_OPERATION;
}
-status_t CameraService::validateConnectLocked(const String8& cameraId, /*inout*/int& clientUid)
- const {
+// Can camera service trust the caller based on the calling UID?
+static bool isTrustedCallingUid(uid_t uid) {
+ switch (uid) {
+ case AID_MEDIA: // mediaserver
+ case AID_CAMERASERVER: // cameraserver
+ return true;
+ default:
+ return false;
+ }
+}
+
+status_t CameraService::validateConnectLocked(const String8& cameraId, /*inout*/int& clientUid,
+ /*inout*/int& clientPid) const {
int callingPid = getCallingPid();
+ int callingUid = getCallingUid();
+ // Check if we can trust clientUid
if (clientUid == USE_CALLING_UID) {
- clientUid = getCallingUid();
- } else {
- // We only trust our own process to forward client UIDs
- if (callingPid != getpid()) {
- ALOGE("CameraService::connect X (PID %d) rejected (don't trust clientUid %d)",
- callingPid, clientUid);
- return PERMISSION_DENIED;
- }
+ clientUid = callingUid;
+ } else if (!isTrustedCallingUid(callingUid)) {
+ ALOGE("CameraService::connect X (calling PID %d, calling UID %d) rejected "
+ "(don't trust clientUid %d)", callingPid, callingUid, clientUid);
+ return PERMISSION_DENIED;
}
+ // Check if we can trust clientPid
+ if (clientPid == USE_CALLING_PID) {
+ clientPid = callingPid;
+ } else if (!isTrustedCallingUid(callingUid)) {
+ ALOGE("CameraService::connect X (calling PID %d, calling UID %d) rejected "
+ "(don't trust clientPid %d)", callingPid, callingUid, clientPid);
+ return PERMISSION_DENIED;
+ }
+
+ // If it's not calling from cameraserver, check the permission.
+ if (callingPid != getpid() &&
+ !checkPermission(String16("android.permission.CAMERA"), clientPid, clientUid)) {
+ ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
+ return PERMISSION_DENIED;
+ }
+
+ // Only use passed in clientPid to check permission. Use calling PID as the client PID that's
+ // connected to camera service directly.
+ clientPid = callingPid;
+
if (!mModule) {
ALOGE("CameraService::connect X (PID %d) rejected (camera HAL module not loaded)",
callingPid);
@@ -888,18 +915,7 @@
return -ENODEV;
}
- // Check device policy for this camera
- char value[PROPERTY_VALUE_MAX];
- char key[PROPERTY_KEY_MAX];
userid_t clientUserId = multiuser_get_user_id(clientUid);
- snprintf(key, PROPERTY_KEY_MAX, "sys.secpolicy.camera.off_%d", clientUserId);
- property_get(key, value, "0");
- if (strcmp(value, "1") == 0) {
- // Camera is disabled by DevicePolicyManager.
- ALOGE("CameraService::connect X (PID %d) rejected (camera %s is disabled by device "
- "policy)", callingPid, cameraId.string());
- return -EACCES;
- }
// Only allow clients who are being used by the current foreground device user, unless calling
// from our own process.
@@ -1159,6 +1175,7 @@
int cameraId,
const String16& clientPackageName,
int clientUid,
+ int clientPid,
/*out*/
sp<ICamera>& device) {
@@ -1167,7 +1184,7 @@
String8 id = String8::format("%d", cameraId);
sp<Client> client = nullptr;
ret = connectHelper<ICameraClient,Client>(cameraClient, id, CAMERA_HAL_API_VERSION_UNSPECIFIED,
- clientPackageName, clientUid, API_1, false, false, /*out*/client);
+ clientPackageName, clientUid, clientPid, API_1, false, false, /*out*/client);
if(ret != NO_ERROR) {
logRejected(id, getCallingPid(), String8(clientPackageName),
@@ -1208,7 +1225,7 @@
status_t ret = NO_ERROR;
sp<Client> client = nullptr;
ret = connectHelper<ICameraClient,Client>(cameraClient, id, halVersion, clientPackageName,
- clientUid, API_1, true, false, /*out*/client);
+ clientUid, USE_CALLING_PID, API_1, true, false, /*out*/client);
if(ret != NO_ERROR) {
logRejected(id, getCallingPid(), String8(clientPackageName),
@@ -1233,8 +1250,8 @@
String8 id = String8::format("%d", cameraId);
sp<CameraDeviceClient> client = nullptr;
ret = connectHelper<ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
- CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, API_2, false, false,
- /*out*/client);
+ CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, USE_CALLING_PID,
+ API_2, false, false, /*out*/client);
if(ret != NO_ERROR) {
logRejected(id, getCallingPid(), String8(clientPackageName),
@@ -1320,7 +1337,6 @@
// update the link to client's death
Mutex::Autolock al(mTorchClientMapMutex);
ssize_t index = mTorchClientMap.indexOfKey(id);
- BatteryNotifier& notifier(BatteryNotifier::getInstance());
if (enabled) {
if (index == NAME_NOT_FOUND) {
mTorchClientMap.add(id, clientBinder);
@@ -1477,8 +1493,6 @@
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
- case CAMERA_DEVICE_API_VERSION_2_0:
- case CAMERA_DEVICE_API_VERSION_2_1:
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
if (apiVersion == API_VERSION_2) {
@@ -1569,8 +1583,34 @@
/**
* Check camera capabilities, such as support for basic color operation
+ * Also check that the device HAL version is still in support
*/
int CameraService::checkCameraCapabilities(int id, camera_info info, int *latestStrangeCameraId) {
+ // device_version undefined in CAMERA_MODULE_API_VERSION_1_0,
+ // All CAMERA_MODULE_API_VERSION_1_0 devices are backward-compatible
+ if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0) {
+ // Verify the device version is in the supported range
+ switch (info.device_version) {
+ case CAMERA_DEVICE_API_VERSION_1_0:
+ case CAMERA_DEVICE_API_VERSION_3_0:
+ case CAMERA_DEVICE_API_VERSION_3_1:
+ case CAMERA_DEVICE_API_VERSION_3_2:
+ case CAMERA_DEVICE_API_VERSION_3_3:
+ // in support
+ break;
+ case CAMERA_DEVICE_API_VERSION_2_0:
+ case CAMERA_DEVICE_API_VERSION_2_1:
+ // no longer supported
+ default:
+ ALOGE("%s: Device %d has HAL version %x, which is not supported",
+ __FUNCTION__, id, info.device_version);
+ String8 msg = String8::format(
+ "Unsupported device HAL version %x for device %d",
+ info.device_version, id);
+ logServiceError(msg.string(), NO_INIT);
+ return NO_INIT;
+ }
+ }
// Assume all devices pre-v3.3 are backward-compatible
bool isBackwardCompatible = true;
@@ -1605,10 +1645,10 @@
ALOGE("%s: Normal camera ID %d higher than strange camera ID %d. "
"This is not allowed due backward-compatibility requirements",
__FUNCTION__, id, *latestStrangeCameraId);
- logServiceError("Invalid order of camera devices", ENODEV);
+ logServiceError("Invalid order of camera devices", NO_INIT);
mNumberOfCameras = 0;
mNumberOfNormalCameras = 0;
- return INVALID_OPERATION;
+ return NO_INIT;
}
}
return OK;
@@ -1766,7 +1806,7 @@
void CameraService::logServiceError(const char* msg, int errorCode) {
String8 curTime = getFormattedCurrentTime();
- logEvent(String8::format("SERVICE ERROR: %s : %d (%s)", msg, errorCode, strerror(errorCode)));
+ logEvent(String8::format("SERVICE ERROR: %s : %d (%s)", msg, errorCode, strerror(-errorCode)));
}
status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
@@ -1777,21 +1817,6 @@
// Permission checks
switch (code) {
- case BnCameraService::CONNECT:
- case BnCameraService::CONNECT_DEVICE:
- case BnCameraService::CONNECT_LEGACY: {
- if (pid != selfPid) {
- // we're called from a different process, do the real check
- if (!checkCallingPermission(
- String16("android.permission.CAMERA"))) {
- const int uid = getCallingUid();
- ALOGE("Permission Denial: "
- "can't use the camera pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
- }
- break;
- }
case BnCameraService::NOTIFY_SYSTEM_EVENT: {
if (pid != selfPid) {
// Ensure we're being called by system_server, or similar process with
@@ -1916,6 +1941,37 @@
mServicePid = servicePid;
mOpsActive = false;
mDestructionStarted = false;
+
+ // In some cases the calling code has no access to the package it runs under.
+ // For example, NDK camera API.
+ // In this case we will get the packages for the calling UID and pick the first one
+ // for attributing the app op. This will work correctly for runtime permissions
+ // as for legacy apps we will toggle the app op for all packages in the UID.
+ // The caveat is that the operation may be attributed to the wrong package and
+ // stats based on app ops may be slightly off.
+ if (mClientPackageName.size() <= 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16(kPermissionServiceName));
+ if (binder == 0) {
+ ALOGE("Cannot get permission service");
+ // Leave mClientPackageName unchanged (empty) and the further interaction
+ // with camera will fail in BasicClient::startCameraOps
+ return;
+ }
+
+ sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
+ Vector<String16> packages;
+
+ permCtrl->getPackagesForUid(mClientUid, packages);
+
+ if (packages.isEmpty()) {
+ ALOGE("No packages for calling UID");
+ // Leave mClientPackageName unchanged (empty) and the further interaction
+ // with camera will fail in BasicClient::startCameraOps
+ return;
+ }
+ mClientPackageName = packages[0];
+ }
}
CameraService::BasicClient::~BasicClient() {
@@ -2095,6 +2151,8 @@
void CameraService::Client::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
const CaptureResultExtras& resultExtras) {
+ (void) errorCode;
+ (void) resultExtras;
if (mRemoteCallback != NULL) {
mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0);
} else {
@@ -2312,6 +2370,7 @@
result.appendFormat("Camera module name: %s\n", mModule->getModuleName());
result.appendFormat("Camera module author: %s\n", mModule->getModuleAuthor());
result.appendFormat("Number of camera devices: %d\n", mNumberOfCameras);
+ result.appendFormat("Number of normal camera devices: %d\n", mNumberOfNormalCameras);
String8 activeClientString = mActiveClientManager.toString();
result.appendFormat("Active Camera Clients:\n%s", activeClientString.string());
result.appendFormat("Allowed users:\n%s\n", toString(mAllowedUsers).string());
@@ -2362,7 +2421,7 @@
result.appendFormat(" Resource Cost: %d\n", state.second->getCost());
result.appendFormat(" Conflicting Devices:");
for (auto& id : conflicting) {
- result.appendFormat(" %s", cameraId.string());
+ result.appendFormat(" %s", id.string());
}
if (conflicting.size() == 0) {
result.appendFormat(" NONE");
@@ -2370,7 +2429,7 @@
result.appendFormat("\n");
result.appendFormat(" Device version: %#x\n", deviceVersion);
- if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
+ if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_0) {
result.appendFormat(" Device static metadata:\n");
write(fd, result.string(), result.size());
dump_indented_camera_metadata(info.static_camera_characteristics,
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index d2c1bd3..66de77f 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -116,7 +116,7 @@
virtual status_t getCameraVendorTagDescriptor(/*out*/ sp<VendorTagDescriptor>& desc);
virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
- const String16& clientPackageName, int clientUid,
+ const String16& clientPackageName, int clientUid, int clientPid,
/*out*/
sp<ICamera>& device);
@@ -244,13 +244,13 @@
bool mDestructionStarted;
// these are initialized in the constructor.
- sp<CameraService> mCameraService; // immutable after constructor
- int mCameraId; // immutable after constructor
- int mCameraFacing; // immutable after constructor
- const String16 mClientPackageName;
+ sp<CameraService> mCameraService; // immutable after constructor
+ int mCameraId; // immutable after constructor
+ int mCameraFacing; // immutable after constructor
+ String16 mClientPackageName; // immutable after constructor
pid_t mClientPid;
- uid_t mClientUid; // immutable after constructor
- pid_t mServicePid; // immutable after constructor
+ uid_t mClientUid; // immutable after constructor
+ pid_t mServicePid; // immutable after constructor
bool mDisconnected;
// - The app-side Binder interface to receive callbacks from us
@@ -299,7 +299,7 @@
virtual status_t startPreview() = 0;
virtual void stopPreview() = 0;
virtual bool previewEnabled() = 0;
- virtual status_t storeMetaDataInBuffers(bool enabled) = 0;
+ virtual status_t setVideoBufferMode(int32_t videoBufferMode) = 0;
virtual status_t startRecording() = 0;
virtual void stopRecording() = 0;
virtual bool recordingEnabled() = 0;
@@ -310,6 +310,7 @@
virtual status_t setParameters(const String8& params) = 0;
virtual String8 getParameters() const = 0;
virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
+ virtual status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer) = 0;
// Interface used by CameraService
Client(const sp<CameraService>& cameraService,
@@ -487,7 +488,8 @@
virtual void onFirstRef();
// Check if we can connect, before we acquire the service lock.
- status_t validateConnectLocked(const String8& cameraId, /*inout*/int& clientUid) const;
+ status_t validateConnectLocked(const String8& cameraId, /*inout*/int& clientUid,
+ /*inout*/int& clientPid) const;
// Handle active client evictions, and update service state.
// Only call with with mServiceLock held.
@@ -500,8 +502,9 @@
// Single implementation shared between the various connect calls
template<class CALLBACK, class CLIENT>
status_t connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId, int halVersion,
- const String16& clientPackageName, int clientUid, apiLevel effectiveApiLevel,
- bool legacyMode, bool shimUpdateOnly, /*out*/sp<CLIENT>& device);
+ const String16& clientPackageName, int clientUid, int clientPid,
+ apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
+ /*out*/sp<CLIENT>& device);
// Lock guarding camera service state
Mutex mServiceLock;
@@ -626,6 +629,7 @@
/**
* Add a event log message that a serious service-level error has occured
+ * The errorCode should be one of the Android Errors
*/
void logServiceError(const char* msg, int errorCode);
@@ -799,12 +803,11 @@
template<class CALLBACK, class CLIENT>
status_t CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
- int halVersion, const String16& clientPackageName, int clientUid,
+ int halVersion, const String16& clientPackageName, int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
/*out*/sp<CLIENT>& device) {
status_t ret = NO_ERROR;
String8 clientName8(clientPackageName);
- int clientPid = getCallingPid();
ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) for HAL version %s and "
"Camera API version %d", clientPid, clientName8.string(), cameraId.string(),
@@ -824,7 +827,8 @@
}
// Enforce client permissions and do basic sanity checks
- if((ret = validateConnectLocked(cameraId, /*inout*/clientUid)) != NO_ERROR) {
+ if((ret = validateConnectLocked(cameraId, /*inout*/clientUid, /*inout*/clientPid)) !=
+ NO_ERROR) {
return ret;
}
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index fbd4034..5ac5743 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -32,7 +32,6 @@
#include "api1/client2/CaptureSequencer.h"
#include "api1/client2/CallbackProcessor.h"
#include "api1/client2/ZslProcessor.h"
-#include "api1/client2/ZslProcessor3.h"
#define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
#define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
@@ -94,7 +93,6 @@
mStreamingProcessor = new StreamingProcessor(this);
threadName = String8::format("C2-%d-StreamProc",
mCameraId);
- mStreamingProcessor->run(threadName.string());
mFrameProcessor = new FrameProcessor(mDevice, this);
threadName = String8::format("C2-%d-FrameProc",
@@ -111,30 +109,11 @@
mCameraId);
mJpegProcessor->run(threadName.string());
- switch (mDeviceVersion) {
- case CAMERA_DEVICE_API_VERSION_2_0: {
- sp<ZslProcessor> zslProc =
- new ZslProcessor(this, mCaptureSequencer);
- mZslProcessor = zslProc;
- mZslProcessorThread = zslProc;
- break;
- }
- case CAMERA_DEVICE_API_VERSION_3_0:
- case CAMERA_DEVICE_API_VERSION_3_1:
- case CAMERA_DEVICE_API_VERSION_3_2:
- case CAMERA_DEVICE_API_VERSION_3_3: {
- sp<ZslProcessor3> zslProc =
- new ZslProcessor3(this, mCaptureSequencer);
- mZslProcessor = zslProc;
- mZslProcessorThread = zslProc;
- break;
- }
- default:
- break;
- }
+ mZslProcessor = new ZslProcessor(this, mCaptureSequencer);
+
threadName = String8::format("C2-%d-ZslProc",
mCameraId);
- mZslProcessorThread->run(threadName.string());
+ mZslProcessor->run(threadName.string());
mCallbackProcessor = new CallbackProcessor(this);
threadName = String8::format("C2-%d-CallbkProc",
@@ -392,7 +371,7 @@
ATRACE_CALL();
Mutex::Autolock icl(mBinderSerializationLock);
- // Allow both client and the media server to disconnect at all times
+ // Allow both client and the cameraserver to disconnect at all times
int callingPid = getCallingPid();
if (callingPid != mClientPid && callingPid != mServicePid) return;
@@ -414,11 +393,10 @@
l.mParameters.state = Parameters::DISCONNECTED;
}
- mStreamingProcessor->requestExit();
mFrameProcessor->requestExit();
mCaptureSequencer->requestExit();
mJpegProcessor->requestExit();
- mZslProcessorThread->requestExit();
+ mZslProcessor->requestExit();
mCallbackProcessor->requestExit();
ALOGV("Camera %d: Waiting for threads", mCameraId);
@@ -428,11 +406,10 @@
// complete callbacks that re-enter Camera2Client
mBinderSerializationLock.unlock();
- mStreamingProcessor->join();
mFrameProcessor->join();
mCaptureSequencer->join();
mJpegProcessor->join();
- mZslProcessorThread->join();
+ mZslProcessor->join();
mCallbackProcessor->join();
mBinderSerializationLock.lock();
@@ -446,9 +423,6 @@
mCallbackProcessor->deleteStream();
mZslProcessor->deleteStream();
- // Remove all ZSL stream state before disconnect; needed to work around b/15408128.
- mZslProcessor->disconnect();
-
ALOGV("Camera %d: Disconnecting device", mCameraId);
mDevice->disconnect();
@@ -765,8 +739,8 @@
// We could wait to create the JPEG output stream until first actual use
// (first takePicture call). However, this would substantially increase the
- // first capture latency on HAL3 devices, and potentially on some HAL2
- // devices. So create it unconditionally at preview start. As a drawback,
+ // first capture latency on HAL3 devices.
+ // So create it unconditionally at preview start. As a drawback,
// this increases gralloc memory consumption for applications that don't
// ever take a picture. Do not enter this mode when jpeg stream will slow
// down preview.
@@ -971,7 +945,7 @@
return l.mParameters.state == Parameters::PREVIEW;
}
-status_t Camera2Client::storeMetaDataInBuffers(bool enabled) {
+status_t Camera2Client::setVideoBufferMode(int32_t videoBufferMode) {
ATRACE_CALL();
Mutex::Autolock icl(mBinderSerializationLock);
status_t res;
@@ -990,7 +964,12 @@
break;
}
- l.mParameters.storeMetadataInBuffers = enabled;
+ if (videoBufferMode != VIDEO_BUFFER_MODE_BUFFER_QUEUE) {
+ ALOGE("%s: %d: Only video buffer queue is supported", __FUNCTION__, __LINE__);
+ return BAD_VALUE;
+ }
+
+ l.mParameters.videoBufferMode = videoBufferMode;
return OK;
}
@@ -1036,10 +1015,14 @@
return INVALID_OPERATION;
};
- if (!params.storeMetadataInBuffers) {
- ALOGE("%s: Camera %d: Recording only supported in metadata mode, but "
- "non-metadata recording mode requested!", __FUNCTION__,
- mCameraId);
+ if (params.videoBufferMode != VIDEO_BUFFER_MODE_BUFFER_QUEUE) {
+ ALOGE("%s: Camera %d: Recording only supported buffer queue mode, but "
+ "mode %d is requested!", __FUNCTION__, mCameraId, params.videoBufferMode);
+ return INVALID_OPERATION;
+ }
+
+ if (!mStreamingProcessor->haveValidRecordingWindow()) {
+ ALOGE("%s: No valid recording window", __FUNCTION__);
return INVALID_OPERATION;
}
@@ -1073,35 +1056,33 @@
}
}
- // On current HALs, clean up ZSL before transitioning into recording
- if (mDeviceVersion != CAMERA_DEVICE_API_VERSION_2_0) {
- if (mZslProcessor->getStreamId() != NO_STREAM) {
- ALOGV("%s: Camera %d: Clearing out zsl stream before "
- "creating recording stream", __FUNCTION__, mCameraId);
- res = mStreamingProcessor->stopStream();
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't stop streaming to delete callback stream",
- __FUNCTION__, mCameraId);
- return res;
- }
- res = mDevice->waitUntilDrained();
- if (res != OK) {
- ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- }
- res = mZslProcessor->clearZslQueue();
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't clear zsl queue",
- __FUNCTION__, mCameraId);
- return res;
- }
- res = mZslProcessor->deleteStream();
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to delete zsl stream before "
- "record: %s (%d)", __FUNCTION__, mCameraId,
- strerror(-res), res);
- return res;
- }
+ // Clean up ZSL before transitioning into recording
+ if (mZslProcessor->getStreamId() != NO_STREAM) {
+ ALOGV("%s: Camera %d: Clearing out zsl stream before "
+ "creating recording stream", __FUNCTION__, mCameraId);
+ res = mStreamingProcessor->stopStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't stop streaming to delete callback stream",
+ __FUNCTION__, mCameraId);
+ return res;
+ }
+ res = mDevice->waitUntilDrained();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ }
+ res = mZslProcessor->clearZslQueue();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't clear zsl queue",
+ __FUNCTION__, mCameraId);
+ return res;
+ }
+ res = mZslProcessor->deleteStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete zsl stream before "
+ "record: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
}
}
@@ -1109,56 +1090,43 @@
// and we can't fail record start without stagefright asserting.
params.previewCallbackFlags = 0;
- if (mDeviceVersion != CAMERA_DEVICE_API_VERSION_2_0) {
- // For newer devices, may need to reconfigure video snapshot JPEG sizes
- // during recording startup, so need a more complex sequence here to
- // ensure an early stream reconfiguration doesn't happen
- bool recordingStreamNeedsUpdate;
- res = mStreamingProcessor->recordingStreamNeedsUpdate(params, &recordingStreamNeedsUpdate);
+ // May need to reconfigure video snapshot JPEG sizes
+ // during recording startup, so need a more complex sequence here to
+ // ensure an early stream reconfiguration doesn't happen
+ bool recordingStreamNeedsUpdate;
+ res = mStreamingProcessor->recordingStreamNeedsUpdate(params, &recordingStreamNeedsUpdate);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't query recording stream",
+ __FUNCTION__, mCameraId);
+ return res;
+ }
+
+ if (recordingStreamNeedsUpdate) {
+ // Need to stop stream here so updateProcessorStream won't trigger configureStream
+ // Right now camera device cannot handle configureStream failure gracefully
+ // when device is streaming
+ res = mStreamingProcessor->stopStream();
if (res != OK) {
- ALOGE("%s: Camera %d: Can't query recording stream",
- __FUNCTION__, mCameraId);
+ ALOGE("%s: Camera %d: Can't stop streaming to update record "
+ "stream", __FUNCTION__, mCameraId);
return res;
}
-
- if (recordingStreamNeedsUpdate) {
- // Need to stop stream here so updateProcessorStream won't trigger configureStream
- // Right now camera device cannot handle configureStream failure gracefully
- // when device is streaming
- res = mStreamingProcessor->stopStream();
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't stop streaming to update record "
- "stream", __FUNCTION__, mCameraId);
- return res;
- }
- res = mDevice->waitUntilDrained();
- if (res != OK) {
- ALOGE("%s: Camera %d: Waiting to stop streaming failed: "
- "%s (%d)", __FUNCTION__, mCameraId,
- strerror(-res), res);
- }
-
- res = updateProcessorStream<
- StreamingProcessor,
- &StreamingProcessor::updateRecordingStream>(
- mStreamingProcessor,
- params);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to update recording stream: "
- "%s (%d)", __FUNCTION__, mCameraId,
- strerror(-res), res);
- return res;
- }
- }
- } else {
- // Maintain call sequencing for HALv2 devices.
- res = updateProcessorStream<
- StreamingProcessor,
- &StreamingProcessor::updateRecordingStream>(mStreamingProcessor,
- params);
+ res = mDevice->waitUntilDrained();
if (res != OK) {
- ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
+ ALOGE("%s: Camera %d: Waiting to stop streaming failed: "
+ "%s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ }
+
+ res = updateProcessorStream<
+ StreamingProcessor,
+ &StreamingProcessor::updateRecordingStream>(
+ mStreamingProcessor,
+ params);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update recording stream: "
+ "%s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
return res;
}
}
@@ -1218,28 +1186,28 @@
mCameraService->playSound(CameraService::SOUND_RECORDING_STOP);
- // Remove recording stream to prevent it from slowing down takePicture later
- if (!l.mParameters.recordingHint && l.mParameters.isJpegSizeOverridden()) {
- res = stopStream();
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't stop streaming: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- }
- res = mDevice->waitUntilDrained();
- if (res != OK) {
- ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- }
- // Clean up recording stream
- res = mStreamingProcessor->deleteRecordingStream();
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to delete recording stream before "
- "stop preview: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- }
- l.mParameters.recoverOverriddenJpegSize();
+ // Remove recording stream because the video target may be abandoned soon.
+ res = stopStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't stop streaming: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
}
+ res = mDevice->waitUntilDrained();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ }
+ // Clean up recording stream
+ res = mStreamingProcessor->deleteRecordingStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete recording stream before "
+ "stop preview: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ }
+ l.mParameters.recoverOverriddenJpegSize();
+
+ // Restart preview
res = startPreviewL(l.mParameters, true);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to return to preview",
@@ -1265,11 +1233,9 @@
}
void Camera2Client::releaseRecordingFrame(const sp<IMemory>& mem) {
+ (void)mem;
ATRACE_CALL();
- Mutex::Autolock icl(mBinderSerializationLock);
- if ( checkPid(__FUNCTION__) != OK) return;
-
- mStreamingProcessor->releaseRecordingFrame(mem);
+ ALOGW("%s: Not supported in buffer queue mode.", __FUNCTION__);
}
status_t Camera2Client::autoFocus() {
@@ -1571,10 +1537,10 @@
case CAMERA_CMD_PING:
return commandPingL();
case CAMERA_CMD_SET_VIDEO_BUFFER_COUNT:
- return commandSetVideoBufferCountL(arg1);
case CAMERA_CMD_SET_VIDEO_FORMAT:
- return commandSetVideoFormatL(arg1,
- static_cast<android_dataspace>(arg2));
+ ALOGE("%s: command %d (arguments %d, %d) is not supported.",
+ __FUNCTION__, cmd, arg1, arg2);
+ return BAD_VALUE;
default:
ALOGE("%s: Unknown command %d (arguments %d, %d)",
__FUNCTION__, cmd, arg1, arg2);
@@ -1716,27 +1682,6 @@
}
}
-status_t Camera2Client::commandSetVideoBufferCountL(size_t count) {
- if (recordingEnabledL()) {
- ALOGE("%s: Camera %d: Error setting video buffer count after "
- "recording was started", __FUNCTION__, mCameraId);
- return INVALID_OPERATION;
- }
-
- return mStreamingProcessor->setRecordingBufferCount(count);
-}
-
-status_t Camera2Client::commandSetVideoFormatL(int format,
- android_dataspace dataspace) {
- if (recordingEnabledL()) {
- ALOGE("%s: Camera %d: Error setting video format after "
- "recording was started", __FUNCTION__, mCameraId);
- return INVALID_OPERATION;
- }
-
- return mStreamingProcessor->setRecordingFormat(format, dataspace);
-}
-
void Camera2Client::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
const CaptureResultExtras& resultExtras) {
int32_t err = CAMERA_ERROR_UNKNOWN;
@@ -2160,6 +2105,84 @@
return res;
}
+status_t Camera2Client::setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer) {
+ ATRACE_CALL();
+ ALOGV("%s: E", __FUNCTION__);
+ Mutex::Autolock icl(mBinderSerializationLock);
+ status_t res;
+ if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+ sp<IBinder> binder = IInterface::asBinder(bufferProducer);
+ if (binder == mVideoSurface) {
+ ALOGV("%s: Camera %d: New video window is same as old video window",
+ __FUNCTION__, mCameraId);
+ return NO_ERROR;
+ }
+
+ sp<Surface> window;
+ int format;
+ android_dataspace dataSpace;
+
+ if (bufferProducer != nullptr) {
+ // Using controlledByApp flag to ensure that the buffer queue remains in
+ // async mode for the old camera API, where many applications depend
+ // on that behavior.
+ window = new Surface(bufferProducer, /*controlledByApp*/ true);
+
+ ANativeWindow *anw = window.get();
+
+ if ((res = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) {
+ ALOGE("%s: Failed to query Surface format", __FUNCTION__);
+ return res;
+ }
+
+ if ((res = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE,
+ reinterpret_cast<int*>(&dataSpace))) != OK) {
+ ALOGE("%s: Failed to query Surface dataSpace", __FUNCTION__);
+ return res;
+ }
+ }
+
+ Parameters::State state;
+ {
+ SharedParameters::Lock l(mParameters);
+ state = l.mParameters.state;
+ }
+
+ switch (state) {
+ case Parameters::STOPPED:
+ case Parameters::WAITING_FOR_PREVIEW_WINDOW:
+ case Parameters::PREVIEW:
+ // OK
+ break;
+ case Parameters::DISCONNECTED:
+ case Parameters::RECORD:
+ case Parameters::STILL_CAPTURE:
+ case Parameters::VIDEO_SNAPSHOT:
+ default:
+ ALOGE("%s: Camera %d: Cannot set video target while in state %s",
+ __FUNCTION__, mCameraId,
+ Parameters::getStateName(state));
+ return INVALID_OPERATION;
+ }
+
+ mVideoSurface = binder;
+ res = mStreamingProcessor->setRecordingWindow(window);
+ if (res != OK) {
+ ALOGE("%s: Unable to set new recording window: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ {
+ SharedParameters::Lock l(mParameters);
+ l.mParameters.videoFormat = format;
+ l.mParameters.videoDataSpace = dataSpace;
+ }
+
+ return OK;
+}
+
const char* Camera2Client::kAutofocusLabel = "autofocus";
const char* Camera2Client::kTakepictureLabel = "take_picture";
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 7e7a284..9155e43 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -24,7 +24,7 @@
#include "api1/client2/FrameProcessor.h"
//#include "api1/client2/StreamingProcessor.h"
//#include "api1/client2/JpegProcessor.h"
-//#include "api1/client2/ZslProcessorInterface.h"
+//#include "api1/client2/ZslProcessor.h"
//#include "api1/client2/CaptureSequencer.h"
//#include "api1/client2/CallbackProcessor.h"
@@ -34,7 +34,7 @@
class StreamingProcessor;
class JpegProcessor;
-class ZslProcessorInterface;
+class ZslProcessor;
class CaptureSequencer;
class CallbackProcessor;
@@ -43,7 +43,7 @@
class IMemory;
/**
* Interface between android.hardware.Camera API and Camera HAL device for versions
- * CAMERA_DEVICE_API_VERSION_2_0 and 3_0.
+ * CAMERA_DEVICE_API_VERSION_3_0 and above.
*/
class Camera2Client :
public Camera2ClientBase<CameraService::Client>
@@ -66,7 +66,7 @@
virtual status_t startPreview();
virtual void stopPreview();
virtual bool previewEnabled();
- virtual status_t storeMetaDataInBuffers(bool enabled);
+ virtual status_t setVideoBufferMode(int32_t videoBufferMode);
virtual status_t startRecording();
virtual void stopRecording();
virtual bool recordingEnabled();
@@ -79,6 +79,7 @@
virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
const CaptureResultExtras& resultExtras);
+ virtual status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
/**
* Interface used by CameraService
@@ -196,6 +197,7 @@
/* Preview/Recording related members */
sp<IBinder> mPreviewSurface;
+ sp<IBinder> mVideoSurface;
sp<camera2::StreamingProcessor> mStreamingProcessor;
/** Preview callback related members */
@@ -206,12 +208,7 @@
sp<camera2::CaptureSequencer> mCaptureSequencer;
sp<camera2::JpegProcessor> mJpegProcessor;
- sp<camera2::ZslProcessorInterface> mZslProcessor;
- sp<Thread> mZslProcessorThread;
-
- /** Notification-related members */
-
- bool mAfInMotion;
+ sp<camera2::ZslProcessor> mZslProcessor;
/** Utility members */
bool mLegacyMode;
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index 6020e35..8ab9a65 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -234,17 +234,12 @@
LOG1("disconnect E (pid %d)", callingPid);
Mutex::Autolock lock(mLock);
- // Allow both client and the media server to disconnect at all times
+ // Allow both client and the cameraserver to disconnect at all times
if (callingPid != mClientPid && callingPid != mServicePid) {
ALOGW("different client - don't disconnect");
return;
}
- if (mClientPid <= 0) {
- LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
- return;
- }
-
// Make sure disconnect() is done once and once only, whether it is called
// from the user directly, or called by the destructor.
if (mHardware == 0) return;
@@ -300,9 +295,8 @@
// If preview has been already started, register preview buffers now.
if (mHardware->previewEnabled()) {
if (window != 0) {
- native_window_set_scaling_mode(window.get(),
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- native_window_set_buffers_transform(window.get(), mOrientation);
+ mHardware->setPreviewScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ mHardware->setPreviewTransform(mOrientation);
result = mHardware->setPreviewWindow(window);
}
}
@@ -409,10 +403,9 @@
}
if (mPreviewWindow != 0) {
- native_window_set_scaling_mode(mPreviewWindow.get(),
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- native_window_set_buffers_transform(mPreviewWindow.get(),
- mOrientation);
+ mHardware->setPreviewScalingMode(
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ mHardware->setPreviewTransform(mOrientation);
}
mHardware->setPreviewWindow(mPreviewWindow);
result = mHardware->startPreview();
@@ -486,14 +479,24 @@
mHardware->releaseRecordingFrame(mem);
}
-status_t CameraClient::storeMetaDataInBuffers(bool enabled)
-{
- LOG1("storeMetaDataInBuffers: %s", enabled? "true": "false");
+status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
+ LOG1("setVideoBufferMode: %d", videoBufferMode);
+ bool enableMetadataInBuffers = false;
+
+ if (videoBufferMode == VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA) {
+ enableMetadataInBuffers = true;
+ } else if (videoBufferMode != VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV) {
+ ALOGE("%s: %d: videoBufferMode %d is not supported.", __FUNCTION__, __LINE__,
+ videoBufferMode);
+ return BAD_VALUE;
+ }
+
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) {
return UNKNOWN_ERROR;
}
- return mHardware->storeMetaDataInBuffers(enabled);
+
+ return mHardware->storeMetaDataInBuffers(enableMetadataInBuffers);
}
bool CameraClient::previewEnabled() {
@@ -636,8 +639,7 @@
if (mOrientation != orientation) {
mOrientation = orientation;
if (mPreviewWindow != 0) {
- native_window_set_buffers_transform(mPreviewWindow.get(),
- mOrientation);
+ mHardware->setPreviewTransform(mOrientation);
}
}
return OK;
@@ -995,4 +997,10 @@
return -1;
}
+status_t CameraClient::setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer) {
+ (void)bufferProducer;
+ ALOGE("%s: %d: CameraClient doesn't support setting a video target.", __FUNCTION__, __LINE__);
+ return INVALID_OPERATION;
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 17999a5..9b32774 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -44,7 +44,7 @@
virtual status_t startPreview();
virtual void stopPreview();
virtual bool previewEnabled();
- virtual status_t storeMetaDataInBuffers(bool enabled);
+ virtual status_t setVideoBufferMode(int32_t videoBufferMode);
virtual status_t startRecording();
virtual void stopRecording();
virtual bool recordingEnabled();
@@ -55,6 +55,7 @@
virtual status_t setParameters(const String8& params);
virtual String8 getParameters() const;
virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
+ virtual status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
// Interface used by CameraService
CameraClient(const sp<CameraService>& cameraService,
diff --git a/services/camera/libcameraservice/api1/client2/BurstCapture.cpp b/services/camera/libcameraservice/api1/client2/BurstCapture.cpp
deleted file mode 100644
index 5502dcb..0000000
--- a/services/camera/libcameraservice/api1/client2/BurstCapture.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2012 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 "Camera2-BurstCapture"
-
-#include <utils/Log.h>
-#include <utils/Trace.h>
-
-#include "BurstCapture.h"
-
-#include "api1/Camera2Client.h"
-#include "api1/client2/JpegCompressor.h"
-
-namespace android {
-namespace camera2 {
-
-BurstCapture::BurstCapture(wp<Camera2Client> client, wp<CaptureSequencer> sequencer):
- mCaptureStreamId(NO_STREAM),
- mClient(client),
- mSequencer(sequencer)
-{
-}
-
-BurstCapture::~BurstCapture() {
-}
-
-status_t BurstCapture::start(Vector<CameraMetadata> &/*metadatas*/,
- int32_t /*firstCaptureId*/) {
- ALOGE("Not completely implemented");
- return INVALID_OPERATION;
-}
-
-void BurstCapture::onFrameAvailable(const BufferItem &/*item*/) {
- ALOGV("%s", __FUNCTION__);
- Mutex::Autolock l(mInputMutex);
- if(!mInputChanged) {
- mInputChanged = true;
- mInputSignal.signal();
- }
-}
-
-bool BurstCapture::threadLoop() {
- status_t res;
- {
- Mutex::Autolock l(mInputMutex);
- while(!mInputChanged) {
- res = mInputSignal.waitRelative(mInputMutex, kWaitDuration);
- if(res == TIMED_OUT) return true;
- }
- mInputChanged = false;
- }
-
- do {
- sp<Camera2Client> client = mClient.promote();
- if(client == 0) return false;
- ALOGV("%s: Calling processFrameAvailable()", __FUNCTION__);
- res = processFrameAvailable(client);
- } while(res == OK);
-
- return true;
-}
-
-CpuConsumer::LockedBuffer* BurstCapture::jpegEncode(
- CpuConsumer::LockedBuffer *imgBuffer,
- int /*quality*/)
-{
- ALOGV("%s", __FUNCTION__);
-
- CpuConsumer::LockedBuffer *imgEncoded = new CpuConsumer::LockedBuffer;
- uint8_t *data = new uint8_t[ANDROID_JPEG_MAX_SIZE];
- imgEncoded->data = data;
- imgEncoded->width = imgBuffer->width;
- imgEncoded->height = imgBuffer->height;
- imgEncoded->stride = imgBuffer->stride;
-
- Vector<CpuConsumer::LockedBuffer*> buffers;
- buffers.push_back(imgBuffer);
- buffers.push_back(imgEncoded);
-
- sp<JpegCompressor> jpeg = new JpegCompressor();
- jpeg->start(buffers, 1);
-
- bool success = jpeg->waitForDone(10 * 1e9);
- if(success) {
- return buffers[1];
- }
- else {
- ALOGE("%s: JPEG encode timed out", __FUNCTION__);
- return NULL; // TODO: maybe change function return value to status_t
- }
-}
-
-status_t BurstCapture::processFrameAvailable(sp<Camera2Client> &/*client*/) {
- ALOGE("Not implemented");
- return INVALID_OPERATION;
-}
-
-} // namespace camera2
-} // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/BurstCapture.h b/services/camera/libcameraservice/api1/client2/BurstCapture.h
deleted file mode 100644
index c3b7722..0000000
--- a/services/camera/libcameraservice/api1/client2/BurstCapture.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2012 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_SERVERS_CAMERA_BURST_CAPTURE_H
-#define ANDROID_SERVERS_CAMERA_BURST_CAPTURE_H
-
-#include <camera/CameraMetadata.h>
-#include <binder/MemoryBase.h>
-#include <binder/MemoryHeapBase.h>
-#include <gui/CpuConsumer.h>
-
-#include "device2/Camera2Device.h"
-
-namespace android {
-
-class Camera2Client;
-
-namespace camera2 {
-
-class CaptureSequencer;
-
-class BurstCapture : public virtual Thread,
- public virtual CpuConsumer::FrameAvailableListener
-{
-public:
- BurstCapture(wp<Camera2Client> client, wp<CaptureSequencer> sequencer);
- virtual ~BurstCapture();
-
- virtual void onFrameAvailable(const BufferItem& item);
- virtual status_t start(Vector<CameraMetadata> &metadatas, int32_t firstCaptureId);
-
-protected:
- Mutex mInputMutex;
- bool mInputChanged;
- Condition mInputSignal;
- int mCaptureStreamId;
- wp<Camera2Client> mClient;
- wp<CaptureSequencer> mSequencer;
-
- // Should only be accessed by processing thread
- enum {
- NO_STREAM = -1
- };
-
- CpuConsumer::LockedBuffer* jpegEncode(
- CpuConsumer::LockedBuffer *imgBuffer,
- int quality);
-
- virtual status_t processFrameAvailable(sp<Camera2Client> &client);
-
-private:
- virtual bool threadLoop();
- static const nsecs_t kWaitDuration = 10000000; // 10 ms
-};
-
-} // namespace camera2
-} // namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.h b/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
index a290536..a22442f 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
@@ -33,7 +33,7 @@
namespace camera2 {
-class Parameters;
+struct Parameters;
/***
* Still image capture output image processing
@@ -75,7 +75,6 @@
sp<CpuConsumer> mCallbackConsumer;
sp<Surface> mCallbackWindow;
sp<Camera2Heap> mCallbackHeap;
- int mCallbackHeapId;
size_t mCallbackHeapHead, mCallbackHeapFree;
virtual bool threadLoop();
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 5f7fd74..61e1442 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -26,9 +26,8 @@
#include "api1/Camera2Client.h"
#include "api1/client2/CaptureSequencer.h"
-#include "api1/client2/BurstCapture.h"
#include "api1/client2/Parameters.h"
-#include "api1/client2/ZslProcessorInterface.h"
+#include "api1/client2/ZslProcessor.h"
namespace android {
namespace camera2 {
@@ -59,7 +58,7 @@
ALOGV("%s: Exit", __FUNCTION__);
}
-void CaptureSequencer::setZslProcessor(wp<ZslProcessorInterface> processor) {
+void CaptureSequencer::setZslProcessor(wp<ZslProcessor> processor) {
Mutex::Autolock l(mInputMutex);
mZslProcessor = processor;
}
@@ -111,6 +110,7 @@
void CaptureSequencer::notifyShutter(const CaptureResultExtras& resultExtras,
nsecs_t timestamp) {
ATRACE_CALL();
+ (void) timestamp;
Mutex::Autolock l(mInputMutex);
if (!mHalNotifiedShutter && resultExtras.requestId == mShutterCaptureId) {
mHalNotifiedShutter = true;
@@ -174,8 +174,6 @@
"STANDARD_PRECAPTURE_WAIT",
"STANDARD_CAPTURE",
"STANDARD_CAPTURE_WAIT",
- "BURST_CAPTURE_START",
- "BURST_CAPTURE_WAIT",
"DONE",
"ERROR",
"UNKNOWN"
@@ -192,8 +190,6 @@
&CaptureSequencer::manageStandardPrecaptureWait,
&CaptureSequencer::manageStandardCapture,
&CaptureSequencer::manageStandardCaptureWait,
- &CaptureSequencer::manageBurstCaptureStart,
- &CaptureSequencer::manageBurstCaptureWait,
&CaptureSequencer::manageDone,
};
@@ -293,7 +289,7 @@
}
takePictureCounter = l.mParameters.takePictureCounter;
}
- sp<ZslProcessorInterface> processor = mZslProcessor.promote();
+ sp<ZslProcessor> processor = mZslProcessor.promote();
if (processor != 0) {
ALOGV("%s: Memory optimization, clearing ZSL queue",
__FUNCTION__);
@@ -336,10 +332,6 @@
return DONE;
}
- if(l.mParameters.lightFx != Parameters::LIGHTFX_NONE &&
- l.mParameters.state == Parameters::STILL_CAPTURE) {
- nextState = BURST_CAPTURE_START;
- }
else if (l.mParameters.zslMode &&
l.mParameters.state == Parameters::STILL_CAPTURE &&
l.mParameters.flashMode != Parameters::FLASH_MODE_ON) {
@@ -361,7 +353,7 @@
sp<Camera2Client> &client) {
ALOGV("%s", __FUNCTION__);
status_t res;
- sp<ZslProcessorInterface> processor = mZslProcessor.promote();
+ sp<ZslProcessor> processor = mZslProcessor.promote();
if (processor == 0) {
ALOGE("%s: No ZSL queue to use!", __FUNCTION__);
return DONE;
@@ -664,76 +656,6 @@
return STANDARD_CAPTURE_WAIT;
}
-CaptureSequencer::CaptureState CaptureSequencer::manageBurstCaptureStart(
- sp<Camera2Client> &client) {
- ALOGV("%s", __FUNCTION__);
- status_t res;
- ATRACE_CALL();
-
- // check which burst mode is set, create respective burst object
- {
- SharedParameters::Lock l(client->getParameters());
-
- res = updateCaptureRequest(l.mParameters, client);
- if(res != OK) {
- return DONE;
- }
-
- //
- // check for burst mode type in mParameters here
- //
- mBurstCapture = new BurstCapture(client, this);
- }
-
- res = mCaptureRequest.update(ANDROID_REQUEST_ID, &mCaptureId, 1);
- if (res == OK) {
- res = mCaptureRequest.sort();
- }
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to set up still capture request: %s (%d)",
- __FUNCTION__, client->getCameraId(), strerror(-res), res);
- return DONE;
- }
-
- CameraMetadata captureCopy = mCaptureRequest;
- if (captureCopy.entryCount() == 0) {
- ALOGE("%s: Camera %d: Unable to copy capture request for HAL device",
- __FUNCTION__, client->getCameraId());
- return DONE;
- }
-
- Vector<CameraMetadata> requests;
- requests.push(mCaptureRequest);
- res = mBurstCapture->start(requests, mCaptureId);
- mTimeoutCount = kMaxTimeoutsForCaptureEnd * 10;
- return BURST_CAPTURE_WAIT;
-}
-
-CaptureSequencer::CaptureState CaptureSequencer::manageBurstCaptureWait(
- sp<Camera2Client> &/*client*/) {
- status_t res;
- ATRACE_CALL();
- while (!mNewCaptureReceived) {
- res = mNewCaptureSignal.waitRelative(mInputMutex, kWaitDuration);
- if (res == TIMED_OUT) {
- mTimeoutCount--;
- break;
- }
- }
-
- if (mTimeoutCount <= 0) {
- ALOGW("Timed out waiting for burst capture to complete");
- return DONE;
- }
- if (mNewCaptureReceived) {
- mNewCaptureReceived = false;
- // TODO: update mCaptureId to last burst's capture ID + 1?
- return DONE;
- }
-
- return BURST_CAPTURE_WAIT;
-}
-
status_t CaptureSequencer::updateCaptureRequest(const Parameters ¶ms,
sp<Camera2Client> &client) {
ATRACE_CALL();
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index 10252fb..b05207e 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -34,8 +34,7 @@
namespace camera2 {
-class ZslProcessorInterface;
-class BurstCapture;
+class ZslProcessor;
/**
* Manages the still image capture process for
@@ -49,7 +48,7 @@
~CaptureSequencer();
// Get reference to the ZslProcessor, which holds the ZSL buffers and frames
- void setZslProcessor(wp<ZslProcessorInterface> processor);
+ void setZslProcessor(wp<ZslProcessor> processor);
// Begin still image capture
status_t startCapture(int msgType);
@@ -113,8 +112,7 @@
static const int kMaxTimeoutsForCaptureEnd = 40; // 4 sec
wp<Camera2Client> mClient;
- wp<ZslProcessorInterface> mZslProcessor;
- sp<BurstCapture> mBurstCapture;
+ wp<ZslProcessor> mZslProcessor;
enum CaptureState {
IDLE,
@@ -126,8 +124,6 @@
STANDARD_PRECAPTURE_WAIT,
STANDARD_CAPTURE,
STANDARD_CAPTURE_WAIT,
- BURST_CAPTURE_START,
- BURST_CAPTURE_WAIT,
DONE,
ERROR,
NUM_CAPTURE_STATES
@@ -165,9 +161,6 @@
CaptureState manageStandardCapture(sp<Camera2Client> &client);
CaptureState manageStandardCaptureWait(sp<Camera2Client> &client);
- CaptureState manageBurstCaptureStart(sp<Camera2Client> &client);
- CaptureState manageBurstCaptureWait(sp<Camera2Client> &client);
-
CaptureState manageDone(sp<Camera2Client> &client);
// Utility methods
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
index 40d53b3..6490682 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
@@ -170,7 +170,7 @@
entry = frame.find(ANDROID_SCALER_CROP_REGION);
if (entry.count < 4) {
- ALOGE("%s: Camera %d: Unable to read crop region (count = %d)",
+ ALOGE("%s: Camera %d: Unable to read crop region (count = %zu)",
__FUNCTION__, client->getCameraId(), entry.count);
return res;
}
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index bd9786f..3923853 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -108,7 +108,7 @@
return NO_MEMORY;
}
}
- ALOGV("%s: Camera %d: JPEG capture heap now %d bytes; requested %d bytes",
+ ALOGV("%s: Camera %d: JPEG capture heap now %zu bytes; requested %zd bytes",
__FUNCTION__, mId, mCaptureHeap->getSize(), maxJpegSize);
if (mCaptureStreamId != NO_STREAM) {
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.h b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
index fbdae11..ac6f5c7 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
@@ -35,7 +35,7 @@
namespace camera2 {
class CaptureSequencer;
-class Parameters;
+struct Parameters;
/***
* Still image capture output image processing
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 44447b4..7a97396 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -30,6 +30,7 @@
#include "Parameters.h"
#include "system/camera.h"
#include "hardware/camera_common.h"
+#include <camera/ICamera.h>
#include <media/MediaProfiles.h>
#include <media/mediarecorder.h>
@@ -870,8 +871,9 @@
}
// Set up initial state for non-Camera.Parameters state variables
-
- storeMetadataInBuffers = true;
+ videoFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ videoDataSpace = HAL_DATASPACE_BT709;
+ videoBufferMode = ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV;
playShutterSound = true;
enableFaceDetect = false;
@@ -913,8 +915,6 @@
ALOGI("%s: zslMode: %d slowJpegMode %d", __FUNCTION__, zslMode, slowJpegMode);
- lightFx = LIGHTFX_NONE;
-
state = STOPPED;
paramsFlattened = params.flatten();
@@ -1040,7 +1040,7 @@
ALOGE("%s: Camera %d: Scene mode override list is an "
"unexpected size: %zu (expected %zu)", __FUNCTION__,
cameraId, sceneModeOverrides.count,
- availableSceneModes.count);
+ availableSceneModes.count * kModesPerSceneMode);
return NO_INIT;
}
for (size_t i = 0; i < availableSceneModes.count; i++) {
@@ -1864,10 +1864,6 @@
ALOGE("%s: Video stabilization not supported", __FUNCTION__);
}
- // LIGHTFX
- validatedParams.lightFx = lightFxStringToEnum(
- newParams.get(CameraParameters::KEY_LIGHTFX));
-
/** Update internal parameters */
*this = validatedParams;
@@ -1959,7 +1955,7 @@
if (res != OK) return res;
// android.hardware.Camera requires that when face detect is enabled, the
- // camera is in a face-priority mode. HAL2 splits this into separate parts
+ // camera is in a face-priority mode. HAL3.x splits this into separate parts
// (face detection statistics and face priority scene mode). Map from other
// to the other.
bool sceneModeActive =
@@ -2501,18 +2497,6 @@
}
}
-Parameters::Parameters::lightFxMode_t Parameters::lightFxStringToEnum(
- const char *lightFxMode) {
- return
- !lightFxMode ?
- Parameters::LIGHTFX_NONE :
- !strcmp(lightFxMode, CameraParameters::LIGHTFX_LOWLIGHT) ?
- Parameters::LIGHTFX_LOWLIGHT :
- !strcmp(lightFxMode, CameraParameters::LIGHTFX_HDR) ?
- Parameters::LIGHTFX_HDR :
- Parameters::LIGHTFX_NONE;
-}
-
status_t Parameters::parseAreas(const char *areasCStr,
Vector<Parameters::Area> *areas) {
static const size_t NUM_FIELDS = 5;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 972d007..c437722 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -131,23 +131,19 @@
int zoom;
- int videoWidth, videoHeight;
+ int videoWidth, videoHeight, videoFormat;
+ android_dataspace videoDataSpace;
bool recordingHint;
bool videoStabilization;
- enum lightFxMode_t {
- LIGHTFX_NONE = 0,
- LIGHTFX_LOWLIGHT,
- LIGHTFX_HDR
- } lightFx;
-
CameraParameters2 params;
String8 paramsFlattened;
// These parameters are also part of the camera API-visible state, but not
// directly listed in Camera.Parameters
- bool storeMetadataInBuffers;
+ // One of ICamera::VIDEO_BUFFER_MODE_*
+ int32_t videoBufferMode;
bool playShutterSound;
bool enableFaceDetect;
@@ -307,7 +303,6 @@
static const char* flashModeEnumToString(flashMode_t flashMode);
static focusMode_t focusModeStringToEnum(const char *focusMode);
static const char* focusModeEnumToString(focusMode_t focusMode);
- static lightFxMode_t lightFxStringToEnum(const char *lightFxMode);
static status_t parseAreas(const char *areasCStr,
Vector<Area> *areas);
@@ -330,7 +325,7 @@
static const int kFpsToApiScale = 1000;
// Transform from (-1000,-1000)-(1000,1000) normalized coords from camera
- // API to HAL2 (0,0)-(activePixelArray.width/height) coordinates
+ // API to HAL3 (0,0)-(activePixelArray.width/height) coordinates
int normalizedXToArray(int x) const;
int normalizedYToArray(int y) const;
@@ -350,7 +345,7 @@
private:
// Convert from viewfinder crop-region relative array coordinates
- // to HAL2 sensor array coordinates
+ // to HAL3 sensor array coordinates
int cropXToArray(int x) const;
int cropYToArray(int y) const;
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index 66d7b00..211bdae 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -49,13 +49,7 @@
mPreviewRequestId(Camera2Client::kPreviewRequestIdStart),
mPreviewStreamId(NO_STREAM),
mRecordingRequestId(Camera2Client::kRecordingRequestIdStart),
- mRecordingStreamId(NO_STREAM),
- mRecordingFrameAvailable(false),
- mRecordingHeapCount(kDefaultRecordingHeapCount),
- mRecordingHeapFree(kDefaultRecordingHeapCount),
- mRecordingFormat(kDefaultRecordingFormat),
- mRecordingDataSpace(kDefaultRecordingDataSpace),
- mRecordingGrallocUsage(kDefaultRecordingGrallocUsage)
+ mRecordingStreamId(NO_STREAM)
{
}
@@ -78,11 +72,30 @@
return OK;
}
+status_t StreamingProcessor::setRecordingWindow(sp<Surface> window) {
+ ATRACE_CALL();
+ status_t res;
+
+ res = deleteRecordingStream();
+ if (res != OK) return res;
+
+ Mutex::Autolock m(mMutex);
+
+ mRecordingWindow = window;
+
+ return OK;
+}
+
bool StreamingProcessor::haveValidPreviewWindow() const {
Mutex::Autolock m(mMutex);
return mPreviewWindow != 0;
}
+bool StreamingProcessor::haveValidRecordingWindow() const {
+ Mutex::Autolock m(mMutex);
+ return mRecordingWindow != nullptr;
+}
+
status_t StreamingProcessor::updatePreviewRequest(const Parameters ¶ms) {
ATRACE_CALL();
status_t res;
@@ -244,86 +257,6 @@
return mPreviewStreamId;
}
-status_t StreamingProcessor::setRecordingBufferCount(size_t count) {
- ATRACE_CALL();
- // Make sure we can support this many buffer slots
- if (count > BufferQueue::NUM_BUFFER_SLOTS) {
- ALOGE("%s: Camera %d: Too many recording buffers requested: %zu, max %d",
- __FUNCTION__, mId, count, BufferQueue::NUM_BUFFER_SLOTS);
- return BAD_VALUE;
- }
-
- Mutex::Autolock m(mMutex);
-
- ALOGV("%s: Camera %d: New recording buffer count from encoder: %zu",
- __FUNCTION__, mId, count);
-
- // Need to re-size consumer and heap
- if (mRecordingHeapCount != count) {
- ALOGV("%s: Camera %d: Resetting recording heap and consumer",
- __FUNCTION__, mId);
-
- if (isStreamActive(mActiveStreamIds, mRecordingStreamId)) {
- ALOGE("%s: Camera %d: Setting recording buffer count when "
- "recording stream is already active!", __FUNCTION__,
- mId);
- return INVALID_OPERATION;
- }
-
- releaseAllRecordingFramesLocked();
-
- if (mRecordingHeap != 0) {
- mRecordingHeap.clear();
- }
- mRecordingHeapCount = count;
- mRecordingHeapFree = count;
-
- mRecordingConsumer.clear();
- }
-
- return OK;
-}
-
-status_t StreamingProcessor::setRecordingFormat(int format,
- android_dataspace dataSpace) {
- ATRACE_CALL();
-
- Mutex::Autolock m(mMutex);
-
- ALOGV("%s: Camera %d: New recording format/dataspace from encoder: %X, %X",
- __FUNCTION__, mId, format, dataSpace);
-
- mRecordingFormat = format;
- mRecordingDataSpace = dataSpace;
- int prevGrallocUsage = mRecordingGrallocUsage;
- if (mRecordingFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
- mRecordingGrallocUsage = GRALLOC_USAGE_HW_VIDEO_ENCODER;
- } else {
- mRecordingGrallocUsage = GRALLOC_USAGE_SW_READ_OFTEN;
- }
-
- ALOGV("%s: Camera %d: New recording gralloc usage: %08X", __FUNCTION__, mId,
- mRecordingGrallocUsage);
-
- if (prevGrallocUsage != mRecordingGrallocUsage) {
- ALOGV("%s: Camera %d: Resetting recording consumer for new usage",
- __FUNCTION__, mId);
-
- if (isStreamActive(mActiveStreamIds, mRecordingStreamId)) {
- ALOGE("%s: Camera %d: Changing recording format when "
- "recording stream is already active!", __FUNCTION__,
- mId);
- return INVALID_OPERATION;
- }
-
- releaseAllRecordingFramesLocked();
-
- mRecordingConsumer.clear();
- }
-
- return OK;
-}
-
status_t StreamingProcessor::updateRecordingRequest(const Parameters ¶ms) {
ATRACE_CALL();
status_t res;
@@ -395,11 +328,11 @@
return res;
}
- if (mRecordingConsumer == 0 ||
+ if (mRecordingWindow == nullptr ||
currentWidth != (uint32_t)params.videoWidth ||
currentHeight != (uint32_t)params.videoHeight ||
- currentFormat != (uint32_t)mRecordingFormat ||
- currentDataSpace != mRecordingDataSpace) {
+ currentFormat != (uint32_t)params.videoFormat ||
+ currentDataSpace != params.videoDataSpace) {
*needsUpdate = true;
}
*needsUpdate = false;
@@ -417,26 +350,6 @@
return INVALID_OPERATION;
}
- bool newConsumer = false;
- if (mRecordingConsumer == 0) {
- ALOGV("%s: Camera %d: Creating recording consumer with %zu + 1 "
- "consumer-side buffers", __FUNCTION__, mId, mRecordingHeapCount);
- // Create CPU buffer queue endpoint. We need one more buffer here so that we can
- // always acquire and free a buffer when the heap is full; otherwise the consumer
- // will have buffers in flight we'll never clear out.
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
- mRecordingConsumer = new BufferItemConsumer(consumer,
- mRecordingGrallocUsage,
- mRecordingHeapCount + 1);
- mRecordingConsumer->setFrameAvailableListener(this);
- mRecordingConsumer->setName(String8("Camera2-RecordingConsumer"));
- mRecordingWindow = new Surface(producer);
- newConsumer = true;
- // Allocate memory later, since we don't know buffer size until receipt
- }
-
if (mRecordingStreamId != NO_STREAM) {
// Check if stream parameters have to change
uint32_t currentWidth, currentHeight;
@@ -453,9 +366,8 @@
}
if (currentWidth != (uint32_t)params.videoWidth ||
currentHeight != (uint32_t)params.videoHeight ||
- currentFormat != (uint32_t)mRecordingFormat ||
- currentDataSpace != mRecordingDataSpace ||
- newConsumer) {
+ currentFormat != (uint32_t)params.videoFormat ||
+ currentDataSpace != params.videoDataSpace) {
// TODO: Should wait to be sure previous recording has finished
res = device->deleteStream(mRecordingStreamId);
@@ -475,10 +387,9 @@
}
if (mRecordingStreamId == NO_STREAM) {
- mRecordingFrameCount = 0;
res = device->createStream(mRecordingWindow,
params.videoWidth, params.videoHeight,
- mRecordingFormat, mRecordingDataSpace,
+ params.videoFormat, params.videoDataSpace,
CAMERA3_STREAM_ROTATION_0, &mRecordingStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for recording: "
@@ -542,20 +453,6 @@
Mutex::Autolock m(mMutex);
- // If a recording stream is being started up and no recording
- // stream is active yet, free up any outstanding buffers left
- // from the previous recording session. There should never be
- // any, so if there are, warn about it.
- bool isRecordingStreamIdle = !isStreamActive(mActiveStreamIds, mRecordingStreamId);
- bool startRecordingStream = isStreamActive(outputStreams, mRecordingStreamId);
- if (startRecordingStream && isRecordingStreamIdle) {
- releaseAllRecordingFramesLocked();
- }
-
- ALOGV("%s: Camera %d: %s started, recording heap has %zu free of %zu",
- __FUNCTION__, mId, (type == PREVIEW) ? "preview" : "recording",
- mRecordingHeapFree, mRecordingHeapCount);
-
CameraMetadata &request = (type == PREVIEW) ?
mPreviewRequest : mRecordingRequest;
@@ -692,272 +589,6 @@
return OK;
}
-void StreamingProcessor::onFrameAvailable(const BufferItem& /*item*/) {
- ATRACE_CALL();
- Mutex::Autolock l(mMutex);
- if (!mRecordingFrameAvailable) {
- mRecordingFrameAvailable = true;
- mRecordingFrameAvailableSignal.signal();
- }
-
-}
-
-bool StreamingProcessor::threadLoop() {
- status_t res;
-
- {
- Mutex::Autolock l(mMutex);
- while (!mRecordingFrameAvailable) {
- res = mRecordingFrameAvailableSignal.waitRelative(
- mMutex, kWaitDuration);
- if (res == TIMED_OUT) return true;
- }
- mRecordingFrameAvailable = false;
- }
-
- do {
- res = processRecordingFrame();
- } while (res == OK);
-
- return true;
-}
-
-status_t StreamingProcessor::processRecordingFrame() {
- ATRACE_CALL();
- status_t res;
- sp<Camera2Heap> recordingHeap;
- size_t heapIdx = 0;
- nsecs_t timestamp;
-
- sp<Camera2Client> client = mClient.promote();
- if (client == 0) {
- // Discard frames during shutdown
- BufferItem imgBuffer;
- res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0);
- if (res != OK) {
- if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
- ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- }
- return res;
- }
- mRecordingConsumer->releaseBuffer(imgBuffer);
- return OK;
- }
-
- {
- /* acquire SharedParameters before mMutex so we don't dead lock
- with Camera2Client code calling into StreamingProcessor */
- SharedParameters::Lock l(client->getParameters());
- Mutex::Autolock m(mMutex);
- BufferItem imgBuffer;
- res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0);
- if (res != OK) {
- if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
- ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- }
- return res;
- }
- timestamp = imgBuffer.mTimestamp;
-
- mRecordingFrameCount++;
- ALOGVV("OnRecordingFrame: Frame %d", mRecordingFrameCount);
-
- if (l.mParameters.state != Parameters::RECORD &&
- l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
- ALOGV("%s: Camera %d: Discarding recording image buffers "
- "received after recording done", __FUNCTION__,
- mId);
- mRecordingConsumer->releaseBuffer(imgBuffer);
- return INVALID_OPERATION;
- }
-
- if (mRecordingHeap == 0) {
- size_t payloadSize = sizeof(VideoNativeMetadata);
- ALOGV("%s: Camera %d: Creating recording heap with %zu buffers of "
- "size %zu bytes", __FUNCTION__, mId,
- mRecordingHeapCount, payloadSize);
-
- mRecordingHeap = new Camera2Heap(payloadSize, mRecordingHeapCount,
- "Camera2Client::RecordingHeap");
- if (mRecordingHeap->mHeap->getSize() == 0) {
- ALOGE("%s: Camera %d: Unable to allocate memory for recording",
- __FUNCTION__, mId);
- mRecordingConsumer->releaseBuffer(imgBuffer);
- return NO_MEMORY;
- }
- for (size_t i = 0; i < mRecordingBuffers.size(); i++) {
- if (mRecordingBuffers[i].mBuf !=
- BufferItemConsumer::INVALID_BUFFER_SLOT) {
- ALOGE("%s: Camera %d: Non-empty recording buffers list!",
- __FUNCTION__, mId);
- }
- }
- mRecordingBuffers.clear();
- mRecordingBuffers.setCapacity(mRecordingHeapCount);
- mRecordingBuffers.insertAt(0, mRecordingHeapCount);
-
- mRecordingHeapHead = 0;
- mRecordingHeapFree = mRecordingHeapCount;
- }
-
- if (mRecordingHeapFree == 0) {
- ALOGE("%s: Camera %d: No free recording buffers, dropping frame",
- __FUNCTION__, mId);
- mRecordingConsumer->releaseBuffer(imgBuffer);
- return NO_MEMORY;
- }
-
- heapIdx = mRecordingHeapHead;
- mRecordingHeapHead = (mRecordingHeapHead + 1) % mRecordingHeapCount;
- mRecordingHeapFree--;
-
- ALOGVV("%s: Camera %d: Timestamp %lld",
- __FUNCTION__, mId, timestamp);
-
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap =
- mRecordingHeap->mBuffers[heapIdx]->getMemory(&offset,
- &size);
-
- VideoNativeMetadata *payload = reinterpret_cast<VideoNativeMetadata*>(
- (uint8_t*)heap->getBase() + offset);
- payload->eType = kMetadataBufferTypeANWBuffer;
- payload->pBuffer = imgBuffer.mGraphicBuffer->getNativeBuffer();
- payload->nFenceFd = -1;
-
- ALOGVV("%s: Camera %d: Sending out ANWBuffer %p",
- __FUNCTION__, mId, payload->pBuffer);
-
- mRecordingBuffers.replaceAt(imgBuffer, heapIdx);
- recordingHeap = mRecordingHeap;
- }
-
- // Call outside locked parameters to allow re-entrancy from notification
- Camera2Client::SharedCameraCallbacks::Lock l(client->mSharedCameraCallbacks);
- if (l.mRemoteCallback != 0) {
- l.mRemoteCallback->dataCallbackTimestamp(timestamp,
- CAMERA_MSG_VIDEO_FRAME,
- recordingHeap->mBuffers[heapIdx]);
- } else {
- ALOGW("%s: Camera %d: Remote callback gone", __FUNCTION__, mId);
- }
-
- return OK;
-}
-
-void StreamingProcessor::releaseRecordingFrame(const sp<IMemory>& mem) {
- ATRACE_CALL();
- status_t res;
-
- Mutex::Autolock m(mMutex);
- // Make sure this is for the current heap
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- if (heap->getHeapID() != mRecordingHeap->mHeap->getHeapID()) {
- ALOGW("%s: Camera %d: Mismatched heap ID, ignoring release "
- "(got %x, expected %x)", __FUNCTION__, mId,
- heap->getHeapID(), mRecordingHeap->mHeap->getHeapID());
- return;
- }
-
- VideoNativeMetadata *payload = reinterpret_cast<VideoNativeMetadata*>(
- (uint8_t*)heap->getBase() + offset);
-
- if (payload->eType != kMetadataBufferTypeANWBuffer) {
- ALOGE("%s: Camera %d: Recording frame type invalid (got %x, expected %x)",
- __FUNCTION__, mId, payload->eType,
- kMetadataBufferTypeANWBuffer);
- return;
- }
-
- // Release the buffer back to the recording queue
- size_t itemIndex;
- for (itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) {
- const BufferItem item = mRecordingBuffers[itemIndex];
- if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT &&
- item.mGraphicBuffer->getNativeBuffer() == payload->pBuffer) {
- break;
- }
- }
-
- if (itemIndex == mRecordingBuffers.size()) {
- ALOGE("%s: Camera %d: Can't find returned ANW Buffer %p in list of "
- "outstanding buffers", __FUNCTION__, mId,
- payload->pBuffer);
- return;
- }
-
- ALOGVV("%s: Camera %d: Freeing returned ANW buffer %p index %d", __FUNCTION__,
- mId, payload->pBuffer, itemIndex);
-
- res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to free recording frame "
- "(Returned ANW buffer: %p): %s (%d)", __FUNCTION__,
- mId, payload->pBuffer, strerror(-res), res);
- return;
- }
- mRecordingBuffers.replaceAt(itemIndex);
-
- mRecordingHeapFree++;
- ALOGV_IF(mRecordingHeapFree == mRecordingHeapCount,
- "%s: Camera %d: All %d recording buffers returned",
- __FUNCTION__, mId, mRecordingHeapCount);
-}
-
-void StreamingProcessor::releaseAllRecordingFramesLocked() {
- ATRACE_CALL();
- status_t res;
-
- if (mRecordingConsumer == 0) {
- return;
- }
-
- ALOGV("%s: Camera %d: Releasing all recording buffers", __FUNCTION__,
- mId);
-
- size_t releasedCount = 0;
- for (size_t itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) {
- const BufferItem item = mRecordingBuffers[itemIndex];
- if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT) {
- res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to free recording frame "
- "(buffer_handle_t: %p): %s (%d)", __FUNCTION__,
- mId, item.mGraphicBuffer->handle, strerror(-res), res);
- }
- mRecordingBuffers.replaceAt(itemIndex);
- releasedCount++;
- }
- }
-
- if (releasedCount > 0) {
- ALOGW("%s: Camera %d: Force-freed %zu outstanding buffers "
- "from previous recording session", __FUNCTION__, mId, releasedCount);
- ALOGE_IF(releasedCount != mRecordingHeapCount - mRecordingHeapFree,
- "%s: Camera %d: Force-freed %zu buffers, but expected %zu",
- __FUNCTION__, mId, releasedCount, mRecordingHeapCount - mRecordingHeapFree);
- }
-
- mRecordingHeapHead = 0;
- mRecordingHeapFree = mRecordingHeapCount;
-}
-
-bool StreamingProcessor::isStreamActive(const Vector<int32_t> &streams,
- int32_t recordingStreamId) {
- for (size_t i = 0; i < streams.size(); i++) {
- if (streams[i] == recordingStreamId) {
- return true;
- }
- }
- return false;
-}
-
-
status_t StreamingProcessor::dump(int fd, const Vector<String16>& /*args*/) {
String8 result;
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
index e0cad3a..57e6389 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
@@ -31,30 +31,28 @@
namespace camera2 {
-class Parameters;
+struct Parameters;
class Camera2Heap;
/**
* Management and processing for preview and recording streams
*/
-class StreamingProcessor:
- public Thread, public BufferItemConsumer::FrameAvailableListener {
+class StreamingProcessor : public virtual VirtualLightRefBase {
public:
StreamingProcessor(sp<Camera2Client> client);
~StreamingProcessor();
status_t setPreviewWindow(sp<Surface> window);
+ status_t setRecordingWindow(sp<Surface> window);
bool haveValidPreviewWindow() const;
+ bool haveValidRecordingWindow() const;
status_t updatePreviewRequest(const Parameters ¶ms);
status_t updatePreviewStream(const Parameters ¶ms);
status_t deletePreviewStream();
int getPreviewStreamId() const;
- status_t setRecordingBufferCount(size_t count);
- status_t setRecordingFormat(int format, android_dataspace_t dataspace);
-
status_t updateRecordingRequest(const Parameters ¶ms);
// If needsUpdate is set to true, a updateRecordingStream call with params will recreate
// recording stream
@@ -81,11 +79,6 @@
status_t getActiveRequestId() const;
status_t incrementStreamingIds();
- // Callback for new recording frames from HAL
- virtual void onFrameAvailable(const BufferItem& item);
- // Callback from stagefright which returns used recording frames
- void releaseRecordingFrame(const sp<IMemory>& mem);
-
status_t dump(int fd, const Vector<String16>& args);
private:
@@ -110,47 +103,10 @@
CameraMetadata mPreviewRequest;
sp<Surface> mPreviewWindow;
- // Recording-related members
- static const nsecs_t kWaitDuration = 50000000; // 50 ms
-
int32_t mRecordingRequestId;
int mRecordingStreamId;
- int mRecordingFrameCount;
- sp<BufferItemConsumer> mRecordingConsumer;
sp<Surface> mRecordingWindow;
CameraMetadata mRecordingRequest;
- sp<camera2::Camera2Heap> mRecordingHeap;
-
- bool mRecordingFrameAvailable;
- Condition mRecordingFrameAvailableSignal;
-
- static const size_t kDefaultRecordingHeapCount = 8;
- size_t mRecordingHeapCount;
- Vector<BufferItem> mRecordingBuffers;
- size_t mRecordingHeapHead, mRecordingHeapFree;
-
- static const int kDefaultRecordingFormat =
- HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
- int mRecordingFormat;
-
- static const android_dataspace kDefaultRecordingDataSpace =
- HAL_DATASPACE_BT709;
- android_dataspace mRecordingDataSpace;
-
- static const int kDefaultRecordingGrallocUsage =
- GRALLOC_USAGE_HW_VIDEO_ENCODER;
- int mRecordingGrallocUsage;
-
- virtual bool threadLoop();
-
- status_t processRecordingFrame();
-
- // Unilaterally free any buffers still outstanding to stagefright
- void releaseAllRecordingFramesLocked();
-
- // Determine if the specified stream is currently in use
- static bool isStreamActive(const Vector<int32_t> &streams,
- int32_t recordingStreamId);
};
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 0b79b31..b127472 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
#ifdef LOG_NNDEBUG
#define ALOGVV(...) ALOGV(__VA_ARGS__)
#else
-#define ALOGVV(...) ((void)0)
+#define ALOGVV(...) if (0) ALOGV(__VA_ARGS__)
#endif
#include <inttypes.h>
@@ -35,6 +35,7 @@
#include "api1/Camera2Client.h"
#include "api1/client2/CaptureSequencer.h"
#include "api1/client2/ZslProcessor.h"
+#include "device3/Camera3Device.h"
namespace android {
namespace camera2 {
@@ -43,35 +44,55 @@
sp<Camera2Client> client,
wp<CaptureSequencer> sequencer):
Thread(false),
+ mLatestClearedBufferTimestamp(0),
mState(RUNNING),
mClient(client),
- mDevice(client->getCameraDevice()),
mSequencer(sequencer),
mId(client->getCameraId()),
- mDeleted(false),
- mZslBufferAvailable(false),
mZslStreamId(NO_STREAM),
- mZslReprocessStreamId(NO_STREAM),
mFrameListHead(0),
- mZslQueueHead(0),
- mZslQueueTail(0) {
- mZslQueue.insertAt(0, kZslBufferDepth);
- mFrameList.insertAt(0, kFrameListDepth);
+ mHasFocuser(false) {
+ // Initialize buffer queue and frame list based on pipeline max depth.
+ size_t pipelineMaxDepth = kDefaultMaxPipelineDepth;
+ if (client != 0) {
+ sp<Camera3Device> device =
+ static_cast<Camera3Device*>(client->getCameraDevice().get());
+ if (device != 0) {
+ camera_metadata_ro_entry_t entry =
+ device->info().find(ANDROID_REQUEST_PIPELINE_MAX_DEPTH);
+ if (entry.count == 1) {
+ pipelineMaxDepth = entry.data.u8[0];
+ } else {
+ ALOGW("%s: Unable to find the android.request.pipelineMaxDepth,"
+ " use default pipeline max depth %d", __FUNCTION__,
+ kDefaultMaxPipelineDepth);
+ }
+
+ entry = device->info().find(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE);
+ if (entry.count > 0 && entry.data.f[0] != 0.) {
+ mHasFocuser = true;
+ }
+ }
+ }
+
+ ALOGV("%s: Initialize buffer queue and frame list depth based on max pipeline depth (%zu)",
+ __FUNCTION__, pipelineMaxDepth);
+ // Need to keep buffer queue longer than metadata queue because sometimes buffer arrives
+ // earlier than metadata which causes the buffer corresponding to oldest metadata being
+ // removed.
+ mFrameListDepth = pipelineMaxDepth;
+ mBufferQueueDepth = mFrameListDepth + 1;
+
+
+ mZslQueue.insertAt(0, mBufferQueueDepth);
+ mFrameList.insertAt(0, mFrameListDepth);
sp<CaptureSequencer> captureSequencer = mSequencer.promote();
if (captureSequencer != 0) captureSequencer->setZslProcessor(this);
}
ZslProcessor::~ZslProcessor() {
ALOGV("%s: Exit", __FUNCTION__);
- disconnect();
-}
-
-void ZslProcessor::onFrameAvailable(const BufferItem& /*item*/) {
- Mutex::Autolock l(mInputMutex);
- if (!mZslBufferAvailable) {
- mZslBufferAvailable = true;
- mZslBufferAvailableSignal.signal();
- }
+ deleteStream();
}
void ZslProcessor::onResultAvailable(const CaptureResult &result) {
@@ -81,35 +102,27 @@
camera_metadata_ro_entry_t entry;
entry = result.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
nsecs_t timestamp = entry.data.i64[0];
- (void)timestamp;
- ALOGVV("Got preview frame for timestamp %" PRId64, timestamp);
+ if (entry.count == 0) {
+ ALOGE("%s: metadata doesn't have timestamp, skip this result", __FUNCTION__);
+ return;
+ }
+
+ entry = result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT);
+ if (entry.count == 0) {
+ ALOGE("%s: metadata doesn't have frame number, skip this result", __FUNCTION__);
+ return;
+ }
+ int32_t frameNumber = entry.data.i32[0];
+
+ ALOGVV("Got preview metadata for frame %d with timestamp %" PRId64, frameNumber, timestamp);
if (mState != RUNNING) return;
+ // Corresponding buffer has been cleared. No need to push into mFrameList
+ if (timestamp <= mLatestClearedBufferTimestamp) return;
+
mFrameList.editItemAt(mFrameListHead) = result.mMetadata;
- mFrameListHead = (mFrameListHead + 1) % kFrameListDepth;
-
- findMatchesLocked();
-}
-
-void ZslProcessor::onBufferReleased(buffer_handle_t *handle) {
- Mutex::Autolock l(mInputMutex);
-
- // Verify that the buffer is in our queue
- size_t i = 0;
- for (; i < mZslQueue.size(); i++) {
- if (&(mZslQueue[i].buffer.mGraphicBuffer->handle) == handle) break;
- }
- if (i == mZslQueue.size()) {
- ALOGW("%s: Released buffer %p not found in queue",
- __FUNCTION__, handle);
- }
-
- // Erase entire ZSL queue since we've now completed the capture and preview
- // is stopped.
- clearZslQueueLocked();
-
- mState = RUNNING;
+ mFrameListHead = (mFrameListHead + 1) % mFrameListDepth;
}
status_t ZslProcessor::updateStream(const Parameters ¶ms) {
@@ -124,25 +137,13 @@
ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
return INVALID_OPERATION;
}
- sp<CameraDeviceBase> device = mDevice.promote();
+ sp<Camera3Device> device =
+ static_cast<Camera3Device*>(client->getCameraDevice().get());
if (device == 0) {
ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
return INVALID_OPERATION;
}
- if (mZslConsumer == 0) {
- // Create CPU buffer queue endpoint
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
- mZslConsumer = new BufferItemConsumer(consumer,
- GRALLOC_USAGE_HW_CAMERA_ZSL,
- kZslBufferDepth);
- mZslConsumer->setFrameAvailableListener(this);
- mZslConsumer->setName(String8("Camera2-ZslConsumer"));
- mZslWindow = new Surface(producer);
- }
-
if (mZslStreamId != NO_STREAM) {
// Check if stream parameters have to change
uint32_t currentWidth, currentHeight;
@@ -151,57 +152,50 @@
if (res != OK) {
ALOGE("%s: Camera %d: Error querying capture output stream info: "
"%s (%d)", __FUNCTION__,
- mId, strerror(-res), res);
+ client->getCameraId(), strerror(-res), res);
return res;
}
if (currentWidth != (uint32_t)params.fastInfo.arrayWidth ||
currentHeight != (uint32_t)params.fastInfo.arrayHeight) {
- res = device->deleteReprocessStream(mZslReprocessStreamId);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to delete old reprocess stream "
- "for ZSL: %s (%d)", __FUNCTION__,
- mId, strerror(-res), res);
- return res;
- }
- ALOGV("%s: Camera %d: Deleting stream %d since the buffer dimensions changed",
- __FUNCTION__, mId, mZslStreamId);
+ ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
+ "dimensions changed",
+ __FUNCTION__, client->getCameraId(), mZslStreamId);
res = device->deleteStream(mZslStreamId);
- if (res != OK) {
+ if (res == -EBUSY) {
+ ALOGV("%s: Camera %d: Device is busy, call updateStream again "
+ " after it becomes idle", __FUNCTION__, mId);
+ return res;
+ } else if(res != OK) {
ALOGE("%s: Camera %d: Unable to delete old output stream "
"for ZSL: %s (%d)", __FUNCTION__,
- mId, strerror(-res), res);
+ client->getCameraId(), strerror(-res), res);
return res;
}
mZslStreamId = NO_STREAM;
}
}
- mDeleted = false;
-
if (mZslStreamId == NO_STREAM) {
// Create stream for HAL production
// TODO: Sort out better way to select resolution for ZSL
- int streamType = params.quirks.useZslFormat ?
- (int)CAMERA2_HAL_PIXEL_FORMAT_ZSL :
- (int)HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
- res = device->createStream(mZslWindow,
- params.fastInfo.arrayWidth, params.fastInfo.arrayHeight, streamType,
- HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0, &mZslStreamId);
+
+ // Note that format specified internally in Camera3ZslStream
+ res = device->createZslStream(
+ params.fastInfo.arrayWidth, params.fastInfo.arrayHeight,
+ mBufferQueueDepth,
+ &mZslStreamId,
+ &mZslStream);
if (res != OK) {
- ALOGE("%s: Camera %d: Can't create output stream for ZSL: "
- "%s (%d)", __FUNCTION__, mId,
+ ALOGE("%s: Camera %d: Can't create ZSL stream: "
+ "%s (%d)", __FUNCTION__, client->getCameraId(),
strerror(-res), res);
return res;
}
- res = device->createReprocessStreamFromStream(mZslStreamId,
- &mZslReprocessStreamId);
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't create reprocess stream for ZSL: "
- "%s (%d)", __FUNCTION__, mId,
- strerror(-res), res);
- return res;
- }
+
+ // Only add the camera3 buffer listener when the stream is created.
+ mZslStream->addBufferListener(this);
}
+
client->registerFrameListener(Camera2Client::kPreviewRequestIdStart,
Camera2Client::kPreviewRequestIdEnd,
this,
@@ -212,47 +206,32 @@
status_t ZslProcessor::deleteStream() {
ATRACE_CALL();
- Mutex::Autolock l(mInputMutex);
- // WAR(b/15408128): do not delete stream unless client is being disconnected.
- mDeleted = true;
- return OK;
-}
-
-status_t ZslProcessor::disconnect() {
- ATRACE_CALL();
status_t res;
Mutex::Autolock l(mInputMutex);
if (mZslStreamId != NO_STREAM) {
- sp<CameraDeviceBase> device = mDevice.promote();
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) {
+ ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
+ return INVALID_OPERATION;
+ }
+
+ sp<Camera3Device> device =
+ reinterpret_cast<Camera3Device*>(client->getCameraDevice().get());
if (device == 0) {
ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
return INVALID_OPERATION;
}
- clearZslQueueLocked();
-
- res = device->deleteReprocessStream(mZslReprocessStreamId);
- if (res != OK) {
- ALOGE("%s: Camera %d: Cannot delete ZSL reprocessing stream %d: "
- "%s (%d)", __FUNCTION__, mId,
- mZslReprocessStreamId, strerror(-res), res);
- return res;
- }
-
- mZslReprocessStreamId = NO_STREAM;
res = device->deleteStream(mZslStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Cannot delete ZSL output stream %d: "
- "%s (%d)", __FUNCTION__, mId,
+ "%s (%d)", __FUNCTION__, client->getCameraId(),
mZslStreamId, strerror(-res), res);
return res;
}
- mZslWindow.clear();
- mZslConsumer.clear();
-
mZslStreamId = NO_STREAM;
}
return OK;
@@ -263,6 +242,46 @@
return mZslStreamId;
}
+status_t ZslProcessor::updateRequestWithDefaultStillRequest(CameraMetadata &request) const {
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) {
+ ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
+ return INVALID_OPERATION;
+ }
+ sp<Camera3Device> device =
+ static_cast<Camera3Device*>(client->getCameraDevice().get());
+ if (device == 0) {
+ ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+ return INVALID_OPERATION;
+ }
+
+ CameraMetadata stillTemplate;
+ device->createDefaultRequest(CAMERA3_TEMPLATE_STILL_CAPTURE, &stillTemplate);
+
+ // Find some of the post-processing tags, and assign the value from template to the request.
+ // Only check the aberration mode and noise reduction mode for now, as they are very important
+ // for image quality.
+ uint32_t postProcessingTags[] = {
+ ANDROID_NOISE_REDUCTION_MODE,
+ ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+ ANDROID_COLOR_CORRECTION_MODE,
+ ANDROID_TONEMAP_MODE,
+ ANDROID_SHADING_MODE,
+ ANDROID_HOT_PIXEL_MODE,
+ ANDROID_EDGE_MODE
+ };
+
+ camera_metadata_entry_t entry;
+ for (size_t i = 0; i < sizeof(postProcessingTags) / sizeof(uint32_t); i++) {
+ entry = stillTemplate.find(postProcessingTags[i]);
+ if (entry.count > 0) {
+ request.update(postProcessingTags[i], entry.data.u8, 1);
+ }
+ }
+
+ return OK;
+}
+
status_t ZslProcessor::pushToReprocess(int32_t requestId) {
ALOGV("%s: Send in reprocess request with id %d",
__FUNCTION__, requestId);
@@ -279,21 +298,30 @@
dumpZslQueue(-1);
}
- if (mZslQueueTail != mZslQueueHead) {
- CameraMetadata request;
- size_t index = mZslQueueTail;
- while (index != mZslQueueHead) {
- if (!mZslQueue[index].frame.isEmpty()) {
- request = mZslQueue[index].frame;
- break;
- }
- index = (index + 1) % kZslBufferDepth;
- }
- if (index == mZslQueueHead) {
- ALOGV("%s: ZSL queue has no valid frames to send yet.",
- __FUNCTION__);
- return NOT_ENOUGH_DATA;
- }
+ size_t metadataIdx;
+ nsecs_t candidateTimestamp = getCandidateTimestampLocked(&metadataIdx);
+
+ if (candidateTimestamp == -1) {
+ ALOGE("%s: Could not find good candidate for ZSL reprocessing",
+ __FUNCTION__);
+ return NOT_ENOUGH_DATA;
+ }
+
+ res = mZslStream->enqueueInputBufferByTimestamp(candidateTimestamp,
+ /*actualTimestamp*/NULL);
+
+ if (res == mZslStream->NO_BUFFER_AVAILABLE) {
+ ALOGV("%s: No ZSL buffers yet", __FUNCTION__);
+ return NOT_ENOUGH_DATA;
+ } else if (res != OK) {
+ ALOGE("%s: Unable to push buffer for reprocessing: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ {
+ CameraMetadata request = mFrameList[metadataIdx];
+
// Verify that the frame is reasonable for reprocessing
camera_metadata_entry_t entry;
@@ -310,25 +338,51 @@
return NOT_ENOUGH_DATA;
}
- buffer_handle_t *handle =
- &(mZslQueue[index].buffer.mGraphicBuffer->handle);
-
uint8_t requestType = ANDROID_REQUEST_TYPE_REPROCESS;
res = request.update(ANDROID_REQUEST_TYPE,
&requestType, 1);
+ if (res != OK) {
+ ALOGE("%s: Unable to update request type",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
int32_t inputStreams[1] =
- { mZslReprocessStreamId };
- if (res == OK) request.update(ANDROID_REQUEST_INPUT_STREAMS,
+ { mZslStreamId };
+ res = request.update(ANDROID_REQUEST_INPUT_STREAMS,
inputStreams, 1);
+ if (res != OK) {
+ ALOGE("%s: Unable to update request input streams",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ uint8_t captureIntent =
+ static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
+ res = request.update(ANDROID_CONTROL_CAPTURE_INTENT,
+ &captureIntent, 1);
+ if (res != OK ) {
+ ALOGE("%s: Unable to update request capture intent",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ // TODO: Shouldn't we also update the latest preview frame?
int32_t outputStreams[1] =
{ client->getCaptureStreamId() };
- if (res == OK) request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
+ res = request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
outputStreams, 1);
+ if (res != OK) {
+ ALOGE("%s: Unable to update request output streams",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
res = request.update(ANDROID_REQUEST_ID,
&requestId, 1);
-
if (res != OK ) {
- ALOGE("%s: Unable to update frame to a reprocess request", __FUNCTION__);
+ ALOGE("%s: Unable to update frame to a reprocess request",
+ __FUNCTION__);
return INVALID_OPERATION;
}
@@ -336,17 +390,9 @@
if (res != OK) {
ALOGE("%s: Camera %d: Unable to stop preview for ZSL capture: "
"%s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
+ __FUNCTION__, client->getCameraId(), strerror(-res), res);
return INVALID_OPERATION;
}
- // TODO: have push-and-clear be atomic
- res = client->getCameraDevice()->pushReprocessBuffer(mZslReprocessStreamId,
- handle, this);
- if (res != OK) {
- ALOGE("%s: Unable to push buffer for reprocessing: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
// Update JPEG settings
{
@@ -355,25 +401,30 @@
if (res != OK) {
ALOGE("%s: Camera %d: Unable to update JPEG entries of ZSL "
"capture request: %s (%d)", __FUNCTION__,
- mId,
+ client->getCameraId(),
strerror(-res), res);
return res;
}
}
+ // Update post-processing settings
+ res = updateRequestWithDefaultStillRequest(request);
+ if (res != OK) {
+ ALOGW("%s: Unable to update post-processing tags, the reprocessed image quality "
+ "may be compromised", __FUNCTION__);
+ }
+
mLatestCapturedRequest = request;
res = client->getCameraDevice()->capture(request);
if (res != OK ) {
- ALOGE("%s: Unable to send ZSL reprocess request to capture: %s (%d)",
- __FUNCTION__, strerror(-res), res);
+ ALOGE("%s: Unable to send ZSL reprocess request to capture: %s"
+ " (%d)", __FUNCTION__, strerror(-res), res);
return res;
}
mState = LOCKED;
- } else {
- ALOGV("%s: No ZSL buffers yet", __FUNCTION__);
- return NOT_ENOUGH_DATA;
}
+
return OK;
}
@@ -386,17 +437,20 @@
}
status_t ZslProcessor::clearZslQueueLocked() {
- for (size_t i = 0; i < mZslQueue.size(); i++) {
- if (mZslQueue[i].buffer.mTimestamp != 0) {
- mZslConsumer->releaseBuffer(mZslQueue[i].buffer);
- }
- mZslQueue.replaceAt(i);
+ if (mZslStream != 0) {
+ // clear result metadata list first.
+ clearZslResultQueueLocked();
+ return mZslStream->clearInputRingBuffer(&mLatestClearedBufferTimestamp);
}
- mZslQueueHead = 0;
- mZslQueueTail = 0;
return OK;
}
+void ZslProcessor::clearZslResultQueueLocked() {
+ mFrameList.clear();
+ mFrameListHead = 0;
+ mFrameList.insertAt(0, mFrameListDepth);
+}
+
void ZslProcessor::dump(int fd, const Vector<String16>& /*args*/) const {
Mutex::Autolock l(mInputMutex);
if (!mLatestCapturedRequest.isEmpty()) {
@@ -411,128 +465,9 @@
}
bool ZslProcessor::threadLoop() {
- status_t res;
-
- {
- Mutex::Autolock l(mInputMutex);
- while (!mZslBufferAvailable) {
- res = mZslBufferAvailableSignal.waitRelative(mInputMutex,
- kWaitDuration);
- if (res == TIMED_OUT) return true;
- }
- mZslBufferAvailable = false;
- }
-
- do {
- res = processNewZslBuffer();
- } while (res == OK);
-
- return true;
-}
-
-status_t ZslProcessor::processNewZslBuffer() {
- ATRACE_CALL();
- status_t res;
- sp<BufferItemConsumer> zslConsumer;
- {
- Mutex::Autolock l(mInputMutex);
- if (mZslConsumer == 0) return OK;
- zslConsumer = mZslConsumer;
- }
- ALOGVV("Trying to get next buffer");
- BufferItem item;
- res = zslConsumer->acquireBuffer(&item, 0);
- if (res != OK) {
- if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
- ALOGE("%s: Camera %d: Error receiving ZSL image buffer: "
- "%s (%d)", __FUNCTION__,
- mId, strerror(-res), res);
- } else {
- ALOGVV(" No buffer");
- }
- return res;
- }
-
- Mutex::Autolock l(mInputMutex);
-
- if (mState == LOCKED) {
- ALOGVV("In capture, discarding new ZSL buffers");
- zslConsumer->releaseBuffer(item);
- return OK;
- }
-
- ALOGVV("Got ZSL buffer: head: %d, tail: %d", mZslQueueHead, mZslQueueTail);
-
- if ( (mZslQueueHead + 1) % kZslBufferDepth == mZslQueueTail) {
- ALOGVV("Releasing oldest buffer");
- zslConsumer->releaseBuffer(mZslQueue[mZslQueueTail].buffer);
- mZslQueue.replaceAt(mZslQueueTail);
- mZslQueueTail = (mZslQueueTail + 1) % kZslBufferDepth;
- }
-
- ZslPair &queueHead = mZslQueue.editItemAt(mZslQueueHead);
-
- queueHead.buffer = item;
- queueHead.frame.release();
-
- mZslQueueHead = (mZslQueueHead + 1) % kZslBufferDepth;
-
- ALOGVV(" Acquired buffer, timestamp %" PRId64, queueHead.buffer.mTimestamp);
-
- findMatchesLocked();
-
- return OK;
-}
-
-void ZslProcessor::findMatchesLocked() {
- ALOGVV("Scanning");
- for (size_t i = 0; i < mZslQueue.size(); i++) {
- ZslPair &queueEntry = mZslQueue.editItemAt(i);
- nsecs_t bufferTimestamp = queueEntry.buffer.mTimestamp;
- IF_ALOGV() {
- camera_metadata_entry_t entry;
- nsecs_t frameTimestamp = 0;
- if (!queueEntry.frame.isEmpty()) {
- entry = queueEntry.frame.find(ANDROID_SENSOR_TIMESTAMP);
- frameTimestamp = entry.data.i64[0];
- }
- ALOGVV(" %d: b: %" PRId64 "\tf: %" PRId64, i,
- bufferTimestamp, frameTimestamp );
- }
- if (queueEntry.frame.isEmpty() && bufferTimestamp != 0) {
- // Have buffer, no matching frame. Look for one
- for (size_t j = 0; j < mFrameList.size(); j++) {
- bool match = false;
- CameraMetadata &frame = mFrameList.editItemAt(j);
- if (!frame.isEmpty()) {
- camera_metadata_entry_t entry;
- entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
- if (entry.count == 0) {
- ALOGE("%s: Can't find timestamp in frame!",
- __FUNCTION__);
- continue;
- }
- nsecs_t frameTimestamp = entry.data.i64[0];
- if (bufferTimestamp == frameTimestamp) {
- ALOGVV("%s: Found match %" PRId64, __FUNCTION__,
- frameTimestamp);
- match = true;
- } else {
- int64_t delta = abs(bufferTimestamp - frameTimestamp);
- if ( delta < 1000000) {
- ALOGVV("%s: Found close match %" PRId64 " (delta %" PRId64 ")",
- __FUNCTION__, bufferTimestamp, delta);
- match = true;
- }
- }
- }
- if (match) {
- queueEntry.frame.acquire(frame);
- break;
- }
- }
- }
- }
+ // TODO: remove dependency on thread. For now, shut thread down right
+ // away.
+ return false;
}
void ZslProcessor::dumpZslQueue(int fd) const {
@@ -567,5 +502,174 @@
}
}
+bool ZslProcessor::isFixedFocusMode(uint8_t afMode) const {
+ switch (afMode) {
+ case ANDROID_CONTROL_AF_MODE_AUTO:
+ case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
+ case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
+ case ANDROID_CONTROL_AF_MODE_MACRO:
+ return false;
+ break;
+ case ANDROID_CONTROL_AF_MODE_OFF:
+ case ANDROID_CONTROL_AF_MODE_EDOF:
+ return true;
+ default:
+ ALOGE("%s: unknown focus mode %d", __FUNCTION__, afMode);
+ return false;
+ }
+}
+
+nsecs_t ZslProcessor::getCandidateTimestampLocked(size_t* metadataIdx) const {
+ /**
+ * Find the smallest timestamp we know about so far
+ * - ensure that aeState is either converged or locked
+ */
+
+ size_t idx = 0;
+ nsecs_t minTimestamp = -1;
+
+ size_t emptyCount = mFrameList.size();
+
+ for (size_t j = 0; j < mFrameList.size(); j++) {
+ const CameraMetadata &frame = mFrameList[j];
+ if (!frame.isEmpty()) {
+
+ emptyCount--;
+
+ camera_metadata_ro_entry_t entry;
+ entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
+ if (entry.count == 0) {
+ ALOGE("%s: Can't find timestamp in frame!",
+ __FUNCTION__);
+ continue;
+ }
+ nsecs_t frameTimestamp = entry.data.i64[0];
+ if (minTimestamp > frameTimestamp || minTimestamp == -1) {
+
+ entry = frame.find(ANDROID_CONTROL_AE_STATE);
+
+ if (entry.count == 0) {
+ /**
+ * This is most likely a HAL bug. The aeState field is
+ * mandatory, so it should always be in a metadata packet.
+ */
+ ALOGW("%s: ZSL queue frame has no AE state field!",
+ __FUNCTION__);
+ continue;
+ }
+ if (entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_CONVERGED &&
+ entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_LOCKED) {
+ ALOGVV("%s: ZSL queue frame AE state is %d, need "
+ "full capture", __FUNCTION__, entry.data.u8[0]);
+ continue;
+ }
+
+ entry = frame.find(ANDROID_CONTROL_AF_MODE);
+ if (entry.count == 0) {
+ ALOGW("%s: ZSL queue frame has no AF mode field!",
+ __FUNCTION__);
+ continue;
+ }
+ uint8_t afMode = entry.data.u8[0];
+ if (afMode == ANDROID_CONTROL_AF_MODE_OFF) {
+ // Skip all the ZSL buffer for manual AF mode, as we don't really
+ // know the af state.
+ continue;
+ }
+
+ // Check AF state if device has focuser and focus mode isn't fixed
+ if (mHasFocuser && !isFixedFocusMode(afMode)) {
+ // Make sure the candidate frame has good focus.
+ entry = frame.find(ANDROID_CONTROL_AF_STATE);
+ if (entry.count == 0) {
+ ALOGW("%s: ZSL queue frame has no AF state field!",
+ __FUNCTION__);
+ continue;
+ }
+ uint8_t afState = entry.data.u8[0];
+ if (afState != ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED &&
+ afState != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED &&
+ afState != ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
+ ALOGVV("%s: ZSL queue frame AF state is %d is not good for capture, skip it",
+ __FUNCTION__, afState);
+ continue;
+ }
+ }
+
+ minTimestamp = frameTimestamp;
+ idx = j;
+ }
+
+ ALOGVV("%s: Saw timestamp %" PRId64, __FUNCTION__, frameTimestamp);
+ }
+ }
+
+ if (emptyCount == mFrameList.size()) {
+ /**
+ * This could be mildly bad and means our ZSL was triggered before
+ * there were any frames yet received by the camera framework.
+ *
+ * This is a fairly corner case which can happen under:
+ * + a user presses the shutter button real fast when the camera starts
+ * (startPreview followed immediately by takePicture).
+ * + burst capture case (hitting shutter button as fast possible)
+ *
+ * If this happens in steady case (preview running for a while, call
+ * a single takePicture) then this might be a fwk bug.
+ */
+ ALOGW("%s: ZSL queue has no metadata frames", __FUNCTION__);
+ }
+
+ ALOGV("%s: Candidate timestamp %" PRId64 " (idx %zu), empty frames: %zu",
+ __FUNCTION__, minTimestamp, idx, emptyCount);
+
+ if (metadataIdx) {
+ *metadataIdx = idx;
+ }
+
+ return minTimestamp;
+}
+
+void ZslProcessor::onBufferAcquired(const BufferInfo& /*bufferInfo*/) {
+ // Intentionally left empty
+ // Although theoretically we could use this to get better dump info
+}
+
+void ZslProcessor::onBufferReleased(const BufferInfo& bufferInfo) {
+
+ // ignore output buffers
+ if (bufferInfo.mOutput) {
+ return;
+ }
+
+ // Lock mutex only once we know this is an input buffer returned to avoid
+ // potential deadlock
+ Mutex::Autolock l(mInputMutex);
+ // TODO: Verify that the buffer is in our queue by looking at timestamp
+ // theoretically unnecessary unless we change the following assumptions:
+ // -- only 1 buffer reprocessed at a time (which is the case now)
+
+ // Erase entire ZSL queue since we've now completed the capture and preview
+ // is stopped.
+ //
+ // We need to guarantee that if we do two back-to-back captures,
+ // the second won't use a buffer that's older/the same as the first, which
+ // is theoretically possible if we don't clear out the queue and the
+ // selection criteria is something like 'newest'. Clearing out the result
+ // metadata queue on a completed capture ensures we'll only use new timestamp.
+ // Calling clearZslQueueLocked is a guaranteed deadlock because this callback
+ // holds the Camera3Stream internal lock (mLock), and clearZslQueueLocked requires
+ // to hold the same lock.
+ // TODO: need figure out a way to clear the Zsl buffer queue properly. Right now
+ // it is safe not to do so, as back to back ZSL capture requires stop and start
+ // preview, which will flush ZSL queue automatically.
+ ALOGV("%s: Memory optimization, clearing ZSL queue",
+ __FUNCTION__);
+ clearZslResultQueueLocked();
+
+ // Required so we accept more ZSL requests
+ mState = RUNNING;
+}
+
}; // namespace camera2
}; // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.h b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
index 5870bd3..86c06c6 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,11 +25,9 @@
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
#include <camera/CameraMetadata.h>
-#include <camera/CaptureResult.h>
-#include "common/CameraDeviceBase.h"
-#include "api1/client2/ZslProcessorInterface.h"
#include "api1/client2/FrameProcessor.h"
+#include "device3/Camera3ZslStream.h"
namespace android {
@@ -38,45 +36,66 @@
namespace camera2 {
class CaptureSequencer;
-class Parameters;
+struct Parameters;
/***
- * ZSL queue processing
+ * ZSL queue processing for HALv3.0 or newer
*/
-class ZslProcessor:
+class ZslProcessor :
+ public camera3::Camera3StreamBufferListener,
virtual public Thread,
- virtual public BufferItemConsumer::FrameAvailableListener,
- virtual public FrameProcessor::FilteredListener,
- virtual public CameraDeviceBase::BufferReleasedListener,
- public ZslProcessorInterface {
+ virtual public FrameProcessor::FilteredListener {
public:
ZslProcessor(sp<Camera2Client> client, wp<CaptureSequencer> sequencer);
~ZslProcessor();
- // From mZslConsumer
- virtual void onFrameAvailable(const BufferItem& item);
- // From FrameProcessor
+ // From FrameProcessor::FilteredListener
virtual void onResultAvailable(const CaptureResult &result);
- virtual void onBufferReleased(buffer_handle_t *handle);
-
/**
****************************************
* ZslProcessorInterface implementation *
****************************************
*/
+ // Update the streams by recreating them if the size/format has changed
status_t updateStream(const Parameters ¶ms);
+
+ // Delete the underlying CameraDevice streams
status_t deleteStream();
- status_t disconnect();
+
+ // Get ID for use with android.request.outputStreams / inputStreams
int getStreamId() const;
+ /**
+ * Submits a ZSL capture request (id = requestId)
+ *
+ * An appropriate ZSL buffer is selected by the closest timestamp,
+ * then we push that buffer to be reprocessed by the HAL.
+ * A capture request is created and submitted on behalf of the client.
+ */
status_t pushToReprocess(int32_t requestId);
+
+ // Flush the ZSL buffer queue, freeing up all the buffers
status_t clearZslQueue();
void dump(int fd, const Vector<String16>& args) const;
+
+ protected:
+ /**
+ **********************************************
+ * Camera3StreamBufferListener implementation *
+ **********************************************
+ */
+ typedef camera3::Camera3StreamBufferListener::BufferInfo BufferInfo;
+ // Buffer was acquired by the HAL
+ virtual void onBufferAcquired(const BufferInfo& bufferInfo);
+ // Buffer was released by the HAL
+ virtual void onBufferReleased(const BufferInfo& bufferInfo);
+
private:
static const nsecs_t kWaitDuration = 10000000; // 10 ms
+ nsecs_t mLatestClearedBufferTimestamp;
enum {
RUNNING,
@@ -84,53 +103,52 @@
} mState;
wp<Camera2Client> mClient;
- wp<CameraDeviceBase> mDevice;
wp<CaptureSequencer> mSequencer;
- int mId;
- bool mDeleted;
+ const int mId;
mutable Mutex mInputMutex;
- bool mZslBufferAvailable;
- Condition mZslBufferAvailableSignal;
enum {
NO_STREAM = -1
};
int mZslStreamId;
- int mZslReprocessStreamId;
- sp<BufferItemConsumer> mZslConsumer;
- sp<Surface> mZslWindow;
+ sp<camera3::Camera3ZslStream> mZslStream;
struct ZslPair {
BufferItem buffer;
CameraMetadata frame;
};
- static const size_t kZslBufferDepth = 4;
- static const size_t kFrameListDepth = kZslBufferDepth * 2;
+ static const int32_t kDefaultMaxPipelineDepth = 4;
+ size_t mBufferQueueDepth;
+ size_t mFrameListDepth;
Vector<CameraMetadata> mFrameList;
size_t mFrameListHead;
ZslPair mNextPair;
Vector<ZslPair> mZslQueue;
- size_t mZslQueueHead;
- size_t mZslQueueTail;
CameraMetadata mLatestCapturedRequest;
+ bool mHasFocuser;
+
virtual bool threadLoop();
- status_t processNewZslBuffer();
-
- // Match up entries from frame list to buffers in ZSL queue
- void findMatchesLocked();
-
status_t clearZslQueueLocked();
+ void clearZslResultQueueLocked();
+
void dumpZslQueue(int id) const;
+
+ nsecs_t getCandidateTimestampLocked(size_t* metadataIdx) const;
+
+ bool isFixedFocusMode(uint8_t afMode) const;
+
+ // Update the post-processing metadata with the default still capture request template
+ status_t updateRequestWithDefaultStillRequest(CameraMetadata &request) const;
};
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
deleted file mode 100644
index 69620ac..0000000
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Camera2-ZslProcessor3"
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
-//#define LOG_NNDEBUG 0
-
-#ifdef LOG_NNDEBUG
-#define ALOGVV(...) ALOGV(__VA_ARGS__)
-#else
-#define ALOGVV(...) ((void)0)
-#endif
-
-#include <inttypes.h>
-
-#include <utils/Log.h>
-#include <utils/Trace.h>
-#include <gui/Surface.h>
-
-#include "common/CameraDeviceBase.h"
-#include "api1/Camera2Client.h"
-#include "api1/client2/CaptureSequencer.h"
-#include "api1/client2/ZslProcessor3.h"
-#include "device3/Camera3Device.h"
-
-namespace android {
-namespace camera2 {
-
-ZslProcessor3::ZslProcessor3(
- sp<Camera2Client> client,
- wp<CaptureSequencer> sequencer):
- Thread(false),
- mLatestClearedBufferTimestamp(0),
- mState(RUNNING),
- mClient(client),
- mSequencer(sequencer),
- mId(client->getCameraId()),
- mZslStreamId(NO_STREAM),
- mFrameListHead(0),
- mZslQueueHead(0),
- mZslQueueTail(0),
- mHasFocuser(false) {
- // Initialize buffer queue and frame list based on pipeline max depth.
- size_t pipelineMaxDepth = kDefaultMaxPipelineDepth;
- if (client != 0) {
- sp<Camera3Device> device =
- static_cast<Camera3Device*>(client->getCameraDevice().get());
- if (device != 0) {
- camera_metadata_ro_entry_t entry =
- device->info().find(ANDROID_REQUEST_PIPELINE_MAX_DEPTH);
- if (entry.count == 1) {
- pipelineMaxDepth = entry.data.u8[0];
- } else {
- ALOGW("%s: Unable to find the android.request.pipelineMaxDepth,"
- " use default pipeline max depth %zu", __FUNCTION__,
- kDefaultMaxPipelineDepth);
- }
-
- entry = device->info().find(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE);
- if (entry.count > 0 && entry.data.f[0] != 0.) {
- mHasFocuser = true;
- }
- }
- }
-
- ALOGV("%s: Initialize buffer queue and frame list depth based on max pipeline depth (%d)",
- __FUNCTION__, pipelineMaxDepth);
- // Need to keep buffer queue longer than metadata queue because sometimes buffer arrives
- // earlier than metadata which causes the buffer corresponding to oldest metadata being
- // removed.
- mFrameListDepth = pipelineMaxDepth;
- mBufferQueueDepth = mFrameListDepth + 1;
-
-
- mZslQueue.insertAt(0, mBufferQueueDepth);
- mFrameList.insertAt(0, mFrameListDepth);
- sp<CaptureSequencer> captureSequencer = mSequencer.promote();
- if (captureSequencer != 0) captureSequencer->setZslProcessor(this);
-}
-
-ZslProcessor3::~ZslProcessor3() {
- ALOGV("%s: Exit", __FUNCTION__);
- deleteStream();
-}
-
-void ZslProcessor3::onResultAvailable(const CaptureResult &result) {
- ATRACE_CALL();
- ALOGV("%s:", __FUNCTION__);
- Mutex::Autolock l(mInputMutex);
- camera_metadata_ro_entry_t entry;
- entry = result.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
- nsecs_t timestamp = entry.data.i64[0];
- if (entry.count == 0) {
- ALOGE("%s: metadata doesn't have timestamp, skip this result", __FUNCTION__);
- return;
- }
-
- entry = result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT);
- if (entry.count == 0) {
- ALOGE("%s: metadata doesn't have frame number, skip this result", __FUNCTION__);
- return;
- }
- int32_t frameNumber = entry.data.i32[0];
-
- ALOGVV("Got preview metadata for frame %d with timestamp %" PRId64, frameNumber, timestamp);
-
- if (mState != RUNNING) return;
-
- // Corresponding buffer has been cleared. No need to push into mFrameList
- if (timestamp <= mLatestClearedBufferTimestamp) return;
-
- mFrameList.editItemAt(mFrameListHead) = result.mMetadata;
- mFrameListHead = (mFrameListHead + 1) % mFrameListDepth;
-}
-
-status_t ZslProcessor3::updateStream(const Parameters ¶ms) {
- ATRACE_CALL();
- ALOGV("%s: Configuring ZSL streams", __FUNCTION__);
- status_t res;
-
- Mutex::Autolock l(mInputMutex);
-
- sp<Camera2Client> client = mClient.promote();
- if (client == 0) {
- ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
- sp<Camera3Device> device =
- static_cast<Camera3Device*>(client->getCameraDevice().get());
- if (device == 0) {
- ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
-
- if (mZslStreamId != NO_STREAM) {
- // Check if stream parameters have to change
- uint32_t currentWidth, currentHeight;
- res = device->getStreamInfo(mZslStreamId,
- ¤tWidth, ¤tHeight, 0, 0);
- 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) {
- ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
- "dimensions changed",
- __FUNCTION__, client->getCameraId(), mZslStreamId);
- res = device->deleteStream(mZslStreamId);
- if (res == -EBUSY) {
- ALOGV("%s: Camera %d: Device is busy, call updateStream again "
- " after it becomes idle", __FUNCTION__, mId);
- return res;
- } else if(res != OK) {
- ALOGE("%s: Camera %d: Unable to delete old output stream "
- "for ZSL: %s (%d)", __FUNCTION__,
- client->getCameraId(), strerror(-res), res);
- return res;
- }
- mZslStreamId = NO_STREAM;
- }
- }
-
- if (mZslStreamId == NO_STREAM) {
- // Create stream for HAL production
- // TODO: Sort out better way to select resolution for ZSL
-
- // Note that format specified internally in Camera3ZslStream
- res = device->createZslStream(
- params.fastInfo.arrayWidth, params.fastInfo.arrayHeight,
- mBufferQueueDepth,
- &mZslStreamId,
- &mZslStream);
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't create ZSL stream: "
- "%s (%d)", __FUNCTION__, client->getCameraId(),
- strerror(-res), res);
- return res;
- }
-
- // Only add the camera3 buffer listener when the stream is created.
- mZslStream->addBufferListener(this);
- }
-
- client->registerFrameListener(Camera2Client::kPreviewRequestIdStart,
- Camera2Client::kPreviewRequestIdEnd,
- this,
- /*sendPartials*/false);
-
- return OK;
-}
-
-status_t ZslProcessor3::deleteStream() {
- ATRACE_CALL();
- status_t res;
-
- Mutex::Autolock l(mInputMutex);
-
- if (mZslStreamId != NO_STREAM) {
- sp<Camera2Client> client = mClient.promote();
- if (client == 0) {
- ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
-
- sp<Camera3Device> device =
- reinterpret_cast<Camera3Device*>(client->getCameraDevice().get());
- if (device == 0) {
- ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
-
- res = device->deleteStream(mZslStreamId);
- if (res != OK) {
- ALOGE("%s: Camera %d: Cannot delete ZSL output stream %d: "
- "%s (%d)", __FUNCTION__, client->getCameraId(),
- mZslStreamId, strerror(-res), res);
- return res;
- }
-
- mZslStreamId = NO_STREAM;
- }
- return OK;
-}
-
-int ZslProcessor3::getStreamId() const {
- Mutex::Autolock l(mInputMutex);
- return mZslStreamId;
-}
-
-status_t ZslProcessor3::updateRequestWithDefaultStillRequest(CameraMetadata &request) const {
- sp<Camera2Client> client = mClient.promote();
- if (client == 0) {
- ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
- sp<Camera3Device> device =
- static_cast<Camera3Device*>(client->getCameraDevice().get());
- if (device == 0) {
- ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
-
- CameraMetadata stillTemplate;
- device->createDefaultRequest(CAMERA3_TEMPLATE_STILL_CAPTURE, &stillTemplate);
-
- // Find some of the post-processing tags, and assign the value from template to the request.
- // Only check the aberration mode and noise reduction mode for now, as they are very important
- // for image quality.
- uint32_t postProcessingTags[] = {
- ANDROID_NOISE_REDUCTION_MODE,
- ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
- ANDROID_COLOR_CORRECTION_MODE,
- ANDROID_TONEMAP_MODE,
- ANDROID_SHADING_MODE,
- ANDROID_HOT_PIXEL_MODE,
- ANDROID_EDGE_MODE
- };
-
- camera_metadata_entry_t entry;
- for (size_t i = 0; i < sizeof(postProcessingTags) / sizeof(uint32_t); i++) {
- entry = stillTemplate.find(postProcessingTags[i]);
- if (entry.count > 0) {
- request.update(postProcessingTags[i], entry.data.u8, 1);
- }
- }
-
- return OK;
-}
-
-status_t ZslProcessor3::pushToReprocess(int32_t requestId) {
- ALOGV("%s: Send in reprocess request with id %d",
- __FUNCTION__, requestId);
- Mutex::Autolock l(mInputMutex);
- status_t res;
- sp<Camera2Client> client = mClient.promote();
-
- if (client == 0) {
- ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
-
- IF_ALOGV() {
- dumpZslQueue(-1);
- }
-
- size_t metadataIdx;
- nsecs_t candidateTimestamp = getCandidateTimestampLocked(&metadataIdx);
-
- if (candidateTimestamp == -1) {
- ALOGE("%s: Could not find good candidate for ZSL reprocessing",
- __FUNCTION__);
- return NOT_ENOUGH_DATA;
- }
-
- res = mZslStream->enqueueInputBufferByTimestamp(candidateTimestamp,
- /*actualTimestamp*/NULL);
-
- if (res == mZslStream->NO_BUFFER_AVAILABLE) {
- ALOGV("%s: No ZSL buffers yet", __FUNCTION__);
- return NOT_ENOUGH_DATA;
- } else if (res != OK) {
- ALOGE("%s: Unable to push buffer for reprocessing: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
-
- {
- CameraMetadata request = mFrameList[metadataIdx];
-
- // Verify that the frame is reasonable for reprocessing
-
- camera_metadata_entry_t entry;
- entry = request.find(ANDROID_CONTROL_AE_STATE);
- if (entry.count == 0) {
- ALOGE("%s: ZSL queue frame has no AE state field!",
- __FUNCTION__);
- return BAD_VALUE;
- }
- if (entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_CONVERGED &&
- entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_LOCKED) {
- ALOGV("%s: ZSL queue frame AE state is %d, need full capture",
- __FUNCTION__, entry.data.u8[0]);
- return NOT_ENOUGH_DATA;
- }
-
- uint8_t requestType = ANDROID_REQUEST_TYPE_REPROCESS;
- res = request.update(ANDROID_REQUEST_TYPE,
- &requestType, 1);
- if (res != OK) {
- ALOGE("%s: Unable to update request type",
- __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- int32_t inputStreams[1] =
- { mZslStreamId };
- res = request.update(ANDROID_REQUEST_INPUT_STREAMS,
- inputStreams, 1);
- if (res != OK) {
- ALOGE("%s: Unable to update request input streams",
- __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- uint8_t captureIntent =
- static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
- res = request.update(ANDROID_CONTROL_CAPTURE_INTENT,
- &captureIntent, 1);
- if (res != OK ) {
- ALOGE("%s: Unable to update request capture intent",
- __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- // TODO: Shouldn't we also update the latest preview frame?
- int32_t outputStreams[1] =
- { client->getCaptureStreamId() };
- res = request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
- outputStreams, 1);
- if (res != OK) {
- ALOGE("%s: Unable to update request output streams",
- __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- res = request.update(ANDROID_REQUEST_ID,
- &requestId, 1);
- if (res != OK ) {
- ALOGE("%s: Unable to update frame to a reprocess request",
- __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- res = client->stopStream();
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to stop preview for ZSL capture: "
- "%s (%d)",
- __FUNCTION__, client->getCameraId(), strerror(-res), res);
- return INVALID_OPERATION;
- }
-
- // Update JPEG settings
- {
- SharedParameters::Lock l(client->getParameters());
- res = l.mParameters.updateRequestJpeg(&request);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to update JPEG entries of ZSL "
- "capture request: %s (%d)", __FUNCTION__,
- client->getCameraId(),
- strerror(-res), res);
- return res;
- }
- }
-
- // Update post-processing settings
- res = updateRequestWithDefaultStillRequest(request);
- if (res != OK) {
- ALOGW("%s: Unable to update post-processing tags, the reprocessed image quality "
- "may be compromised", __FUNCTION__);
- }
-
- mLatestCapturedRequest = request;
- res = client->getCameraDevice()->capture(request);
- if (res != OK ) {
- ALOGE("%s: Unable to send ZSL reprocess request to capture: %s"
- " (%d)", __FUNCTION__, strerror(-res), res);
- return res;
- }
-
- mState = LOCKED;
- }
-
- return OK;
-}
-
-status_t ZslProcessor3::clearZslQueue() {
- Mutex::Autolock l(mInputMutex);
- // If in middle of capture, can't clear out queue
- if (mState == LOCKED) return OK;
-
- return clearZslQueueLocked();
-}
-
-status_t ZslProcessor3::clearZslQueueLocked() {
- if (mZslStream != 0) {
- // clear result metadata list first.
- clearZslResultQueueLocked();
- return mZslStream->clearInputRingBuffer(&mLatestClearedBufferTimestamp);
- }
- return OK;
-}
-
-void ZslProcessor3::clearZslResultQueueLocked() {
- mFrameList.clear();
- mFrameListHead = 0;
- mFrameList.insertAt(0, mFrameListDepth);
-}
-
-void ZslProcessor3::dump(int fd, const Vector<String16>& /*args*/) const {
- Mutex::Autolock l(mInputMutex);
- if (!mLatestCapturedRequest.isEmpty()) {
- String8 result(" Latest ZSL capture request:\n");
- write(fd, result.string(), result.size());
- mLatestCapturedRequest.dump(fd, 2, 6);
- } else {
- String8 result(" Latest ZSL capture request: none yet\n");
- write(fd, result.string(), result.size());
- }
- dumpZslQueue(fd);
-}
-
-bool ZslProcessor3::threadLoop() {
- // TODO: remove dependency on thread. For now, shut thread down right
- // away.
- return false;
-}
-
-void ZslProcessor3::dumpZslQueue(int fd) const {
- String8 header("ZSL queue contents:");
- String8 indent(" ");
- ALOGV("%s", header.string());
- if (fd != -1) {
- header = indent + header + "\n";
- write(fd, header.string(), header.size());
- }
- for (size_t i = 0; i < mZslQueue.size(); i++) {
- const ZslPair &queueEntry = mZslQueue[i];
- nsecs_t bufferTimestamp = queueEntry.buffer.mTimestamp;
- camera_metadata_ro_entry_t entry;
- nsecs_t frameTimestamp = 0;
- int frameAeState = -1;
- if (!queueEntry.frame.isEmpty()) {
- entry = queueEntry.frame.find(ANDROID_SENSOR_TIMESTAMP);
- if (entry.count > 0) frameTimestamp = entry.data.i64[0];
- entry = queueEntry.frame.find(ANDROID_CONTROL_AE_STATE);
- if (entry.count > 0) frameAeState = entry.data.u8[0];
- }
- String8 result =
- String8::format(" %zu: b: %" PRId64 "\tf: %" PRId64 ", AE state: %d", i,
- bufferTimestamp, frameTimestamp, frameAeState);
- ALOGV("%s", result.string());
- if (fd != -1) {
- result = indent + result + "\n";
- write(fd, result.string(), result.size());
- }
-
- }
-}
-
-bool ZslProcessor3::isFixedFocusMode(uint8_t afMode) const {
- switch (afMode) {
- case ANDROID_CONTROL_AF_MODE_AUTO:
- case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
- case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
- case ANDROID_CONTROL_AF_MODE_MACRO:
- return false;
- break;
- case ANDROID_CONTROL_AF_MODE_OFF:
- case ANDROID_CONTROL_AF_MODE_EDOF:
- return true;
- default:
- ALOGE("%s: unknown focus mode %d", __FUNCTION__, afMode);
- return false;
- }
-}
-
-nsecs_t ZslProcessor3::getCandidateTimestampLocked(size_t* metadataIdx) const {
- /**
- * Find the smallest timestamp we know about so far
- * - ensure that aeState is either converged or locked
- */
-
- size_t idx = 0;
- nsecs_t minTimestamp = -1;
-
- size_t emptyCount = mFrameList.size();
-
- for (size_t j = 0; j < mFrameList.size(); j++) {
- const CameraMetadata &frame = mFrameList[j];
- if (!frame.isEmpty()) {
-
- emptyCount--;
-
- camera_metadata_ro_entry_t entry;
- entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
- if (entry.count == 0) {
- ALOGE("%s: Can't find timestamp in frame!",
- __FUNCTION__);
- continue;
- }
- nsecs_t frameTimestamp = entry.data.i64[0];
- if (minTimestamp > frameTimestamp || minTimestamp == -1) {
-
- entry = frame.find(ANDROID_CONTROL_AE_STATE);
-
- if (entry.count == 0) {
- /**
- * This is most likely a HAL bug. The aeState field is
- * mandatory, so it should always be in a metadata packet.
- */
- ALOGW("%s: ZSL queue frame has no AE state field!",
- __FUNCTION__);
- continue;
- }
- if (entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_CONVERGED &&
- entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_LOCKED) {
- ALOGVV("%s: ZSL queue frame AE state is %d, need "
- "full capture", __FUNCTION__, entry.data.u8[0]);
- continue;
- }
-
- entry = frame.find(ANDROID_CONTROL_AF_MODE);
- if (entry.count == 0) {
- ALOGW("%s: ZSL queue frame has no AF mode field!",
- __FUNCTION__);
- continue;
- }
- uint8_t afMode = entry.data.u8[0];
- if (afMode == ANDROID_CONTROL_AF_MODE_OFF) {
- // Skip all the ZSL buffer for manual AF mode, as we don't really
- // know the af state.
- continue;
- }
-
- // Check AF state if device has focuser and focus mode isn't fixed
- if (mHasFocuser && !isFixedFocusMode(afMode)) {
- // Make sure the candidate frame has good focus.
- entry = frame.find(ANDROID_CONTROL_AF_STATE);
- if (entry.count == 0) {
- ALOGW("%s: ZSL queue frame has no AF state field!",
- __FUNCTION__);
- continue;
- }
- uint8_t afState = entry.data.u8[0];
- if (afState != ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED &&
- afState != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED &&
- afState != ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
- ALOGVV("%s: ZSL queue frame AF state is %d is not good for capture, skip it",
- __FUNCTION__, afState);
- continue;
- }
- }
-
- minTimestamp = frameTimestamp;
- idx = j;
- }
-
- ALOGVV("%s: Saw timestamp %" PRId64, __FUNCTION__, frameTimestamp);
- }
- }
-
- if (emptyCount == mFrameList.size()) {
- /**
- * This could be mildly bad and means our ZSL was triggered before
- * there were any frames yet received by the camera framework.
- *
- * This is a fairly corner case which can happen under:
- * + a user presses the shutter button real fast when the camera starts
- * (startPreview followed immediately by takePicture).
- * + burst capture case (hitting shutter button as fast possible)
- *
- * If this happens in steady case (preview running for a while, call
- * a single takePicture) then this might be a fwk bug.
- */
- ALOGW("%s: ZSL queue has no metadata frames", __FUNCTION__);
- }
-
- ALOGV("%s: Candidate timestamp %" PRId64 " (idx %zu), empty frames: %zu",
- __FUNCTION__, minTimestamp, idx, emptyCount);
-
- if (metadataIdx) {
- *metadataIdx = idx;
- }
-
- return minTimestamp;
-}
-
-void ZslProcessor3::onBufferAcquired(const BufferInfo& /*bufferInfo*/) {
- // Intentionally left empty
- // Although theoretically we could use this to get better dump info
-}
-
-void ZslProcessor3::onBufferReleased(const BufferInfo& bufferInfo) {
-
- // ignore output buffers
- if (bufferInfo.mOutput) {
- return;
- }
-
- // Lock mutex only once we know this is an input buffer returned to avoid
- // potential deadlock
- Mutex::Autolock l(mInputMutex);
- // TODO: Verify that the buffer is in our queue by looking at timestamp
- // theoretically unnecessary unless we change the following assumptions:
- // -- only 1 buffer reprocessed at a time (which is the case now)
-
- // Erase entire ZSL queue since we've now completed the capture and preview
- // is stopped.
- //
- // We need to guarantee that if we do two back-to-back captures,
- // the second won't use a buffer that's older/the same as the first, which
- // is theoretically possible if we don't clear out the queue and the
- // selection criteria is something like 'newest'. Clearing out the result
- // metadata queue on a completed capture ensures we'll only use new timestamp.
- // Calling clearZslQueueLocked is a guaranteed deadlock because this callback
- // holds the Camera3Stream internal lock (mLock), and clearZslQueueLocked requires
- // to hold the same lock.
- // TODO: need figure out a way to clear the Zsl buffer queue properly. Right now
- // it is safe not to do so, as back to back ZSL capture requires stop and start
- // preview, which will flush ZSL queue automatically.
- ALOGV("%s: Memory optimization, clearing ZSL queue",
- __FUNCTION__);
- clearZslResultQueueLocked();
-
- // Required so we accept more ZSL requests
- mState = RUNNING;
-}
-
-}; // namespace camera2
-}; // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
deleted file mode 100644
index 2960478..0000000
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SERVERS_CAMERA_CAMERA2_ZSLPROCESSOR3_H
-#define ANDROID_SERVERS_CAMERA_CAMERA2_ZSLPROCESSOR3_H
-
-#include <utils/Thread.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-#include <utils/Mutex.h>
-#include <utils/Condition.h>
-#include <gui/BufferItem.h>
-#include <gui/BufferItemConsumer.h>
-#include <camera/CameraMetadata.h>
-
-#include "api1/client2/FrameProcessor.h"
-#include "api1/client2/ZslProcessorInterface.h"
-#include "device3/Camera3ZslStream.h"
-
-namespace android {
-
-class Camera2Client;
-
-namespace camera2 {
-
-class CaptureSequencer;
-class Parameters;
-
-/***
- * ZSL queue processing
- */
-class ZslProcessor3 :
- public ZslProcessorInterface,
- public camera3::Camera3StreamBufferListener,
- virtual public Thread,
- virtual public FrameProcessor::FilteredListener {
- public:
- ZslProcessor3(sp<Camera2Client> client, wp<CaptureSequencer> sequencer);
- ~ZslProcessor3();
-
- // From FrameProcessor::FilteredListener
- virtual void onResultAvailable(const CaptureResult &result);
-
- /**
- ****************************************
- * ZslProcessorInterface implementation *
- ****************************************
- */
-
- virtual status_t updateStream(const Parameters ¶ms);
- virtual status_t deleteStream();
- virtual int getStreamId() const;
-
- virtual status_t pushToReprocess(int32_t requestId);
- virtual status_t clearZslQueue();
-
- void dump(int fd, const Vector<String16>& args) const;
-
- protected:
- /**
- **********************************************
- * Camera3StreamBufferListener implementation *
- **********************************************
- */
- typedef camera3::Camera3StreamBufferListener::BufferInfo BufferInfo;
- // Buffer was acquired by the HAL
- virtual void onBufferAcquired(const BufferInfo& bufferInfo);
- // Buffer was released by the HAL
- virtual void onBufferReleased(const BufferInfo& bufferInfo);
-
- private:
- static const nsecs_t kWaitDuration = 10000000; // 10 ms
- nsecs_t mLatestClearedBufferTimestamp;
-
- enum {
- RUNNING,
- LOCKED
- } mState;
-
- wp<Camera2Client> mClient;
- wp<CaptureSequencer> mSequencer;
-
- const int mId;
-
- mutable Mutex mInputMutex;
-
- enum {
- NO_STREAM = -1
- };
-
- int mZslStreamId;
- sp<camera3::Camera3ZslStream> mZslStream;
-
- struct ZslPair {
- BufferItem buffer;
- CameraMetadata frame;
- };
-
- static const int32_t kDefaultMaxPipelineDepth = 4;
- size_t mBufferQueueDepth;
- size_t mFrameListDepth;
- Vector<CameraMetadata> mFrameList;
- size_t mFrameListHead;
-
- ZslPair mNextPair;
-
- Vector<ZslPair> mZslQueue;
- size_t mZslQueueHead;
- size_t mZslQueueTail;
-
- CameraMetadata mLatestCapturedRequest;
-
- bool mHasFocuser;
-
- virtual bool threadLoop();
-
- status_t clearZslQueueLocked();
-
- void clearZslResultQueueLocked();
-
- void dumpZslQueue(int id) const;
-
- nsecs_t getCandidateTimestampLocked(size_t* metadataIdx) const;
-
- bool isFixedFocusMode(uint8_t afMode) const;
-
- // Update the post-processing metadata with the default still capture request template
- status_t updateRequestWithDefaultStillRequest(CameraMetadata &request) const;
-};
-
-
-}; //namespace camera2
-}; //namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp
deleted file mode 100644
index 9efeaba..0000000
--- a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ZslProcessorInterface.h"
-
-namespace android {
-namespace camera2 {
-
-status_t ZslProcessorInterface::disconnect() {
- return OK;
-}
-
-}; //namespace camera2
-}; //namespace android
-
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
deleted file mode 100644
index 9e266e7..0000000
--- a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SERVERS_CAMERA_CAMERA2_ZSLPROCESSORINTERFACE_H
-#define ANDROID_SERVERS_CAMERA_CAMERA2_ZSLPROCESSORINTERFACE_H
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-namespace android {
-namespace camera2 {
-
-class Parameters;
-
-class ZslProcessorInterface : virtual public RefBase {
-public:
-
- // Get ID for use with android.request.outputStreams / inputStreams
- virtual int getStreamId() const = 0;
-
- // Update the streams by recreating them if the size/format has changed
- virtual status_t updateStream(const Parameters& params) = 0;
-
- // Delete the underlying CameraDevice streams
- virtual status_t deleteStream() = 0;
-
- // Clear any additional state necessary before the CameraDevice is disconnected
- virtual status_t disconnect();
-
- /**
- * Submits a ZSL capture request (id = requestId)
- *
- * An appropriate ZSL buffer is selected by the closest timestamp,
- * then we push that buffer to be reprocessed by the HAL.
- * A capture request is created and submitted on behalf of the client.
- */
- virtual status_t pushToReprocess(int32_t requestId) = 0;
-
- // Flush the ZSL buffer queue, freeing up all the buffers
- virtual status_t clearZslQueue() = 0;
-
- // (Debugging only) Dump the current state to the specified file descriptor
- virtual void dump(int fd, const Vector<String16>& args) const = 0;
-};
-
-}; //namespace camera2
-}; //namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index bd9fea3..7be5696 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -456,11 +456,11 @@
return BAD_VALUE;
}
- int streamId = -1;
+ int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
res = mDevice->createStream(surface, width, height, format, dataSpace,
static_cast<camera3_stream_rotation_t>
(outputConfiguration.getRotation()),
- &streamId);
+ &streamId, outputConfiguration.getSurfaceSetID());
if (res == OK) {
mStreamMap.add(binder, streamId);
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index c7de56a..4a812b4 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -31,7 +31,7 @@
#include "api2/CameraDeviceClient.h"
-#include "CameraDeviceFactory.h"
+#include "device3/Camera3Device.h"
namespace android {
using namespace camera2;
@@ -62,7 +62,7 @@
String8(clientPackageName).string(), clientPid, clientUid);
mInitialClientPid = clientPid;
- mDevice = CameraDeviceFactory::createDevice(cameraId);
+ mDevice = new Camera3Device(cameraId);
LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 4568af0..81bae7b 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -125,7 +125,7 @@
// that mBinderSerializationLock is locked when they're called
mutable Mutex mBinderSerializationLock;
- /** CameraDeviceBase instance wrapping HAL2+ entry */
+ /** CameraDeviceBase instance wrapping HAL3+ entry */
const int mDeviceVersion;
sp<CameraDeviceBase> mDevice;
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 7b083a3..6fd2b39 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -31,6 +31,7 @@
#include "camera/CaptureResult.h"
#include "common/CameraModule.h"
#include "gui/IGraphicBufferProducer.h"
+#include "device3/Camera3StreamInterface.h"
namespace android {
@@ -108,7 +109,8 @@
*/
virtual status_t createStream(sp<Surface> consumer,
uint32_t width, uint32_t height, int format,
- android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id) = 0;
+ android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
+ int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID) = 0;
/**
* Create an input stream of width, height, and format.
diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp
index 16b8aba..f33d1ba 100644
--- a/services/camera/libcameraservice/common/CameraModule.cpp
+++ b/services/camera/libcameraservice/common/CameraModule.cpp
@@ -27,15 +27,10 @@
void CameraModule::deriveCameraCharacteristicsKeys(
uint32_t deviceVersion, CameraMetadata &chars) {
ATRACE_CALL();
- // HAL1 devices should not reach here
- if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) {
- ALOGV("%s: Cannot derive keys for HAL version < 2.0");
- return;
- }
+ Vector<int32_t> derivedCharKeys;
// Keys added in HAL3.3
if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_3) {
- const size_t NUM_DERIVED_KEYS_HAL3_3 = 5;
Vector<uint8_t> controlModes;
uint8_t data = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;
chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1);
@@ -107,18 +102,11 @@
chars.update(ANDROID_SHADING_AVAILABLE_MODES, lscModes);
chars.update(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, lscMapModes);
- entry = chars.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
- Vector<int32_t> availableCharsKeys;
- availableCharsKeys.setCapacity(entry.count + NUM_DERIVED_KEYS_HAL3_3);
- for (size_t i = 0; i < entry.count; i++) {
- availableCharsKeys.push(entry.data.i32[i]);
- }
- availableCharsKeys.push(ANDROID_CONTROL_AE_LOCK_AVAILABLE);
- availableCharsKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE);
- availableCharsKeys.push(ANDROID_CONTROL_AVAILABLE_MODES);
- availableCharsKeys.push(ANDROID_SHADING_AVAILABLE_MODES);
- availableCharsKeys.push(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES);
- chars.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, availableCharsKeys);
+ derivedCharKeys.push(ANDROID_CONTROL_AE_LOCK_AVAILABLE);
+ derivedCharKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE);
+ derivedCharKeys.push(ANDROID_CONTROL_AVAILABLE_MODES);
+ derivedCharKeys.push(ANDROID_SHADING_AVAILABLE_MODES);
+ derivedCharKeys.push(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES);
// Need update android.control.availableHighSpeedVideoConfigurations since HAL3.3
// adds batch size to this array.
@@ -137,6 +125,65 @@
}
}
+ // Keys added in HAL3.4
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
+ // Check if HAL supports RAW_OPAQUE output
+ camera_metadata_entry entry = chars.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ bool supportRawOpaque = false;
+ bool supportAnyRaw = false;
+ const int STREAM_CONFIGURATION_SIZE = 4;
+ const int STREAM_FORMAT_OFFSET = 0;
+ const int STREAM_WIDTH_OFFSET = 1;
+ const int STREAM_HEIGHT_OFFSET = 2;
+ const int STREAM_IS_INPUT_OFFSET = 3;
+ Vector<int32_t> rawOpaqueSizes;
+
+ for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+ int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+ int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+ int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+ int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+ if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+ supportRawOpaque = true;
+ rawOpaqueSizes.push(width);
+ rawOpaqueSizes.push(height);
+ // 2 bytes per pixel. This rough estimation is only used when
+ // HAL does not fill in the opaque raw size
+ rawOpaqueSizes.push(width * height *2);
+ }
+ if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ (format == HAL_PIXEL_FORMAT_RAW16 ||
+ format == HAL_PIXEL_FORMAT_RAW10 ||
+ format == HAL_PIXEL_FORMAT_RAW12 ||
+ format == HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
+ supportAnyRaw = true;
+ }
+ }
+
+ if (supportRawOpaque) {
+ entry = chars.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+ if (entry.count == 0) {
+ // Fill in estimated value if HAL does not list it
+ chars.update(ANDROID_SENSOR_OPAQUE_RAW_SIZE, rawOpaqueSizes);
+ derivedCharKeys.push(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+ }
+ }
+
+ // Check if HAL supports any RAW output, if so, fill in postRawSensitivityBoost range
+ if (supportAnyRaw) {
+ int32_t defaultRange[2] = {100, 100};
+ entry = chars.find(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
+ if (entry.count == 0) {
+ // Fill in default value (100, 100)
+ chars.update(
+ ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE,
+ defaultRange, 2);
+ derivedCharKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
+ }
+ }
+ }
+
// Always add a default for the pre-correction active array if the vendor chooses to omit this
camera_metadata_entry entry = chars.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
if (entry.count == 0) {
@@ -144,8 +191,21 @@
entry = chars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
preCorrectionArray.appendArray(entry.data.i32, entry.count);
chars.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, preCorrectionArray);
+ derivedCharKeys.push(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
}
+ // Add those newly added keys to AVAILABLE_CHARACTERISTICS_KEYS
+ // This has to be done at this end of this function.
+ entry = chars.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+ Vector<int32_t> availableCharsKeys;
+ availableCharsKeys.setCapacity(entry.count + derivedCharKeys.size());
+ for (size_t i = 0; i < entry.count; i++) {
+ availableCharsKeys.push(entry.data.i32[i]);
+ }
+ for (size_t i = 0; i < derivedCharKeys.size(); i++) {
+ availableCharsKeys.push(derivedCharKeys[i]);
+ }
+ chars.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, availableCharsKeys);
return;
}
@@ -196,6 +256,9 @@
int ret;
ATRACE_BEGIN("camera_module->get_camera_info");
ret = mModule->get_camera_info(cameraId, info);
+ // Fill in this so CameraService won't be confused by
+ // possibly 0 device_version
+ info->device_version = CAMERA_DEVICE_API_VERSION_1_0;
ATRACE_END();
return ret;
}
@@ -211,7 +274,7 @@
return ret;
}
int deviceVersion = rawInfo.device_version;
- if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) {
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_0) {
// static_camera_characteristics is invalid
*info = rawInfo;
return ret;
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 7f14cd4..0fe76e5 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -73,10 +73,18 @@
class CameraHardwareInterface : public virtual RefBase {
public:
- CameraHardwareInterface(const char *name)
+ CameraHardwareInterface(const char *name):
+ mDevice(nullptr),
+ mName(name),
+ mPreviewScalingMode(NOT_SET),
+ mPreviewTransform(NOT_SET),
+ mPreviewWidth(NOT_SET),
+ mPreviewHeight(NOT_SET),
+ mPreviewFormat(NOT_SET),
+ mPreviewUsage(0),
+ mPreviewSwapInterval(NOT_SET),
+ mPreviewCrop{NOT_SET,NOT_SET,NOT_SET,NOT_SET}
{
- mDevice = 0;
- mName = name;
}
~CameraHardwareInterface()
@@ -118,9 +126,16 @@
status_t setPreviewWindow(const sp<ANativeWindow>& buf)
{
ALOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get());
-
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);
@@ -130,6 +145,27 @@
return INVALID_OPERATION;
}
+ status_t setPreviewScalingMode(int scalingMode)
+ {
+ int rc = OK;
+ mPreviewScalingMode = scalingMode;
+ if (mPreviewWindow != nullptr) {
+ rc = native_window_set_scaling_mode(mPreviewWindow.get(),
+ scalingMode);
+ }
+ return rc;
+ }
+
+ status_t setPreviewTransform(int transform) {
+ int rc = OK;
+ mPreviewTransform = transform;
+ if (mPreviewWindow != nullptr) {
+ rc = native_window_set_buffers_transform(mPreviewWindow.get(),
+ mPreviewTransform);
+ }
+ return rc;
+ }
+
/** Set the notification and data callbacks */
void setCallbacks(notify_callback notify_cb,
data_callback data_cb,
@@ -569,6 +605,8 @@
return __this->mPreviewWindow.get();
}
#define anw(n) __to_anw(((struct camera_preview_window *)n)->user)
+#define hwi(n) reinterpret_cast<CameraHardwareInterface *>(\
+ ((struct camera_preview_window *)n)->user)
static int __dequeue_buffer(struct preview_stream_ops* w,
buffer_handle_t** buffer, int *stride)
@@ -617,6 +655,44 @@
static int __set_buffer_count(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);
}
@@ -625,7 +701,10 @@
{
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) {
rc = native_window_set_buffers_format(a, format);
@@ -637,12 +716,12 @@
int left, int top, int right, int bottom)
{
ANativeWindow *a = anw(w);
- android_native_rect_t crop;
- crop.left = left;
- crop.top = top;
- crop.right = right;
- crop.bottom = bottom;
- return native_window_set_crop(a, &crop);
+ 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));
}
static int __set_timestamp(struct preview_stream_ops *w,
@@ -654,12 +733,16 @@
static int __set_usage(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);
}
static int __set_swap_interval(struct preview_stream_ops *w, int interval)
{
ANativeWindow *a = anw(w);
+ CameraHardwareInterface *hw = hwi(w);
+ hw->mPreviewSwapInterval = interval;
return a->setSwapInterval(a, interval);
}
@@ -701,6 +784,17 @@
data_callback mDataCb;
data_callback_timestamp mDataCbTimestamp;
void *mCbUser;
+
+ // Cached values for preview stream parameters
+ static const int NOT_SET = -1;
+ int mPreviewScalingMode;
+ int mPreviewTransform;
+ int mPreviewWidth;
+ int mPreviewHeight;
+ int mPreviewFormat;
+ int mPreviewUsage;
+ int mPreviewSwapInterval;
+ android_native_rect_t mPreviewCrop;
};
}; // namespace android
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
deleted file mode 100644
index d74f976..0000000
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ /dev/null
@@ -1,1618 +0,0 @@
-/*
- * Copyright (C) 2012 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 "Camera2-Device"
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
-//#define LOG_NNDEBUG 0 // Per-frame verbose logging
-
-#ifdef LOG_NNDEBUG
-#define ALOGVV(...) ALOGV(__VA_ARGS__)
-#else
-#define ALOGVV(...) ((void)0)
-#endif
-
-#include <inttypes.h>
-#include <utils/Log.h>
-#include <utils/Trace.h>
-#include <utils/Timers.h>
-#include "Camera2Device.h"
-#include "CameraService.h"
-
-namespace android {
-
-Camera2Device::Camera2Device(int id):
- mId(id),
- mHal2Device(NULL)
-{
- ATRACE_CALL();
- ALOGV("%s: Created device for camera %d", __FUNCTION__, id);
-}
-
-Camera2Device::~Camera2Device()
-{
- ATRACE_CALL();
- ALOGV("%s: Tearing down for camera id %d", __FUNCTION__, mId);
- disconnect();
-}
-
-int Camera2Device::getId() const {
- return mId;
-}
-
-status_t Camera2Device::initialize(CameraModule *module)
-{
- ATRACE_CALL();
- ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);
- if (mHal2Device != NULL) {
- ALOGE("%s: Already initialized!", __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- status_t res;
- char name[10];
- snprintf(name, sizeof(name), "%d", mId);
-
- camera2_device_t *device;
-
- res = module->open(name, reinterpret_cast<hw_device_t**>(&device));
-
- if (res != OK) {
- ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__,
- mId, strerror(-res), res);
- return res;
- }
-
- if (device->common.version != CAMERA_DEVICE_API_VERSION_2_0) {
- ALOGE("%s: Could not open camera %d: "
- "Camera device is not version %x, reports %x instead",
- __FUNCTION__, mId, CAMERA_DEVICE_API_VERSION_2_0,
- device->common.version);
- device->common.close(&device->common);
- return BAD_VALUE;
- }
-
- camera_info info;
- res = module->getCameraInfo(mId, &info);
- if (res != OK ) return res;
-
- if (info.device_version != device->common.version) {
- ALOGE("%s: HAL reporting mismatched camera_info version (%x)"
- " and device version (%x).", __FUNCTION__,
- device->common.version, info.device_version);
- device->common.close(&device->common);
- return BAD_VALUE;
- }
-
- res = mRequestQueue.setConsumerDevice(device);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to connect request queue to device: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- device->common.close(&device->common);
- return res;
- }
- res = mFrameQueue.setProducerDevice(device);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to connect frame queue to device: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- device->common.close(&device->common);
- return res;
- }
-
- res = device->ops->set_notify_callback(device, notificationCallback,
- NULL);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to initialize notification callback!",
- __FUNCTION__, mId);
- device->common.close(&device->common);
- return res;
- }
-
- mDeviceInfo = info.static_camera_characteristics;
- mHal2Device = device;
- mDeviceVersion = device->common.version;
-
- return OK;
-}
-
-status_t Camera2Device::disconnect() {
- ATRACE_CALL();
- status_t res = OK;
- if (mHal2Device) {
- ALOGV("%s: Closing device for camera %d", __FUNCTION__, mId);
-
- int inProgressCount = mHal2Device->ops->get_in_progress_count(mHal2Device);
- if (inProgressCount > 0) {
- ALOGW("%s: Closing camera device %d with %d requests in flight!",
- __FUNCTION__, mId, inProgressCount);
- }
- mReprocessStreams.clear();
- mStreams.clear();
- res = mHal2Device->common.close(&mHal2Device->common);
- if (res != OK) {
- ALOGE("%s: Could not close camera %d: %s (%d)",
- __FUNCTION__,
- mId, strerror(-res), res);
- }
- mHal2Device = NULL;
- ALOGV("%s: Shutdown complete", __FUNCTION__);
- }
- return res;
-}
-
-status_t Camera2Device::dump(int fd, const Vector<String16>& args) {
- ATRACE_CALL();
- String8 result;
- int detailLevel = 0;
- int n = args.size();
- String16 detailOption("-d");
- for (int i = 0; i + 1 < n; i++) {
- if (args[i] == detailOption) {
- String8 levelStr(args[i+1]);
- detailLevel = atoi(levelStr.string());
- }
- }
-
- result.appendFormat(" Camera2Device[%d] dump (detail level %d):\n",
- mId, detailLevel);
-
- if (detailLevel > 0) {
- result = " Request queue contents:\n";
- write(fd, result.string(), result.size());
- mRequestQueue.dump(fd, args);
-
- result = " Frame queue contents:\n";
- write(fd, result.string(), result.size());
- mFrameQueue.dump(fd, args);
- }
-
- result = " Active streams:\n";
- write(fd, result.string(), result.size());
- for (StreamList::iterator s = mStreams.begin(); s != mStreams.end(); s++) {
- (*s)->dump(fd, args);
- }
-
- result = " HAL device dump:\n";
- write(fd, result.string(), result.size());
-
- status_t res;
- res = mHal2Device->ops->dump(mHal2Device, fd);
-
- return res;
-}
-
-const CameraMetadata& Camera2Device::info() const {
- ALOGVV("%s: E", __FUNCTION__);
-
- return mDeviceInfo;
-}
-
-status_t Camera2Device::capture(CameraMetadata &request, int64_t* /*lastFrameNumber*/) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
-
- mRequestQueue.enqueue(request.release());
- return OK;
-}
-
-status_t Camera2Device::captureList(const List<const CameraMetadata> &requests,
- int64_t* /*lastFrameNumber*/) {
- ATRACE_CALL();
- ALOGE("%s: Camera2Device burst capture not implemented", __FUNCTION__);
- return INVALID_OPERATION;
-}
-
-status_t Camera2Device::setStreamingRequest(const CameraMetadata &request,
- int64_t* /*lastFrameNumber*/) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- CameraMetadata streamRequest(request);
- return mRequestQueue.setStreamSlot(streamRequest.release());
-}
-
-status_t Camera2Device::setStreamingRequestList(const List<const CameraMetadata> &requests,
- int64_t* /*lastFrameNumber*/) {
- ATRACE_CALL();
- ALOGE("%s, Camera2Device streaming burst not implemented", __FUNCTION__);
- return INVALID_OPERATION;
-}
-
-status_t Camera2Device::clearStreamingRequest(int64_t* /*lastFrameNumber*/) {
- ATRACE_CALL();
- return mRequestQueue.setStreamSlot(NULL);
-}
-
-status_t Camera2Device::waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) {
- ATRACE_CALL();
- return mRequestQueue.waitForDequeue(requestId, timeout);
-}
-
-status_t Camera2Device::createStream(sp<Surface> consumer,
- uint32_t width, uint32_t height, int format,
- android_dataspace /*dataSpace*/, camera3_stream_rotation_t rotation, int *id) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: E", __FUNCTION__);
-
- sp<StreamAdapter> stream = new StreamAdapter(mHal2Device);
- size_t size = 0;
- if (format == HAL_PIXEL_FORMAT_BLOB) {
- size = getJpegBufferSize(width, height);
- }
- res = stream->connectToDevice(consumer, width, height, format, size);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to create stream (%d x %d, format %x):"
- "%s (%d)",
- __FUNCTION__, mId, width, height, format, strerror(-res), res);
- return res;
- }
-
- *id = stream->getId();
-
- mStreams.push_back(stream);
- return OK;
-}
-
-ssize_t Camera2Device::getJpegBufferSize(uint32_t width, uint32_t height) const {
- // Always give the max jpeg buffer size regardless of the actual jpeg resolution.
- camera_metadata_ro_entry jpegBufMaxSize = mDeviceInfo.find(ANDROID_JPEG_MAX_SIZE);
- if (jpegBufMaxSize.count == 0) {
- ALOGE("%s: Camera %d: Can't find maximum JPEG size in static metadata!", __FUNCTION__, mId);
- return BAD_VALUE;
- }
-
- return jpegBufMaxSize.data.i32[0];
-}
-
-status_t Camera2Device::createReprocessStreamFromStream(int outputId, int *id) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: E", __FUNCTION__);
-
- bool found = false;
- StreamList::iterator streamI;
- for (streamI = mStreams.begin();
- streamI != mStreams.end(); streamI++) {
- if ((*streamI)->getId() == outputId) {
- found = true;
- break;
- }
- }
- if (!found) {
- ALOGE("%s: Camera %d: Output stream %d doesn't exist; can't create "
- "reprocess stream from it!", __FUNCTION__, mId, outputId);
- return BAD_VALUE;
- }
-
- sp<ReprocessStreamAdapter> stream = new ReprocessStreamAdapter(mHal2Device);
-
- res = stream->connectToDevice((*streamI));
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to create reprocessing stream from "\
- "stream %d: %s (%d)", __FUNCTION__, mId, outputId,
- strerror(-res), res);
- return res;
- }
-
- *id = stream->getId();
-
- mReprocessStreams.push_back(stream);
- return OK;
-}
-
-
-status_t Camera2Device::getStreamInfo(int id,
- uint32_t *width, uint32_t *height,
- uint32_t *format, android_dataspace *dataSpace) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- bool found = false;
- StreamList::iterator streamI;
- for (streamI = mStreams.begin();
- streamI != mStreams.end(); streamI++) {
- if ((*streamI)->getId() == id) {
- found = true;
- break;
- }
- }
- if (!found) {
- ALOGE("%s: Camera %d: Stream %d does not exist",
- __FUNCTION__, mId, id);
- return BAD_VALUE;
- }
-
- if (width) *width = (*streamI)->getWidth();
- if (height) *height = (*streamI)->getHeight();
- if (format) *format = (*streamI)->getFormat();
- if (dataSpace) *dataSpace = HAL_DATASPACE_UNKNOWN;
-
- return OK;
-}
-
-status_t Camera2Device::setStreamTransform(int id,
- int transform) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- bool found = false;
- StreamList::iterator streamI;
- for (streamI = mStreams.begin();
- streamI != mStreams.end(); streamI++) {
- if ((*streamI)->getId() == id) {
- found = true;
- break;
- }
- }
- if (!found) {
- ALOGE("%s: Camera %d: Stream %d does not exist",
- __FUNCTION__, mId, id);
- return BAD_VALUE;
- }
-
- return (*streamI)->setTransform(transform);
-}
-
-status_t Camera2Device::deleteStream(int id) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- bool found = false;
- for (StreamList::iterator streamI = mStreams.begin();
- streamI != mStreams.end(); streamI++) {
- if ((*streamI)->getId() == id) {
- status_t res = (*streamI)->release();
- if (res != OK) {
- ALOGE("%s: Unable to release stream %d from HAL device: "
- "%s (%d)", __FUNCTION__, id, strerror(-res), res);
- return res;
- }
- mStreams.erase(streamI);
- found = true;
- break;
- }
- }
- if (!found) {
- ALOGE("%s: Camera %d: Unable to find stream %d to delete",
- __FUNCTION__, mId, id);
- return BAD_VALUE;
- }
- return OK;
-}
-
-status_t Camera2Device::deleteReprocessStream(int id) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- bool found = false;
- for (ReprocessStreamList::iterator streamI = mReprocessStreams.begin();
- streamI != mReprocessStreams.end(); streamI++) {
- if ((*streamI)->getId() == id) {
- status_t res = (*streamI)->release();
- if (res != OK) {
- ALOGE("%s: Unable to release reprocess stream %d from "
- "HAL device: %s (%d)", __FUNCTION__, id,
- strerror(-res), res);
- return res;
- }
- mReprocessStreams.erase(streamI);
- found = true;
- break;
- }
- }
- if (!found) {
- ALOGE("%s: Camera %d: Unable to find stream %d to delete",
- __FUNCTION__, mId, id);
- return BAD_VALUE;
- }
- return OK;
-}
-
-status_t Camera2Device::configureStreams(bool isConstrainedHighSpeed) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
-
- /**
- * HAL2 devices do not need to configure streams;
- * streams are created on the fly.
- */
- ALOGW("%s: No-op for HAL2 devices", __FUNCTION__);
-
- return OK;
-}
-
-
-status_t Camera2Device::createDefaultRequest(int templateId,
- CameraMetadata *request) {
- ATRACE_CALL();
- status_t err;
- ALOGV("%s: E", __FUNCTION__);
- camera_metadata_t *rawRequest;
- err = mHal2Device->ops->construct_default_request(
- mHal2Device, templateId, &rawRequest);
- request->acquire(rawRequest);
- return err;
-}
-
-status_t Camera2Device::waitUntilDrained() {
- ATRACE_CALL();
- static const uint32_t kSleepTime = 50000; // 50 ms
- static const uint32_t kMaxSleepTime = 10000000; // 10 s
- ALOGV("%s: Camera %d: Starting wait", __FUNCTION__, mId);
- if (mRequestQueue.getBufferCount() ==
- CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS) return INVALID_OPERATION;
-
- // TODO: Set up notifications from HAL, instead of sleeping here
- uint32_t totalTime = 0;
- while (mHal2Device->ops->get_in_progress_count(mHal2Device) > 0) {
- usleep(kSleepTime);
- totalTime += kSleepTime;
- if (totalTime > kMaxSleepTime) {
- ALOGE("%s: Waited %d us, %d requests still in flight", __FUNCTION__,
- totalTime, mHal2Device->ops->get_in_progress_count(mHal2Device));
- return TIMED_OUT;
- }
- }
- ALOGV("%s: Camera %d: HAL is idle", __FUNCTION__, mId);
- return OK;
-}
-
-status_t Camera2Device::setNotifyCallback(NotificationListener *listener) {
- ATRACE_CALL();
- status_t res;
- res = mHal2Device->ops->set_notify_callback(mHal2Device, notificationCallback,
- reinterpret_cast<void*>(listener) );
- if (res != OK) {
- ALOGE("%s: Unable to set notification callback!", __FUNCTION__);
- }
- return res;
-}
-
-bool Camera2Device::willNotify3A() {
- return true;
-}
-
-void Camera2Device::notificationCallback(int32_t msg_type,
- int32_t ext1,
- int32_t ext2,
- int32_t ext3,
- void *user) {
- ATRACE_CALL();
- NotificationListener *listener = reinterpret_cast<NotificationListener*>(user);
- ALOGV("%s: Notification %d, arguments %d, %d, %d", __FUNCTION__, msg_type,
- ext1, ext2, ext3);
- if (listener != NULL) {
- switch (msg_type) {
- case CAMERA2_MSG_ERROR:
- // TODO: This needs to be fixed. ext2 and ext3 need to be considered.
- listener->notifyError(
- ((ext1 == CAMERA2_MSG_ERROR_DEVICE)
- || (ext1 == CAMERA2_MSG_ERROR_HARDWARE)) ?
- ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE :
- ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE,
- CaptureResultExtras());
- break;
- case CAMERA2_MSG_SHUTTER: {
- // TODO: Only needed for camera2 API, which is unsupported
- // by HAL2 directly.
- // nsecs_t timestamp = (nsecs_t)ext2 | ((nsecs_t)(ext3) << 32 );
- // listener->notifyShutter(requestId, timestamp);
- break;
- }
- case CAMERA2_MSG_AUTOFOCUS:
- listener->notifyAutoFocus(ext1, ext2);
- break;
- case CAMERA2_MSG_AUTOEXPOSURE:
- listener->notifyAutoExposure(ext1, ext2);
- break;
- case CAMERA2_MSG_AUTOWB:
- listener->notifyAutoWhitebalance(ext1, ext2);
- break;
- default:
- ALOGE("%s: Unknown notification %d (arguments %d, %d, %d)!",
- __FUNCTION__, msg_type, ext1, ext2, ext3);
- }
- }
-}
-
-status_t Camera2Device::waitForNextFrame(nsecs_t timeout) {
- return mFrameQueue.waitForBuffer(timeout);
-}
-
-status_t Camera2Device::getNextResult(CaptureResult *result) {
- ATRACE_CALL();
- ALOGV("%s: get CaptureResult", __FUNCTION__);
- if (result == NULL) {
- ALOGE("%s: result pointer is NULL", __FUNCTION__);
- return BAD_VALUE;
- }
- status_t res;
- camera_metadata_t *rawFrame;
- res = mFrameQueue.dequeue(&rawFrame);
- if (rawFrame == NULL) {
- return NOT_ENOUGH_DATA;
- } else if (res == OK) {
- result->mMetadata.acquire(rawFrame);
- }
-
- return res;
-}
-
-status_t Camera2Device::triggerAutofocus(uint32_t id) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: Triggering autofocus, id %d", __FUNCTION__, id);
- res = mHal2Device->ops->trigger_action(mHal2Device,
- CAMERA2_TRIGGER_AUTOFOCUS, id, 0);
- if (res != OK) {
- ALOGE("%s: Error triggering autofocus (id %d)",
- __FUNCTION__, id);
- }
- return res;
-}
-
-status_t Camera2Device::triggerCancelAutofocus(uint32_t id) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: Canceling autofocus, id %d", __FUNCTION__, id);
- res = mHal2Device->ops->trigger_action(mHal2Device,
- CAMERA2_TRIGGER_CANCEL_AUTOFOCUS, id, 0);
- if (res != OK) {
- ALOGE("%s: Error canceling autofocus (id %d)",
- __FUNCTION__, id);
- }
- return res;
-}
-
-status_t Camera2Device::triggerPrecaptureMetering(uint32_t id) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: Triggering precapture metering, id %d", __FUNCTION__, id);
- res = mHal2Device->ops->trigger_action(mHal2Device,
- CAMERA2_TRIGGER_PRECAPTURE_METERING, id, 0);
- if (res != OK) {
- ALOGE("%s: Error triggering precapture metering (id %d)",
- __FUNCTION__, id);
- }
- return res;
-}
-
-status_t Camera2Device::pushReprocessBuffer(int reprocessStreamId,
- buffer_handle_t *buffer, wp<BufferReleasedListener> listener) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- bool found = false;
- status_t res = OK;
- for (ReprocessStreamList::iterator streamI = mReprocessStreams.begin();
- streamI != mReprocessStreams.end(); streamI++) {
- if ((*streamI)->getId() == reprocessStreamId) {
- res = (*streamI)->pushIntoStream(buffer, listener);
- if (res != OK) {
- ALOGE("%s: Unable to push buffer to reprocess stream %d: %s (%d)",
- __FUNCTION__, reprocessStreamId, strerror(-res), res);
- return res;
- }
- found = true;
- break;
- }
- }
- if (!found) {
- ALOGE("%s: Camera %d: Unable to find reprocess stream %d",
- __FUNCTION__, mId, reprocessStreamId);
- res = BAD_VALUE;
- }
- return res;
-}
-
-status_t Camera2Device::flush(int64_t* /*lastFrameNumber*/) {
- ATRACE_CALL();
-
- mRequestQueue.clear();
- return waitUntilDrained();
-}
-
-status_t Camera2Device::prepare(int streamId) {
- ATRACE_CALL();
- ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId);
- return NO_INIT;
-}
-
-status_t Camera2Device::tearDown(int streamId) {
- ATRACE_CALL();
- ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId);
- return NO_INIT;
-}
-
-status_t Camera2Device::prepare(int maxCount, int streamId) {
- ATRACE_CALL();
- ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId);
- return NO_INIT;
-}
-
-uint32_t Camera2Device::getDeviceVersion() {
- ATRACE_CALL();
- return mDeviceVersion;
-}
-
-/**
- * Camera2Device::MetadataQueue
- */
-
-Camera2Device::MetadataQueue::MetadataQueue():
- mHal2Device(NULL),
- mFrameCount(0),
- mLatestRequestId(0),
- mCount(0),
- mStreamSlotCount(0),
- mSignalConsumer(true)
-{
- ATRACE_CALL();
- camera2_request_queue_src_ops::dequeue_request = consumer_dequeue;
- camera2_request_queue_src_ops::request_count = consumer_buffer_count;
- camera2_request_queue_src_ops::free_request = consumer_free;
-
- camera2_frame_queue_dst_ops::dequeue_frame = producer_dequeue;
- camera2_frame_queue_dst_ops::cancel_frame = producer_cancel;
- camera2_frame_queue_dst_ops::enqueue_frame = producer_enqueue;
-}
-
-Camera2Device::MetadataQueue::~MetadataQueue() {
- ATRACE_CALL();
- clear();
-}
-
-// Connect to camera2 HAL as consumer (input requests/reprocessing)
-status_t Camera2Device::MetadataQueue::setConsumerDevice(camera2_device_t *d) {
- ATRACE_CALL();
- status_t res;
- res = d->ops->set_request_queue_src_ops(d,
- this);
- if (res != OK) return res;
- mHal2Device = d;
- return OK;
-}
-
-status_t Camera2Device::MetadataQueue::setProducerDevice(camera2_device_t *d) {
- ATRACE_CALL();
- status_t res;
- res = d->ops->set_frame_queue_dst_ops(d,
- this);
- return res;
-}
-
-// Real interfaces
-status_t Camera2Device::MetadataQueue::enqueue(camera_metadata_t *buf) {
- ATRACE_CALL();
- ALOGVV("%s: E", __FUNCTION__);
- Mutex::Autolock l(mMutex);
-
- mCount++;
- mEntries.push_back(buf);
-
- return signalConsumerLocked();
-}
-
-int Camera2Device::MetadataQueue::getBufferCount() {
- ATRACE_CALL();
- Mutex::Autolock l(mMutex);
- if (mStreamSlotCount > 0) {
- return CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS;
- }
- return mCount;
-}
-
-status_t Camera2Device::MetadataQueue::dequeue(camera_metadata_t **buf,
- bool incrementCount)
-{
- ATRACE_CALL();
- ALOGVV("%s: E", __FUNCTION__);
- status_t res;
- Mutex::Autolock l(mMutex);
-
- if (mCount == 0) {
- if (mStreamSlotCount == 0) {
- ALOGVV("%s: Empty", __FUNCTION__);
- *buf = NULL;
- mSignalConsumer = true;
- return OK;
- }
- ALOGVV("%s: Streaming %d frames to queue", __FUNCTION__,
- mStreamSlotCount);
-
- for (List<camera_metadata_t*>::iterator slotEntry = mStreamSlot.begin();
- slotEntry != mStreamSlot.end();
- slotEntry++ ) {
- size_t entries = get_camera_metadata_entry_count(*slotEntry);
- size_t dataBytes = get_camera_metadata_data_count(*slotEntry);
-
- camera_metadata_t *copy =
- allocate_camera_metadata(entries, dataBytes);
- append_camera_metadata(copy, *slotEntry);
- mEntries.push_back(copy);
- }
- mCount = mStreamSlotCount;
- }
- ALOGVV("MetadataQueue: deque (%d buffers)", mCount);
- camera_metadata_t *b = *(mEntries.begin());
- mEntries.erase(mEntries.begin());
-
- if (incrementCount) {
- ATRACE_INT("cam2_request", mFrameCount);
- camera_metadata_entry_t frameCount;
- res = find_camera_metadata_entry(b,
- ANDROID_REQUEST_FRAME_COUNT,
- &frameCount);
- if (res != OK) {
- ALOGE("%s: Unable to add frame count: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- } else {
- *frameCount.data.i32 = mFrameCount;
- }
- mFrameCount++;
- }
-
- // Check for request ID, and if present, signal waiters.
- camera_metadata_entry_t requestId;
- res = find_camera_metadata_entry(b,
- ANDROID_REQUEST_ID,
- &requestId);
- if (res == OK) {
- mLatestRequestId = requestId.data.i32[0];
- mNewRequestId.signal();
- }
-
- *buf = b;
- mCount--;
-
- return OK;
-}
-
-status_t Camera2Device::MetadataQueue::waitForBuffer(nsecs_t timeout)
-{
- Mutex::Autolock l(mMutex);
- status_t res;
- while (mCount == 0) {
- res = notEmpty.waitRelative(mMutex,timeout);
- if (res != OK) return res;
- }
- return OK;
-}
-
-status_t Camera2Device::MetadataQueue::waitForDequeue(int32_t id,
- nsecs_t timeout) {
- Mutex::Autolock l(mMutex);
- status_t res;
- while (mLatestRequestId != id) {
- nsecs_t startTime = systemTime();
-
- res = mNewRequestId.waitRelative(mMutex, timeout);
- if (res != OK) return res;
-
- timeout -= (systemTime() - startTime);
- }
-
- return OK;
-}
-
-status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf)
-{
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- Mutex::Autolock l(mMutex);
- if (buf == NULL) {
- freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
- mStreamSlotCount = 0;
- return OK;
- }
-
- if (mStreamSlotCount > 1) {
- List<camera_metadata_t*>::iterator deleter = ++mStreamSlot.begin();
- freeBuffers(++mStreamSlot.begin(), mStreamSlot.end());
- mStreamSlotCount = 1;
- }
- if (mStreamSlotCount == 1) {
- free_camera_metadata( *(mStreamSlot.begin()) );
- *(mStreamSlot.begin()) = buf;
- } else {
- mStreamSlot.push_front(buf);
- mStreamSlotCount = 1;
- }
- return signalConsumerLocked();
-}
-
-status_t Camera2Device::MetadataQueue::setStreamSlot(
- const List<camera_metadata_t*> &bufs)
-{
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- Mutex::Autolock l(mMutex);
-
- if (mStreamSlotCount > 0) {
- freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
- }
- mStreamSlotCount = 0;
- for (List<camera_metadata_t*>::const_iterator r = bufs.begin();
- r != bufs.end(); r++) {
- mStreamSlot.push_back(*r);
- mStreamSlotCount++;
- }
- return signalConsumerLocked();
-}
-
-status_t Camera2Device::MetadataQueue::clear()
-{
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
-
- Mutex::Autolock l(mMutex);
-
- // Clear streaming slot
- freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
- mStreamSlotCount = 0;
-
- // Clear request queue
- freeBuffers(mEntries.begin(), mEntries.end());
- mCount = 0;
- return OK;
-}
-
-status_t Camera2Device::MetadataQueue::dump(int fd,
- const Vector<String16>& /*args*/) {
- ATRACE_CALL();
- String8 result;
- status_t notLocked;
- notLocked = mMutex.tryLock();
- if (notLocked) {
- result.append(" (Unable to lock queue mutex)\n");
- }
- result.appendFormat(" Current frame number: %d\n", mFrameCount);
- if (mStreamSlotCount == 0) {
- result.append(" Stream slot: Empty\n");
- write(fd, result.string(), result.size());
- } else {
- result.appendFormat(" Stream slot: %zu entries\n",
- mStreamSlot.size());
- int i = 0;
- for (List<camera_metadata_t*>::iterator r = mStreamSlot.begin();
- r != mStreamSlot.end(); r++) {
- result = String8::format(" Stream slot buffer %d:\n", i);
- write(fd, result.string(), result.size());
- dump_indented_camera_metadata(*r, fd, 2, 10);
- i++;
- }
- }
- if (mEntries.size() == 0) {
- result = " Main queue is empty\n";
- write(fd, result.string(), result.size());
- } else {
- result = String8::format(" Main queue has %zu entries:\n",
- mEntries.size());
- int i = 0;
- for (List<camera_metadata_t*>::iterator r = mEntries.begin();
- r != mEntries.end(); r++) {
- result = String8::format(" Queue entry %d:\n", i);
- write(fd, result.string(), result.size());
- dump_indented_camera_metadata(*r, fd, 2, 10);
- i++;
- }
- }
-
- if (notLocked == 0) {
- mMutex.unlock();
- }
-
- return OK;
-}
-
-status_t Camera2Device::MetadataQueue::signalConsumerLocked() {
- ATRACE_CALL();
- status_t res = OK;
- notEmpty.signal();
- if (mSignalConsumer && mHal2Device != NULL) {
- mSignalConsumer = false;
-
- mMutex.unlock();
- ALOGV("%s: Signaling consumer", __FUNCTION__);
- res = mHal2Device->ops->notify_request_queue_not_empty(mHal2Device);
- mMutex.lock();
- }
- return res;
-}
-
-status_t Camera2Device::MetadataQueue::freeBuffers(
- List<camera_metadata_t*>::iterator start,
- List<camera_metadata_t*>::iterator end)
-{
- ATRACE_CALL();
- while (start != end) {
- free_camera_metadata(*start);
- start = mStreamSlot.erase(start);
- }
- return OK;
-}
-
-Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance(
- const camera2_request_queue_src_ops_t *q)
-{
- const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q);
- return const_cast<MetadataQueue*>(cmq);
-}
-
-Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance(
- const camera2_frame_queue_dst_ops_t *q)
-{
- const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q);
- return const_cast<MetadataQueue*>(cmq);
-}
-
-int Camera2Device::MetadataQueue::consumer_buffer_count(
- const camera2_request_queue_src_ops_t *q)
-{
- MetadataQueue *queue = getInstance(q);
- return queue->getBufferCount();
-}
-
-int Camera2Device::MetadataQueue::consumer_dequeue(
- const camera2_request_queue_src_ops_t *q,
- camera_metadata_t **buffer)
-{
- MetadataQueue *queue = getInstance(q);
- return queue->dequeue(buffer, true);
-}
-
-int Camera2Device::MetadataQueue::consumer_free(
- const camera2_request_queue_src_ops_t *q,
- camera_metadata_t *old_buffer)
-{
- ATRACE_CALL();
- MetadataQueue *queue = getInstance(q);
- (void)queue;
- free_camera_metadata(old_buffer);
- return OK;
-}
-
-int Camera2Device::MetadataQueue::producer_dequeue(
- const camera2_frame_queue_dst_ops_t * /*q*/,
- size_t entries, size_t bytes,
- camera_metadata_t **buffer)
-{
- ATRACE_CALL();
- camera_metadata_t *new_buffer =
- allocate_camera_metadata(entries, bytes);
- if (new_buffer == NULL) return NO_MEMORY;
- *buffer = new_buffer;
- return OK;
-}
-
-int Camera2Device::MetadataQueue::producer_cancel(
- const camera2_frame_queue_dst_ops_t * /*q*/,
- camera_metadata_t *old_buffer)
-{
- ATRACE_CALL();
- free_camera_metadata(old_buffer);
- return OK;
-}
-
-int Camera2Device::MetadataQueue::producer_enqueue(
- const camera2_frame_queue_dst_ops_t *q,
- camera_metadata_t *filled_buffer)
-{
- MetadataQueue *queue = getInstance(q);
- return queue->enqueue(filled_buffer);
-}
-
-/**
- * Camera2Device::StreamAdapter
- */
-
-#ifndef container_of
-#define container_of(ptr, type, member) \
- (type *)((char*)(ptr) - offsetof(type, member))
-#endif
-
-Camera2Device::StreamAdapter::StreamAdapter(camera2_device_t *d):
- mState(RELEASED),
- mHal2Device(d),
- mId(-1),
- mWidth(0), mHeight(0), mFormat(0), mSize(0), mUsage(0),
- mMaxProducerBuffers(0), mMaxConsumerBuffers(0),
- mTotalBuffers(0),
- mFormatRequested(0),
- mActiveBuffers(0),
- mFrameCount(0),
- mLastTimestamp(0)
-{
- camera2_stream_ops::dequeue_buffer = dequeue_buffer;
- camera2_stream_ops::enqueue_buffer = enqueue_buffer;
- camera2_stream_ops::cancel_buffer = cancel_buffer;
- camera2_stream_ops::set_crop = set_crop;
-}
-
-Camera2Device::StreamAdapter::~StreamAdapter() {
- ATRACE_CALL();
- if (mState != RELEASED) {
- release();
- }
-}
-
-status_t Camera2Device::StreamAdapter::connectToDevice(
- sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, size_t size) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: E", __FUNCTION__);
-
- if (mState != RELEASED) return INVALID_OPERATION;
- if (consumer == NULL) {
- ALOGE("%s: Null consumer passed to stream adapter", __FUNCTION__);
- return BAD_VALUE;
- }
-
- ALOGV("%s: New stream parameters %d x %d, format 0x%x, size %zu",
- __FUNCTION__, width, height, format, size);
-
- mConsumerInterface = consumer;
- mWidth = width;
- mHeight = height;
- mSize = (format == HAL_PIXEL_FORMAT_BLOB) ? size : 0;
- mFormatRequested = format;
-
- // Allocate device-side stream interface
-
- uint32_t id;
- uint32_t formatActual;
- uint32_t usage;
- uint32_t maxBuffers = 2;
- res = mHal2Device->ops->allocate_stream(mHal2Device,
- mWidth, mHeight, mFormatRequested, getStreamOps(),
- &id, &formatActual, &usage, &maxBuffers);
- if (res != OK) {
- ALOGE("%s: Device stream allocation failed: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
-
- ALOGV("%s: Allocated stream id %d, actual format 0x%x, "
- "usage 0x%x, producer wants %d buffers", __FUNCTION__,
- id, formatActual, usage, maxBuffers);
-
- mId = id;
- mFormat = formatActual;
- mUsage = usage;
- mMaxProducerBuffers = maxBuffers;
-
- mState = ALLOCATED;
-
- // Configure consumer-side ANativeWindow interface
- res = native_window_api_connect(mConsumerInterface.get(),
- NATIVE_WINDOW_API_CAMERA);
- if (res != OK) {
- ALOGE("%s: Unable to connect to native window for stream %d",
- __FUNCTION__, mId);
-
- return res;
- }
-
- mState = CONNECTED;
-
- res = native_window_set_usage(mConsumerInterface.get(), mUsage);
- if (res != OK) {
- ALOGE("%s: Unable to configure usage %08x for stream %d",
- __FUNCTION__, mUsage, mId);
- return res;
- }
-
- res = native_window_set_scaling_mode(mConsumerInterface.get(),
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- if (res != OK) {
- ALOGE("%s: Unable to configure stream scaling: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
-
- res = setTransform(0);
- if (res != OK) {
- return res;
- }
-
- if (mFormat == HAL_PIXEL_FORMAT_BLOB) {
- res = native_window_set_buffers_dimensions(mConsumerInterface.get(),
- mSize, 1);
- if (res != OK) {
- ALOGE("%s: Unable to configure compressed stream buffer dimensions"
- " %d x %d, size %zu for stream %d",
- __FUNCTION__, mWidth, mHeight, mSize, mId);
- return res;
- }
- } else {
- res = native_window_set_buffers_dimensions(mConsumerInterface.get(),
- mWidth, mHeight);
- if (res != OK) {
- ALOGE("%s: Unable to configure stream buffer dimensions"
- " %d x %d for stream %d",
- __FUNCTION__, mWidth, mHeight, mId);
- return res;
- }
- }
-
- res = native_window_set_buffers_format(mConsumerInterface.get(), mFormat);
- if (res != OK) {
- ALOGE("%s: Unable to configure stream buffer format"
- " %#x for stream %d",
- __FUNCTION__, mFormat, mId);
- return res;
- }
-
- int maxConsumerBuffers;
- res = mConsumerInterface->query(mConsumerInterface.get(),
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
- if (res != OK) {
- ALOGE("%s: Unable to query consumer undequeued"
- " buffer count for stream %d", __FUNCTION__, mId);
- return res;
- }
- mMaxConsumerBuffers = maxConsumerBuffers;
-
- ALOGV("%s: Consumer wants %d buffers", __FUNCTION__,
- mMaxConsumerBuffers);
-
- mTotalBuffers = mMaxConsumerBuffers + mMaxProducerBuffers;
- mActiveBuffers = 0;
- mFrameCount = 0;
- mLastTimestamp = 0;
-
- res = native_window_set_buffer_count(mConsumerInterface.get(),
- mTotalBuffers);
- if (res != OK) {
- ALOGE("%s: Unable to set buffer count for stream %d",
- __FUNCTION__, mId);
- return res;
- }
-
- // Register allocated buffers with HAL device
- buffer_handle_t *buffers = new buffer_handle_t[mTotalBuffers];
- ANativeWindowBuffer **anwBuffers = new ANativeWindowBuffer*[mTotalBuffers];
- uint32_t bufferIdx = 0;
- for (; bufferIdx < mTotalBuffers; bufferIdx++) {
- res = native_window_dequeue_buffer_and_wait(mConsumerInterface.get(),
- &anwBuffers[bufferIdx]);
- if (res != OK) {
- ALOGE("%s: Unable to dequeue buffer %d for initial registration for "
- "stream %d", __FUNCTION__, bufferIdx, mId);
- goto cleanUpBuffers;
- }
-
- buffers[bufferIdx] = anwBuffers[bufferIdx]->handle;
- ALOGV("%s: Buffer %p allocated", __FUNCTION__, (void*)buffers[bufferIdx]);
- }
-
- ALOGV("%s: Registering %d buffers with camera HAL", __FUNCTION__, mTotalBuffers);
- res = mHal2Device->ops->register_stream_buffers(mHal2Device,
- mId,
- mTotalBuffers,
- buffers);
- if (res != OK) {
- ALOGE("%s: Unable to register buffers with HAL device for stream %d",
- __FUNCTION__, mId);
- } else {
- mState = ACTIVE;
- }
-
-cleanUpBuffers:
- ALOGV("%s: Cleaning up %d buffers", __FUNCTION__, bufferIdx);
- for (uint32_t i = 0; i < bufferIdx; i++) {
- res = mConsumerInterface->cancelBuffer(mConsumerInterface.get(),
- anwBuffers[i], -1);
- if (res != OK) {
- ALOGE("%s: Unable to cancel buffer %d after registration",
- __FUNCTION__, i);
- }
- }
- delete[] anwBuffers;
- delete[] buffers;
-
- return res;
-}
-
-status_t Camera2Device::StreamAdapter::release() {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: Releasing stream %d (%d x %d, format %d)", __FUNCTION__, mId,
- mWidth, mHeight, mFormat);
- if (mState >= ALLOCATED) {
- res = mHal2Device->ops->release_stream(mHal2Device, mId);
- if (res != OK) {
- ALOGE("%s: Unable to release stream %d",
- __FUNCTION__, mId);
- return res;
- }
- }
- if (mState >= CONNECTED) {
- res = native_window_api_disconnect(mConsumerInterface.get(),
- NATIVE_WINDOW_API_CAMERA);
-
- /* this is not an error. if client calling process dies,
- the window will also die and all calls to it will return
- DEAD_OBJECT, thus it's already "disconnected" */
- if (res == DEAD_OBJECT) {
- ALOGW("%s: While disconnecting stream %d from native window, the"
- " native window died from under us", __FUNCTION__, mId);
- }
- else if (res != OK) {
- ALOGE("%s: Unable to disconnect stream %d from native window (error %d %s)",
- __FUNCTION__, mId, res, strerror(-res));
- return res;
- }
- }
- mId = -1;
- mState = RELEASED;
- return OK;
-}
-
-status_t Camera2Device::StreamAdapter::setTransform(int transform) {
- ATRACE_CALL();
- status_t res;
- if (mState < CONNECTED) {
- ALOGE("%s: Cannot set transform on unconnected stream", __FUNCTION__);
- return INVALID_OPERATION;
- }
- res = native_window_set_buffers_transform(mConsumerInterface.get(),
- transform);
- if (res != OK) {
- ALOGE("%s: Unable to configure stream transform to %x: %s (%d)",
- __FUNCTION__, transform, strerror(-res), res);
- }
- return res;
-}
-
-status_t Camera2Device::StreamAdapter::dump(int fd,
- const Vector<String16>& /*args*/) {
- ATRACE_CALL();
- String8 result = String8::format(" Stream %d: %d x %d, format 0x%x\n",
- mId, mWidth, mHeight, mFormat);
- result.appendFormat(" size %zu, usage 0x%x, requested format 0x%x\n",
- mSize, mUsage, mFormatRequested);
- result.appendFormat(" total buffers: %d, dequeued buffers: %d\n",
- mTotalBuffers, mActiveBuffers);
- result.appendFormat(" frame count: %d, last timestamp %" PRId64 "\n",
- mFrameCount, mLastTimestamp);
- write(fd, result.string(), result.size());
- return OK;
-}
-
-const camera2_stream_ops *Camera2Device::StreamAdapter::getStreamOps() {
- return static_cast<camera2_stream_ops *>(this);
-}
-
-ANativeWindow* Camera2Device::StreamAdapter::toANW(
- const camera2_stream_ops_t *w) {
- return static_cast<const StreamAdapter*>(w)->mConsumerInterface.get();
-}
-
-int Camera2Device::StreamAdapter::dequeue_buffer(const camera2_stream_ops_t *w,
- buffer_handle_t** buffer) {
- ATRACE_CALL();
- int res;
- StreamAdapter* stream =
- const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
- if (stream->mState != ACTIVE) {
- ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
- return INVALID_OPERATION;
- }
-
- ANativeWindow *a = toANW(w);
- ANativeWindowBuffer* anb;
- res = native_window_dequeue_buffer_and_wait(a, &anb);
- if (res != OK) {
- ALOGE("Stream %d dequeue: Error from native_window: %s (%d)", stream->mId,
- strerror(-res), res);
- return res;
- }
-
- *buffer = &(anb->handle);
- stream->mActiveBuffers++;
-
- ALOGVV("Stream %d dequeue: Buffer %p dequeued", stream->mId, (void*)(**buffer));
- return res;
-}
-
-int Camera2Device::StreamAdapter::enqueue_buffer(const camera2_stream_ops_t* w,
- int64_t timestamp,
- buffer_handle_t* buffer) {
- ATRACE_CALL();
- StreamAdapter *stream =
- const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
- stream->mFrameCount++;
- ALOGVV("Stream %d enqueue: Frame %d (%p) captured at %lld ns",
- stream->mId, stream->mFrameCount, (void*)(*buffer), timestamp);
- int state = stream->mState;
- if (state != ACTIVE) {
- ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
- return INVALID_OPERATION;
- }
- ANativeWindow *a = toANW(w);
- status_t err;
-
- err = native_window_set_buffers_timestamp(a, timestamp);
- if (err != OK) {
- ALOGE("%s: Error setting timestamp on native window: %s (%d)",
- __FUNCTION__, strerror(-err), err);
- return err;
- }
- err = a->queueBuffer(a,
- container_of(buffer, ANativeWindowBuffer, handle), -1);
- if (err != OK) {
- ALOGE("%s: Error queueing buffer to native window: %s (%d)",
- __FUNCTION__, strerror(-err), err);
- return err;
- }
-
- stream->mActiveBuffers--;
- stream->mLastTimestamp = timestamp;
- return OK;
-}
-
-int Camera2Device::StreamAdapter::cancel_buffer(const camera2_stream_ops_t* w,
- buffer_handle_t* buffer) {
- ATRACE_CALL();
- StreamAdapter *stream =
- const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
- ALOGVV("Stream %d cancel: Buffer %p",
- stream->mId, (void*)(*buffer));
- if (stream->mState != ACTIVE) {
- ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
- return INVALID_OPERATION;
- }
-
- ANativeWindow *a = toANW(w);
- int err = a->cancelBuffer(a,
- container_of(buffer, ANativeWindowBuffer, handle), -1);
- if (err != OK) {
- ALOGE("%s: Error canceling buffer to native window: %s (%d)",
- __FUNCTION__, strerror(-err), err);
- return err;
- }
-
- stream->mActiveBuffers--;
- return OK;
-}
-
-int Camera2Device::StreamAdapter::set_crop(const camera2_stream_ops_t* w,
- int left, int top, int right, int bottom) {
- ATRACE_CALL();
- int state = static_cast<const StreamAdapter*>(w)->mState;
- if (state != ACTIVE) {
- ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
- return INVALID_OPERATION;
- }
- ANativeWindow *a = toANW(w);
- android_native_rect_t crop = { left, top, right, bottom };
- return native_window_set_crop(a, &crop);
-}
-
-/**
- * Camera2Device::ReprocessStreamAdapter
- */
-
-#ifndef container_of
-#define container_of(ptr, type, member) \
- (type *)((char*)(ptr) - offsetof(type, member))
-#endif
-
-Camera2Device::ReprocessStreamAdapter::ReprocessStreamAdapter(camera2_device_t *d):
- mState(RELEASED),
- mHal2Device(d),
- mId(-1),
- mWidth(0), mHeight(0), mFormat(0),
- mActiveBuffers(0),
- mFrameCount(0)
-{
- ATRACE_CALL();
- camera2_stream_in_ops::acquire_buffer = acquire_buffer;
- camera2_stream_in_ops::release_buffer = release_buffer;
-}
-
-Camera2Device::ReprocessStreamAdapter::~ReprocessStreamAdapter() {
- ATRACE_CALL();
- if (mState != RELEASED) {
- release();
- }
-}
-
-status_t Camera2Device::ReprocessStreamAdapter::connectToDevice(
- const sp<StreamAdapter> &outputStream) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: E", __FUNCTION__);
-
- if (mState != RELEASED) return INVALID_OPERATION;
- if (outputStream == NULL) {
- ALOGE("%s: Null base stream passed to reprocess stream adapter",
- __FUNCTION__);
- return BAD_VALUE;
- }
-
- mBaseStream = outputStream;
- mWidth = outputStream->getWidth();
- mHeight = outputStream->getHeight();
- mFormat = outputStream->getFormat();
-
- ALOGV("%s: New reprocess stream parameters %d x %d, format 0x%x",
- __FUNCTION__, mWidth, mHeight, mFormat);
-
- // Allocate device-side stream interface
-
- uint32_t id;
- res = mHal2Device->ops->allocate_reprocess_stream_from_stream(mHal2Device,
- outputStream->getId(), getStreamOps(),
- &id);
- if (res != OK) {
- ALOGE("%s: Device reprocess stream allocation failed: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
-
- ALOGV("%s: Allocated reprocess stream id %d based on stream %d",
- __FUNCTION__, id, outputStream->getId());
-
- mId = id;
-
- mState = ACTIVE;
-
- return OK;
-}
-
-status_t Camera2Device::ReprocessStreamAdapter::release() {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: Releasing stream %d", __FUNCTION__, mId);
- if (mState >= ACTIVE) {
- res = mHal2Device->ops->release_reprocess_stream(mHal2Device, mId);
- if (res != OK) {
- ALOGE("%s: Unable to release stream %d",
- __FUNCTION__, mId);
- return res;
- }
- }
-
- List<QueueEntry>::iterator s;
- for (s = mQueue.begin(); s != mQueue.end(); s++) {
- sp<BufferReleasedListener> listener = s->releaseListener.promote();
- if (listener != 0) listener->onBufferReleased(s->handle);
- }
- for (s = mInFlightQueue.begin(); s != mInFlightQueue.end(); s++) {
- sp<BufferReleasedListener> listener = s->releaseListener.promote();
- if (listener != 0) listener->onBufferReleased(s->handle);
- }
- mQueue.clear();
- mInFlightQueue.clear();
-
- mState = RELEASED;
- return OK;
-}
-
-status_t Camera2Device::ReprocessStreamAdapter::pushIntoStream(
- buffer_handle_t *handle, const wp<BufferReleasedListener> &releaseListener) {
- ATRACE_CALL();
- // TODO: Some error checking here would be nice
- ALOGV("%s: Pushing buffer %p to stream", __FUNCTION__, (void*)(*handle));
-
- QueueEntry entry;
- entry.handle = handle;
- entry.releaseListener = releaseListener;
- mQueue.push_back(entry);
- return OK;
-}
-
-status_t Camera2Device::ReprocessStreamAdapter::dump(int fd,
- const Vector<String16>& /*args*/) {
- ATRACE_CALL();
- String8 result =
- String8::format(" Reprocess stream %d: %d x %d, fmt 0x%x\n",
- mId, mWidth, mHeight, mFormat);
- result.appendFormat(" acquired buffers: %d\n",
- mActiveBuffers);
- result.appendFormat(" frame count: %d\n",
- mFrameCount);
- write(fd, result.string(), result.size());
- return OK;
-}
-
-const camera2_stream_in_ops *Camera2Device::ReprocessStreamAdapter::getStreamOps() {
- return static_cast<camera2_stream_in_ops *>(this);
-}
-
-int Camera2Device::ReprocessStreamAdapter::acquire_buffer(
- const camera2_stream_in_ops_t *w,
- buffer_handle_t** buffer) {
- ATRACE_CALL();
-
- ReprocessStreamAdapter* stream =
- const_cast<ReprocessStreamAdapter*>(
- static_cast<const ReprocessStreamAdapter*>(w));
- if (stream->mState != ACTIVE) {
- ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
- return INVALID_OPERATION;
- }
-
- if (stream->mQueue.empty()) {
- *buffer = NULL;
- return OK;
- }
-
- QueueEntry &entry = *(stream->mQueue.begin());
-
- *buffer = entry.handle;
-
- stream->mInFlightQueue.push_back(entry);
- stream->mQueue.erase(stream->mQueue.begin());
-
- stream->mActiveBuffers++;
-
- ALOGV("Stream %d acquire: Buffer %p acquired", stream->mId,
- (void*)(**buffer));
- return OK;
-}
-
-int Camera2Device::ReprocessStreamAdapter::release_buffer(
- const camera2_stream_in_ops_t* w,
- buffer_handle_t* buffer) {
- ATRACE_CALL();
- ReprocessStreamAdapter *stream =
- const_cast<ReprocessStreamAdapter*>(
- static_cast<const ReprocessStreamAdapter*>(w) );
- stream->mFrameCount++;
- ALOGV("Reprocess stream %d release: Frame %d (%p)",
- stream->mId, stream->mFrameCount, (void*)*buffer);
- int state = stream->mState;
- if (state != ACTIVE) {
- ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
- return INVALID_OPERATION;
- }
- stream->mActiveBuffers--;
-
- List<QueueEntry>::iterator s;
- for (s = stream->mInFlightQueue.begin(); s != stream->mInFlightQueue.end(); s++) {
- if ( s->handle == buffer ) break;
- }
- if (s == stream->mInFlightQueue.end()) {
- ALOGE("%s: Can't find buffer %p in in-flight list!", __FUNCTION__,
- buffer);
- return INVALID_OPERATION;
- }
-
- sp<BufferReleasedListener> listener = s->releaseListener.promote();
- if (listener != 0) {
- listener->onBufferReleased(s->handle);
- } else {
- ALOGE("%s: Can't free buffer - missing listener", __FUNCTION__);
- }
- stream->mInFlightQueue.erase(s);
-
- return OK;
-}
-
-// camera 2 devices don't support reprocessing
-status_t Camera2Device::createInputStream(
- uint32_t width, uint32_t height, int format, int *id) {
- ALOGE("%s: camera 2 devices don't support reprocessing", __FUNCTION__);
- return INVALID_OPERATION;
-}
-
-// camera 2 devices don't support reprocessing
-status_t Camera2Device::getInputBufferProducer(
- sp<IGraphicBufferProducer> *producer) {
- ALOGE("%s: camera 2 devices don't support reprocessing", __FUNCTION__);
- return INVALID_OPERATION;
-}
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
deleted file mode 100644
index b4d343c..0000000
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Copyright (C) 2012 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_SERVERS_CAMERA_CAMERA2DEVICE_H
-#define ANDROID_SERVERS_CAMERA_CAMERA2DEVICE_H
-
-#include <utils/Condition.h>
-#include <utils/Errors.h>
-#include <utils/List.h>
-#include <utils/Mutex.h>
-
-#include "common/CameraDeviceBase.h"
-
-namespace android {
-
-/**
- * CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_2_0
- *
- * TODO for camera2 API implementation:
- * Does not produce notifyShutter / notifyIdle callbacks to NotificationListener
- * Use waitUntilDrained for idle.
- */
-class Camera2Device: public CameraDeviceBase {
- public:
- Camera2Device(int id);
-
- virtual ~Camera2Device();
-
- /**
- * CameraDevice interface
- */
- virtual int getId() const;
- virtual status_t initialize(CameraModule *module);
- virtual status_t disconnect();
- virtual status_t dump(int fd, const Vector<String16>& args);
- virtual const CameraMetadata& info() const;
- virtual status_t capture(CameraMetadata &request, int64_t *lastFrameNumber = NULL);
- virtual status_t captureList(const List<const CameraMetadata> &requests,
- int64_t *lastFrameNumber = NULL);
- virtual status_t setStreamingRequest(const CameraMetadata &request,
- int64_t *lastFrameNumber = NULL);
- virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests,
- int64_t *lastFrameNumber = NULL);
- virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL);
- virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
- virtual status_t createStream(sp<Surface> consumer,
- uint32_t width, uint32_t height, int format,
- android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id);
- virtual status_t createInputStream(
- uint32_t width, uint32_t height, int format, int *id);
- virtual status_t createReprocessStreamFromStream(int outputId, int *id);
- virtual status_t getStreamInfo(int id,
- uint32_t *width, uint32_t *height,
- uint32_t *format, android_dataspace *dataSpace);
- virtual status_t setStreamTransform(int id, int transform);
- virtual status_t deleteStream(int id);
- virtual status_t deleteReprocessStream(int id);
- // No-op on HAL2 devices
- virtual status_t configureStreams(bool isConstrainedHighSpeed = false);
- virtual status_t getInputBufferProducer(
- sp<IGraphicBufferProducer> *producer);
- virtual status_t createDefaultRequest(int templateId, CameraMetadata *request);
- virtual status_t waitUntilDrained();
- virtual status_t setNotifyCallback(NotificationListener *listener);
- virtual bool willNotify3A();
- virtual status_t waitForNextFrame(nsecs_t timeout);
- virtual status_t getNextResult(CaptureResult *frame);
- virtual status_t triggerAutofocus(uint32_t id);
- virtual status_t triggerCancelAutofocus(uint32_t id);
- virtual status_t triggerPrecaptureMetering(uint32_t id);
- virtual status_t pushReprocessBuffer(int reprocessStreamId,
- buffer_handle_t *buffer, wp<BufferReleasedListener> listener);
- // Flush implemented as just a wait
- virtual status_t flush(int64_t *lastFrameNumber = NULL);
- // Prepare and tearDown are no-ops
- virtual status_t prepare(int streamId);
- virtual status_t tearDown(int streamId);
- virtual status_t prepare(int maxCount, int streamId);
-
- virtual uint32_t getDeviceVersion();
- virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
-
- private:
- const int mId;
- camera2_device_t *mHal2Device;
-
- CameraMetadata mDeviceInfo;
-
- uint32_t mDeviceVersion;
-
- /**
- * Queue class for both sending requests to a camera2 device, and for
- * receiving frames from a camera2 device.
- */
- class MetadataQueue: public camera2_request_queue_src_ops_t,
- public camera2_frame_queue_dst_ops_t {
- public:
- MetadataQueue();
- ~MetadataQueue();
-
- // Interface to camera2 HAL device, either for requests (device is
- // consumer) or for frames (device is producer)
- const camera2_request_queue_src_ops_t* getToConsumerInterface();
- void setFromConsumerInterface(camera2_device_t *d);
-
- // Connect queue consumer endpoint to a camera2 device
- status_t setConsumerDevice(camera2_device_t *d);
- // Connect queue producer endpoint to a camera2 device
- status_t setProducerDevice(camera2_device_t *d);
-
- const camera2_frame_queue_dst_ops_t* getToProducerInterface();
-
- // Real interfaces. On enqueue, queue takes ownership of buffer pointer
- // On dequeue, user takes ownership of buffer pointer.
- status_t enqueue(camera_metadata_t *buf);
- status_t dequeue(camera_metadata_t **buf, bool incrementCount = false);
- int getBufferCount();
- status_t waitForBuffer(nsecs_t timeout);
- // Wait until a buffer with the given ID is dequeued. Will return
- // immediately if the latest buffer dequeued has that ID.
- status_t waitForDequeue(int32_t id, nsecs_t timeout);
-
- // Set repeating buffer(s); if the queue is empty on a dequeue call, the
- // queue copies the contents of the stream slot into the queue, and then
- // dequeues the first new entry. The methods take the ownership of the
- // metadata buffers passed in.
- status_t setStreamSlot(camera_metadata_t *buf);
- status_t setStreamSlot(const List<camera_metadata_t*> &bufs);
-
- // Clear the request queue and the streaming slot
- status_t clear();
-
- status_t dump(int fd, const Vector<String16>& args);
-
- private:
- status_t signalConsumerLocked();
- status_t freeBuffers(List<camera_metadata_t*>::iterator start,
- List<camera_metadata_t*>::iterator end);
-
- camera2_device_t *mHal2Device;
-
- Mutex mMutex;
- Condition notEmpty;
-
- int mFrameCount;
- int32_t mLatestRequestId;
- Condition mNewRequestId;
-
- int mCount;
- List<camera_metadata_t*> mEntries;
- int mStreamSlotCount;
- List<camera_metadata_t*> mStreamSlot;
-
- bool mSignalConsumer;
-
- static MetadataQueue* getInstance(
- const camera2_frame_queue_dst_ops_t *q);
- static MetadataQueue* getInstance(
- const camera2_request_queue_src_ops_t *q);
-
- static int consumer_buffer_count(
- const camera2_request_queue_src_ops_t *q);
-
- static int consumer_dequeue(const camera2_request_queue_src_ops_t *q,
- camera_metadata_t **buffer);
-
- static int consumer_free(const camera2_request_queue_src_ops_t *q,
- camera_metadata_t *old_buffer);
-
- static int producer_dequeue(const camera2_frame_queue_dst_ops_t *q,
- size_t entries, size_t bytes,
- camera_metadata_t **buffer);
-
- static int producer_cancel(const camera2_frame_queue_dst_ops_t *q,
- camera_metadata_t *old_buffer);
-
- static int producer_enqueue(const camera2_frame_queue_dst_ops_t *q,
- camera_metadata_t *filled_buffer);
-
- }; // class MetadataQueue
-
- MetadataQueue mRequestQueue;
- MetadataQueue mFrameQueue;
-
- /**
- * Adapter from an ANativeWindow interface to camera2 device stream ops.
- * Also takes care of allocating/deallocating stream in device interface
- */
- class StreamAdapter: public camera2_stream_ops, public virtual RefBase {
- public:
- StreamAdapter(camera2_device_t *d);
-
- ~StreamAdapter();
-
- /**
- * Create a HAL device stream of the requested size and format.
- *
- * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device
- * selects an appropriate format; it can be queried with getFormat.
- *
- * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must
- * be equal to the size in bytes of the buffers to allocate for the
- * stream. For other formats, the size parameter is ignored.
- */
- status_t connectToDevice(sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, size_t size);
-
- status_t release();
-
- status_t setTransform(int transform);
-
- // Get stream parameters.
- // Only valid after a successful connectToDevice call.
- int getId() const { return mId; }
- uint32_t getWidth() const { return mWidth; }
- uint32_t getHeight() const { return mHeight; }
- uint32_t getFormat() const { return mFormat; }
-
- // Dump stream information
- status_t dump(int fd, const Vector<String16>& args);
-
- private:
- enum {
- ERROR = -1,
- RELEASED = 0,
- ALLOCATED,
- CONNECTED,
- ACTIVE
- } mState;
-
- sp<ANativeWindow> mConsumerInterface;
- camera2_device_t *mHal2Device;
-
- uint32_t mId;
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mFormat;
- size_t mSize;
- uint32_t mUsage;
- uint32_t mMaxProducerBuffers;
- uint32_t mMaxConsumerBuffers;
- uint32_t mTotalBuffers;
- int mFormatRequested;
-
- /** Debugging information */
- uint32_t mActiveBuffers;
- uint32_t mFrameCount;
- int64_t mLastTimestamp;
-
- const camera2_stream_ops *getStreamOps();
-
- static ANativeWindow* toANW(const camera2_stream_ops_t *w);
-
- static int dequeue_buffer(const camera2_stream_ops_t *w,
- buffer_handle_t** buffer);
-
- static int enqueue_buffer(const camera2_stream_ops_t* w,
- int64_t timestamp,
- buffer_handle_t* buffer);
-
- static int cancel_buffer(const camera2_stream_ops_t* w,
- buffer_handle_t* buffer);
-
- static int set_crop(const camera2_stream_ops_t* w,
- int left, int top, int right, int bottom);
- }; // class StreamAdapter
-
- typedef List<sp<StreamAdapter> > StreamList;
- StreamList mStreams;
-
- /**
- * Adapter from an ANativeWindow interface to camera2 device stream ops.
- * Also takes care of allocating/deallocating stream in device interface
- */
- class ReprocessStreamAdapter: public camera2_stream_in_ops, public virtual RefBase {
- public:
- ReprocessStreamAdapter(camera2_device_t *d);
-
- ~ReprocessStreamAdapter();
-
- /**
- * Create a HAL device reprocess stream based on an existing output stream.
- */
- status_t connectToDevice(const sp<StreamAdapter> &outputStream);
-
- status_t release();
-
- /**
- * Push buffer into stream for reprocessing. Takes ownership until it notifies
- * that the buffer has been released
- */
- status_t pushIntoStream(buffer_handle_t *handle,
- const wp<BufferReleasedListener> &releaseListener);
-
- /**
- * Get stream parameters.
- * Only valid after a successful connectToDevice call.
- */
- int getId() const { return mId; }
- uint32_t getWidth() const { return mWidth; }
- uint32_t getHeight() const { return mHeight; }
- uint32_t getFormat() const { return mFormat; }
-
- // Dump stream information
- status_t dump(int fd, const Vector<String16>& args);
-
- private:
- enum {
- ERROR = -1,
- RELEASED = 0,
- ACTIVE
- } mState;
-
- sp<ANativeWindow> mConsumerInterface;
- wp<StreamAdapter> mBaseStream;
-
- struct QueueEntry {
- buffer_handle_t *handle;
- wp<BufferReleasedListener> releaseListener;
- };
-
- List<QueueEntry> mQueue;
-
- List<QueueEntry> mInFlightQueue;
-
- camera2_device_t *mHal2Device;
-
- uint32_t mId;
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mFormat;
-
- /** Debugging information */
- uint32_t mActiveBuffers;
- uint32_t mFrameCount;
- int64_t mLastTimestamp;
-
- const camera2_stream_in_ops *getStreamOps();
-
- static int acquire_buffer(const camera2_stream_in_ops_t *w,
- buffer_handle_t** buffer);
-
- static int release_buffer(const camera2_stream_in_ops_t* w,
- buffer_handle_t* buffer);
-
- }; // class ReprocessStreamAdapter
-
- typedef List<sp<ReprocessStreamAdapter> > ReprocessStreamList;
- ReprocessStreamList mReprocessStreams;
-
- // Receives HAL notifications and routes them to the NotificationListener
- static void notificationCallback(int32_t msg_type,
- int32_t ext1,
- int32_t ext2,
- int32_t ext3,
- void *user);
-
-}; // class Camera2Device
-
-}; // namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
new file mode 100644
index 0000000..ae20887
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
@@ -0,0 +1,438 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Camera3-BufferManager"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <gui/ISurfaceComposer.h>
+#include <private/gui/ComposerService.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include "utils/CameraTraces.h"
+#include "Camera3BufferManager.h"
+
+namespace android {
+
+namespace camera3 {
+
+Camera3BufferManager::Camera3BufferManager(const sp<IGraphicBufferAlloc>& allocator) :
+ mAllocator(allocator) {
+ if (allocator == NULL) {
+ sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+ mAllocator = composer->createGraphicBufferAlloc();
+ if (mAllocator == NULL) {
+ ALOGE("createGraphicBufferAlloc failed");
+ }
+ }
+}
+
+Camera3BufferManager::~Camera3BufferManager() {
+}
+
+status_t Camera3BufferManager::registerStream(const StreamInfo& streamInfo) {
+ ATRACE_CALL();
+
+ int streamId = streamInfo.streamId;
+ int streamSetId = streamInfo.streamSetId;
+
+ if (streamId == CAMERA3_STREAM_ID_INVALID || streamSetId == CAMERA3_STREAM_SET_ID_INVALID) {
+ ALOGE("%s: Stream id (%d) or stream set id (%d) is invalid",
+ __FUNCTION__, streamId, streamSetId);
+ return BAD_VALUE;
+ }
+ if (streamInfo.totalBufferCount > kMaxBufferCount || streamInfo.totalBufferCount == 0) {
+ ALOGE("%s: Stream id (%d) with stream set id (%d) total buffer count %zu is invalid",
+ __FUNCTION__, streamId, streamSetId, streamInfo.totalBufferCount);
+ return BAD_VALUE;
+ }
+ if (!streamInfo.isConfigured) {
+ ALOGE("%s: Stream (%d) is not configured", __FUNCTION__, streamId);
+ return BAD_VALUE;
+ }
+
+ // For Gralloc v1, try to allocate a buffer and see if it is successful, otherwise, stream
+ // buffer sharing for this newly added stream is not supported. For Gralloc v0, we don't
+ // need check this, as the buffers are not really shared between streams, the buffers are
+ // allocated for each stream individually, the allocation failure will be checked in
+ // getBufferForStream() call.
+ if (mGrallocVersion > HARDWARE_DEVICE_API_VERSION(0,1)) {
+ // TODO: To be implemented.
+
+ // In case allocation fails, return invalid operation
+ return INVALID_OPERATION;
+ }
+
+ Mutex::Autolock l(mLock);
+ if (mAllocator == NULL) {
+ ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ // Check if this stream was registered with different stream set ID, if so, error out.
+ for (size_t i = 0; i < mStreamSetMap.size(); i++) {
+ ssize_t streamIdx = mStreamSetMap[i].streamInfoMap.indexOfKey(streamId);
+ if (streamIdx != NAME_NOT_FOUND &&
+ mStreamSetMap[i].streamInfoMap[streamIdx].streamSetId != streamInfo.streamSetId) {
+ ALOGE("%s: It is illegal to register the same stream id with different stream set",
+ __FUNCTION__);
+ return BAD_VALUE;
+ }
+ }
+ // Check if there is an existing stream set registered; if not, create one; otherwise, add this
+ // stream info to the existing stream set entry.
+ ssize_t setIdx = mStreamSetMap.indexOfKey(streamSetId);
+ if (setIdx == NAME_NOT_FOUND) {
+ ALOGV("%s: stream set %d is not registered to stream set map yet, create it.",
+ __FUNCTION__, streamSetId);
+ // Create stream info map, then add to mStreamsetMap.
+ StreamSet newStreamSet;
+ setIdx = mStreamSetMap.add(streamSetId, newStreamSet);
+ }
+ // Update stream set map and water mark.
+ StreamSet& currentStreamSet = mStreamSetMap.editValueAt(setIdx);
+ ssize_t streamIdx = currentStreamSet.streamInfoMap.indexOfKey(streamId);
+ if (streamIdx != NAME_NOT_FOUND) {
+ ALOGW("%s: stream %d was already registered with stream set %d",
+ __FUNCTION__, streamId, streamSetId);
+ return OK;
+ }
+ currentStreamSet.streamInfoMap.add(streamId, streamInfo);
+ currentStreamSet.handoutBufferCountMap.add(streamId, 0);
+
+ // The max allowed buffer count should be the max of buffer count of each stream inside a stream
+ // set.
+ if (streamInfo.totalBufferCount > currentStreamSet.maxAllowedBufferCount) {
+ currentStreamSet.maxAllowedBufferCount = streamInfo.totalBufferCount;
+ }
+
+ return OK;
+}
+
+status_t Camera3BufferManager::unregisterStream(int streamId, int streamSetId) {
+ ATRACE_CALL();
+ Mutex::Autolock l(mLock);
+ ALOGV("%s: unregister stream %d with stream set %d", __FUNCTION__,
+ streamId, streamSetId);
+ if (mAllocator == NULL) {
+ ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ if (!checkIfStreamRegisteredLocked(streamId, streamSetId)){
+ ALOGE("%s: stream %d with set id %d wasn't properly registered to this buffer manager!",
+ __FUNCTION__, streamId, streamSetId);
+ return BAD_VALUE;
+ }
+
+ // De-list all the buffers associated with this stream first.
+ StreamSet& currentSet = mStreamSetMap.editValueFor(streamSetId);
+ BufferList& freeBufs = currentSet.freeBuffers;
+ BufferCountMap& handOutBufferCounts = currentSet.handoutBufferCountMap;
+ InfoMap& infoMap = currentSet.streamInfoMap;
+ removeBuffersFromBufferListLocked(freeBufs, streamId);
+ handOutBufferCounts.removeItem(streamId);
+
+ // Remove the stream info from info map and recalculate the buffer count water mark.
+ infoMap.removeItem(streamId);
+ currentSet.maxAllowedBufferCount = 0;
+ for (size_t i = 0; i < infoMap.size(); i++) {
+ if (infoMap[i].totalBufferCount > currentSet.maxAllowedBufferCount) {
+ currentSet.maxAllowedBufferCount = infoMap[i].totalBufferCount;
+ }
+ }
+ // Lazy solution: when a stream is unregistered, the streams will be reconfigured, reset
+ // the water mark and let it grow again.
+ currentSet.allocatedBufferWaterMark = 0;
+
+ // Remove this stream set if all its streams have been removed.
+ if (freeBufs.size() == 0 && handOutBufferCounts.size() == 0 && infoMap.size() == 0) {
+ mStreamSetMap.removeItem(streamSetId);
+ }
+
+ return OK;
+}
+
+status_t Camera3BufferManager::getBufferForStream(int streamId, int streamSetId,
+ sp<GraphicBuffer>* gb, int* fenceFd) {
+ ATRACE_CALL();
+
+ Mutex::Autolock l(mLock);
+ ALOGV("%s: get buffer for stream %d with stream set %d", __FUNCTION__,
+ streamId, streamSetId);
+ if (mAllocator == NULL) {
+ ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ if (!checkIfStreamRegisteredLocked(streamId, streamSetId)) {
+ ALOGE("%s: stream %d is not registered with stream set %d yet!!!",
+ __FUNCTION__, streamId, streamSetId);
+ return BAD_VALUE;
+ }
+
+ StreamSet &streamSet = mStreamSetMap.editValueFor(streamSetId);
+ BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap;
+ size_t& bufferCount = handOutBufferCounts.editValueFor(streamId);
+ if (bufferCount >= streamSet.maxAllowedBufferCount) {
+ ALOGE("%s: bufferCount (%zu) exceeds the max allowed buffer count (%zu) of this stream set",
+ __FUNCTION__, bufferCount, streamSet.maxAllowedBufferCount);
+ return INVALID_OPERATION;
+ }
+
+ GraphicBufferEntry buffer =
+ getFirstBufferFromBufferListLocked(streamSet.freeBuffers, streamId);
+
+ if (mGrallocVersion < HARDWARE_DEVICE_API_VERSION(1,0)) {
+ // Allocate one if there is no free buffer available.
+ if (buffer.graphicBuffer == nullptr) {
+ const StreamInfo& info = streamSet.streamInfoMap.valueFor(streamId);
+ status_t res = OK;
+ buffer.fenceFd = -1;
+ buffer.graphicBuffer = mAllocator->createGraphicBuffer(
+ info.width, info.height, info.format, info.combinedUsage, &res);
+ ALOGV("%s: allocating a new graphic buffer (%dx%d, format 0x%x) %p with handle %p",
+ __FUNCTION__, info.width, info.height, info.format,
+ buffer.graphicBuffer.get(), buffer.graphicBuffer->handle);
+ if (res != OK) {
+ ALOGE("%s: graphic buffer allocation failed: (error %d %s) ",
+ __FUNCTION__, res, strerror(-res));
+ return res;
+ }
+ ALOGV("%s: allocation done", __FUNCTION__);
+ }
+
+ // Increase the hand-out buffer count for tracking purpose.
+ bufferCount++;
+ // Update the water mark to be the max hand-out buffer count + 1. An additional buffer is
+ // added to reduce the chance of buffer allocation during stream steady state, especially
+ // for cases where one stream is active, the other stream may request some buffers randomly.
+ if (bufferCount + 1 > streamSet.allocatedBufferWaterMark) {
+ streamSet.allocatedBufferWaterMark = bufferCount + 1;
+ }
+ *gb = buffer.graphicBuffer;
+ *fenceFd = buffer.fenceFd;
+ ALOGV("%s: get buffer (%p) with handle (%p).",
+ __FUNCTION__, buffer.graphicBuffer.get(), buffer.graphicBuffer->handle);
+
+ // Proactively free buffers for other streams if the current number of allocated buffers
+ // exceeds the water mark. This only for Gralloc V1, for V2, this logic can also be handled
+ // in returnBufferForStream() if we want to free buffer more quickly.
+ // TODO: probably should find out all the inactive stream IDs, and free the firstly found
+ // buffers for them.
+ StreamId firstOtherStreamId = CAMERA3_STREAM_ID_INVALID;
+ if (streamSet.streamInfoMap.size() > 1) {
+ for (size_t i = 0; i < streamSet.streamInfoMap.size(); i++) {
+ firstOtherStreamId = streamSet.streamInfoMap[i].streamId;
+ if (firstOtherStreamId != streamId &&
+ hasBufferForStreamLocked(streamSet.freeBuffers, firstOtherStreamId)) {
+ break;
+ }
+ }
+ if (firstOtherStreamId == CAMERA3_STREAM_ID_INVALID) {
+ return OK;
+ }
+
+ // This will drop the reference to one free buffer, which will effectively free one
+ // buffer (from the free buffer list) for the inactive streams.
+ size_t totalAllocatedBufferCount = streamSet.freeBuffers.size();
+ for (size_t i = 0; i < streamSet.handoutBufferCountMap.size(); i++) {
+ totalAllocatedBufferCount += streamSet.handoutBufferCountMap[i];
+ }
+ if (totalAllocatedBufferCount > streamSet.allocatedBufferWaterMark) {
+ ALOGV("%s: free a buffer from stream %d", __FUNCTION__, firstOtherStreamId);
+ getFirstBufferFromBufferListLocked(streamSet.freeBuffers, firstOtherStreamId);
+ }
+ }
+ } else {
+ // TODO: implement this.
+ return BAD_VALUE;
+ }
+
+ return OK;
+}
+
+status_t Camera3BufferManager::returnBufferForStream(int streamId,
+ int streamSetId, const sp<GraphicBuffer>& buffer, int fenceFd) {
+ ATRACE_CALL();
+ Mutex::Autolock l(mLock);
+ ALOGV_IF(buffer != 0, "%s: return buffer (%p) with handle (%p) for stream %d and stream set %d",
+ __FUNCTION__, buffer.get(), buffer->handle, streamId, streamSetId);
+ if (mAllocator == NULL) {
+ ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ if (!checkIfStreamRegisteredLocked(streamId, streamSetId)){
+ ALOGV("%s: returning buffer for an already unregistered stream (stream %d with set id %d),"
+ "buffer will be dropped right away!", __FUNCTION__, streamId, streamSetId);
+ return OK;
+ }
+
+ if (mGrallocVersion < HARDWARE_DEVICE_API_VERSION(1,0)) {
+ // Add to the freeBuffer list.
+ StreamSet& streamSet = mStreamSetMap.editValueFor(streamSetId);
+ if (buffer != 0) {
+ BufferEntry entry;
+ entry.add(streamId, GraphicBufferEntry(buffer, fenceFd));
+ status_t res = addBufferToBufferListLocked(streamSet.freeBuffers, entry);
+ if (res != OK) {
+ ALOGE("%s: add buffer to free buffer list failed", __FUNCTION__);
+ return res;
+ }
+ }
+
+ // Update the hand-out buffer count for this buffer.
+ BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap;
+ size_t& bufferCount = handOutBufferCounts.editValueFor(streamId);
+ bufferCount--;
+ } else {
+ // TODO: implement this.
+ return BAD_VALUE;
+ }
+
+ return OK;
+}
+
+void Camera3BufferManager::dump(int fd, const Vector<String16>& args) const {
+ Mutex::Autolock l(mLock);
+
+ (void) args;
+ String8 lines;
+ lines.appendFormat(" Total stream sets: %zu\n", mStreamSetMap.size());
+ for (size_t i = 0; i < mStreamSetMap.size(); i++) {
+ lines.appendFormat(" Stream set %d has below streams:\n", mStreamSetMap.keyAt(i));
+ for (size_t j = 0; j < mStreamSetMap[i].streamInfoMap.size(); j++) {
+ lines.appendFormat(" Stream %d\n", mStreamSetMap[i].streamInfoMap[j].streamId);
+ }
+ lines.appendFormat(" Stream set max allowed buffer count: %zu\n",
+ mStreamSetMap[i].maxAllowedBufferCount);
+ lines.appendFormat(" Stream set buffer count water mark: %zu\n",
+ mStreamSetMap[i].allocatedBufferWaterMark);
+ lines.appendFormat(" Handout buffer counts:\n");
+ for (size_t m = 0; m < mStreamSetMap[i].handoutBufferCountMap.size(); m++) {
+ int streamId = mStreamSetMap[i].handoutBufferCountMap.keyAt(m);
+ size_t bufferCount = mStreamSetMap[i].handoutBufferCountMap.valueAt(m);
+ lines.appendFormat(" stream id: %d, buffer count: %zu.\n",
+ streamId, bufferCount);
+ }
+
+ lines.appendFormat(" Free buffer count: %zu\n",
+ mStreamSetMap[i].freeBuffers.size());
+ for (auto& bufEntry : mStreamSetMap[i].freeBuffers) {
+ for (size_t m = 0; m < bufEntry.size(); m++) {
+ const sp<GraphicBuffer>& buffer = bufEntry.valueAt(m).graphicBuffer;
+ int streamId = bufEntry.keyAt(m);
+ lines.appendFormat(" stream id: %d, buffer: %p, handle: %p.\n",
+ streamId, buffer.get(), buffer->handle);
+ }
+ }
+ }
+ write(fd, lines.string(), lines.size());
+}
+
+bool Camera3BufferManager::checkIfStreamRegisteredLocked(int streamId, int streamSetId) const {
+ ssize_t setIdx = mStreamSetMap.indexOfKey(streamSetId);
+ if (setIdx == NAME_NOT_FOUND) {
+ ALOGV("%s: stream set %d is not registered to stream set map yet!",
+ __FUNCTION__, streamSetId);
+ return false;
+ }
+
+ ssize_t streamIdx = mStreamSetMap.valueAt(setIdx).streamInfoMap.indexOfKey(streamId);
+ if (streamIdx == NAME_NOT_FOUND) {
+ ALOGV("%s: stream %d is not registered to stream info map yet!", __FUNCTION__, streamId);
+ return false;
+ }
+
+ size_t bufferWaterMark = mStreamSetMap[setIdx].maxAllowedBufferCount;
+ if (bufferWaterMark == 0 || bufferWaterMark > kMaxBufferCount) {
+ ALOGW("%s: stream %d with stream set %d is not registered correctly to stream set map,"
+ " as the water mark (%zu) is wrong!",
+ __FUNCTION__, streamId, streamSetId, bufferWaterMark);
+ return false;
+ }
+
+ return true;
+}
+
+status_t Camera3BufferManager::addBufferToBufferListLocked(BufferList& bufList,
+ const BufferEntry& buffer) {
+ // TODO: need add some sanity check here.
+ bufList.push_back(buffer);
+
+ return OK;
+}
+
+status_t Camera3BufferManager::removeBuffersFromBufferListLocked(BufferList& bufferList,
+ int streamId) {
+ BufferList::iterator i = bufferList.begin();
+ while (i != bufferList.end()) {
+ ssize_t idx = i->indexOfKey(streamId);
+ if (idx != NAME_NOT_FOUND) {
+ ALOGV("%s: Remove a buffer for stream %d, free buffer total count: %zu",
+ __FUNCTION__, streamId, bufferList.size());
+ i->removeItem(streamId);
+ if (i->isEmpty()) {
+ i = bufferList.erase(i);
+ }
+ } else {
+ i++;
+ }
+ }
+
+ ALOGW_IF(i == bufferList.end(), "%s: Unable to find buffers for stream %d",
+ __FUNCTION__, streamId);
+
+ return OK;
+}
+
+bool Camera3BufferManager::hasBufferForStreamLocked(BufferList& buffers, int streamId) {
+ BufferList::iterator i = buffers.begin();
+ while (i != buffers.end()) {
+ ssize_t idx = i->indexOfKey(streamId);
+ if (idx != NAME_NOT_FOUND) {
+ return true;
+ }
+ i++;
+ }
+
+ return false;
+}
+
+Camera3BufferManager::GraphicBufferEntry Camera3BufferManager::getFirstBufferFromBufferListLocked(
+ BufferList& buffers, int streamId) {
+ // Try to get the first buffer from the free buffer list if there is one.
+ GraphicBufferEntry entry;
+ BufferList::iterator i = buffers.begin();
+ while (i != buffers.end()) {
+ ssize_t idx = i->indexOfKey(streamId);
+ if (idx != NAME_NOT_FOUND) {
+ entry = GraphicBufferEntry(i->valueAt(idx));
+ i = buffers.erase(i);
+ break;
+ } else {
+ i++;
+ }
+ }
+
+ ALOGV_IF(entry.graphicBuffer == 0, "%s: Unable to find free buffer for stream %d",
+ __FUNCTION__, streamId);
+ return entry;
+}
+
+} // namespace camera3
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.h b/services/camera/libcameraservice/device3/Camera3BufferManager.h
new file mode 100644
index 0000000..7942ae6
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.h
@@ -0,0 +1,307 @@
+/*
+ * 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 ANDROID_SERVERS_CAMERA3_BUFFER_MANAGER_H
+#define ANDROID_SERVERS_CAMERA3_BUFFER_MANAGER_H
+
+#include <list>
+#include <algorithm>
+#include <ui/GraphicBuffer.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include "Camera3OutputStream.h"
+
+namespace android {
+
+namespace camera3 {
+
+struct StreamInfo;
+
+/**
+ * A class managing the graphic buffers that is used by camera output streams. It allocates and
+ * hands out Gralloc buffers to the clients (e.g., Camera3OutputStream) based on the requests.
+ * When clients request a buffer, buffer manager will pick a buffer if there are some already
+ * allocated buffer available, will allocate a buffer otherwise. When there are too many allocated
+ * buffer maintained by the buffer manager, it will dynamically deallocate some buffers that are
+ * solely owned by this buffer manager.
+ * In doing so, it reduces the memory footprint unless it is already minimal without impacting
+ * performance.
+ *
+ */
+class Camera3BufferManager: public virtual RefBase {
+public:
+ Camera3BufferManager(const sp<IGraphicBufferAlloc>& allocator = NULL);
+
+ virtual ~Camera3BufferManager();
+
+ /**
+ * This method registers an output stream to this buffer manager by using the provided stream
+ * information.
+ *
+ * The stream info includes the necessary information such as stream size, format, buffer count,
+ * usage flags, etc. for the buffer manager to allocate and hand out buffers for this stream.
+ *
+ * It's illegal to call this method if the stream is not CONFIGURED yet, as some critical
+ * stream properties (e.g., combined usage flags) are only available in this state. It is also
+ * illegal to call this method with an invalid stream set ID (CAMERA3_STREAM_SET_ID_INVALID),
+ * as the invalid stream set ID indicates that this stream doesn't intend to use buffer manager.
+ *
+ *
+ * Once a stream is successfully registered to this buffer manager, the buffer manager takes
+ * over the buffer allocation role and provides buffers to this stream via getBufferForStream().
+ * The returned buffer can be sent to the camera HAL for image output, and then queued to the
+ * ANativeWindow (Surface) for downstream consumer to acquire. Once the image buffer is released
+ * by the consumer end point, the BufferQueueProducer callback onBufferReleased will call
+ * returnBufferForStream() to return the free buffer to this buffer manager. If the stream
+ * uses buffer manager to manage the stream buffers, it should disable the BufferQueue
+ * allocation via IGraphicBufferProducer::allowAllocation(false).
+ *
+ * Registering an already registered stream has no effect.
+ *
+ * Return values:
+ *
+ * OK: Registration of the new stream was successful.
+ * BAD_VALUE: This stream is not at CONFIGURED state, or the stream ID or stream set
+ * ID are invalid, or attempting to register the same stream to multiple
+ * stream sets, or other stream properties are invalid.
+ * INVALID_OPERATION: This buffer manager doesn't support buffer sharing across this stream
+ * and other streams that were already registered with the same stream set
+ * ID.
+ */
+ status_t registerStream(const StreamInfo &streamInfo);
+
+ /**
+ * This method unregisters a stream from this buffer manager.
+ *
+ * After a stream is unregistered, further getBufferForStream() calls will fail for this stream.
+ * After all streams for a given stream set are unregistered, all the buffers solely owned (for
+ * this stream set) by this buffer manager will be freed; all buffers subsequently returned to
+ * this buffer manager for this stream set will be freed immediately.
+ *
+ * Return values:
+ *
+ * OK: Removal of the a stream from this buffer manager was successful.
+ * BAD_VALUE: stream ID or stream set ID are invalid, or stream ID and stream set ID
+ * combination doesn't match what was registered, or this stream wasn't registered
+ * to this buffer manager before.
+ */
+ status_t unregisterStream(int streamId, int streamSetId);
+
+ /**
+ * This method obtains a buffer for a stream from this buffer manager.
+ *
+ * This method returns the first free buffer from the free buffer list (associated with this
+ * stream set) if there is any. Otherwise, it will allocate a buffer for this stream, return
+ * it and increment its count of handed-out buffers. When the total number of allocated buffers
+ * is too high, it may deallocate the unused buffers to save memory footprint of this stream
+ * set.
+ *
+ * After this call, the client takes over the ownership of this buffer if it is not freed.
+ *
+ * Return values:
+ *
+ * OK: Getting buffer for this stream was successful.
+ * BAD_VALUE: stream ID or streamSetId are invalid, or stream ID and stream set ID
+ * combination doesn't match what was registered, or this stream wasn't registered
+ * to this buffer manager before.
+ * NO_MEMORY: Unable to allocate a buffer for this stream at this time.
+ */
+ status_t getBufferForStream(int streamId, int streamSetId, sp<GraphicBuffer>* gb, int* fenceFd);
+
+ /**
+ * This method returns a buffer for a stream to this buffer manager.
+ *
+ * When a buffer is returned, it is treated as a free buffer and may either be reused for future
+ * getBufferForStream() calls, or freed if there total number of outstanding allocated buffers
+ * is too large. The latter only applies to the case where the buffer are physically shared
+ * between streams in the same stream set. A physically shared buffer is the buffer that has one
+ * physical back store but multiple handles. Multiple stream can access the same physical memory
+ * with their own handles. Physically shared buffer can only be supported by Gralloc HAL V1.
+ * See hardware/libhardware/include/hardware/gralloc1.h for more details.
+ *
+ *
+ * This call takes the ownership of the returned buffer if it was allocated by this buffer
+ * manager; clients should not use this buffer after this call. Attempting to access this buffer
+ * after this call will have undefined behavior. Holding a reference to this buffer after this
+ * call may cause memory leakage. If a BufferQueue is used to track the buffers handed out by
+ * this buffer queue, it is recommended to call detachNextBuffer() from the buffer queue after
+ * BufferQueueProducer onBufferReleased callback is fired, and return it to this buffer manager.
+ *
+ * OK: Buffer return for this stream was successful.
+ * BAD_VALUE: stream ID or streamSetId are invalid, or stream ID and stream set ID combination
+ * doesn't match what was registered, or this stream wasn't registered to this
+ * buffer manager before.
+ */
+ status_t returnBufferForStream(int streamId, int streamSetId, const sp<GraphicBuffer>& buffer,
+ int fenceFd);
+
+ /**
+ * Dump the buffer manager statistics.
+ */
+ void dump(int fd, const Vector<String16> &args) const;
+
+private:
+ /**
+ * Lock to synchronize the access to the methods of this class.
+ */
+ mutable Mutex mLock;
+
+ static const size_t kMaxBufferCount = BufferQueueDefs::NUM_BUFFER_SLOTS;
+
+ /**
+ * mAllocator is the connection to SurfaceFlinger that is used to allocate new GraphicBuffer
+ * objects.
+ */
+ sp<IGraphicBufferAlloc> mAllocator;
+
+ struct GraphicBufferEntry {
+ sp<GraphicBuffer> graphicBuffer;
+ int fenceFd;
+ GraphicBufferEntry(const sp<GraphicBuffer>& gb = 0, int fd = -1) :
+ graphicBuffer(gb),
+ fenceFd(fd) {}
+ };
+
+ /**
+ * A buffer entry (indexed by stream ID) represents a single physically allocated buffer. For
+ * Gralloc V0, since each physical buffer is associated with one stream, this is
+ * a single entry map. For Gralloc V1, one physical buffer can be shared between different
+ * streams in one stream set, so this entry may include multiple entries, where the different
+ * graphic buffers have the same common Gralloc backing store.
+ */
+ typedef int StreamId;
+ typedef KeyedVector<StreamId, GraphicBufferEntry> BufferEntry;
+
+ typedef std::list<BufferEntry> BufferList;
+
+ /**
+ * Stream info map (indexed by stream ID) tracks all the streams registered to a particular
+ * stream set.
+ */
+ typedef KeyedVector<StreamId, StreamInfo> InfoMap;
+
+ /**
+ * Stream set buffer count map (indexed by stream ID) tracks all buffer counts of the streams
+ * registered to a particular stream set.
+ */
+ typedef KeyedVector<StreamId, size_t> BufferCountMap;
+
+ /**
+ * StreamSet keeps track of the stream info, free buffer list and hand-out buffer counts for
+ * each stream set.
+ */
+ struct StreamSet {
+ /**
+ * Stream set buffer count water mark representing the max number of allocated buffers
+ * (hand-out buffers + free buffers) count for each stream set. For a given stream set, when
+ * getBufferForStream() is called on this buffer manager, if the total allocated buffer
+ * count exceeds this water mark, the buffer manager will attempt to reduce it as follows:
+ *
+ * In getBufferForStream(), find a buffer associated with other streams (inside the same
+ * stream set) on the free buffer list and free it. For Gralloc V1, can just free the top
+ * of the free buffer list if the physical buffer sharing in this stream is supported.
+ *
+ * For a particular stream set, a larger allocatedBufferWaterMark increases the memory
+ * footprint of the stream set, but reduces the chance that getBufferForStream() will have
+ * to allocate a new buffer. We assume that the streams in one stream set are not streaming
+ * simultaneously, the max allocated buffer count water mark for a stream set will the max
+ * of all streams' total buffer counts. This will avoid new buffer allocation in steady
+ * streaming state.
+ *
+ * This water mark can be dynamically changed, and will grow when the hand-out buffer count
+ * of each stream increases, until it reaches the maxAllowedBufferCount.
+ */
+ size_t allocatedBufferWaterMark;
+
+ /**
+ * The max allowed buffer count for this stream set. It is the max of total number of
+ * buffers for each stream. This is the upper bound of the allocatedBufferWaterMark.
+ */
+ size_t maxAllowedBufferCount;
+
+ /**
+ * The stream info for all streams in this set
+ */
+ InfoMap streamInfoMap;
+ /**
+ * The free buffer list for all the buffers belong to this set. The free buffers are
+ * returned by the returnBufferForStream() call, and available for reuse.
+ */
+ BufferList freeBuffers;
+ /**
+ * The count of the buffers that were handed out to the streams of this set.
+ */
+ BufferCountMap handoutBufferCountMap;
+ StreamSet() {
+ allocatedBufferWaterMark = 0;
+ maxAllowedBufferCount = 0;
+ }
+ };
+
+ /**
+ * Stream set map managed by this buffer manager.
+ */
+ typedef int StreamSetId;
+ KeyedVector<StreamSetId, StreamSet> mStreamSetMap;
+
+ // TODO: There is no easy way to query the Gralloc version in this code yet, we have different
+ // code paths for different Gralloc versions, hardcode something here for now.
+ const uint32_t mGrallocVersion = GRALLOC_DEVICE_API_VERSION_0_1;
+
+ /**
+ * Check if this stream was successfully registered already. This method needs to be called with
+ * mLock held.
+ */
+ bool checkIfStreamRegisteredLocked(int streamId, int streamSetId) const;
+
+ /**
+ * Add a buffer entry to the BufferList. This method needs to be called with mLock held.
+ */
+ status_t addBufferToBufferListLocked(BufferList &bufList, const BufferEntry &buffer);
+
+ /**
+ * Remove all buffers from the BufferList.
+ *
+ * Note that this doesn't mean that the buffers are freed after this call. A buffer is freed
+ * only if all other references to it are dropped.
+ *
+ * This method needs to be called with mLock held.
+ */
+ status_t removeBuffersFromBufferListLocked(BufferList &bufList, int streamId);
+
+ /**
+ * Get the first available buffer from the buffer list for this stream. The graphicBuffer inside
+ * this entry will be NULL if there is no any GraphicBufferEntry found. After this call, the
+ * GraphicBufferEntry will be removed from the BufferList if a GraphicBufferEntry is found.
+ *
+ * This method needs to be called with mLock held.
+ *
+ */
+ GraphicBufferEntry getFirstBufferFromBufferListLocked(BufferList& buffers, int streamId);
+
+ /**
+ * Check if there is any buffer associated with this stream in the given buffer list.
+ *
+ * This method needs to be called with mLock held.
+ *
+ */
+ bool inline hasBufferForStreamLocked(BufferList& buffers, int streamId);
+};
+
+} // namespace camera3
+} // namespace android
+
+#endif // ANDROID_SERVERS_CAMERA3_BUFFER_MANAGER_H
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 50d9d75..5f990a9 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -64,6 +64,7 @@
mStatusWaiters(0),
mUsePartialResult(false),
mNumPartialResults(1),
+ mTimestampOffset(0),
mNextResultFrameNumber(0),
mNextReprocessResultFrameNumber(0),
mNextShutterFrameNumber(0),
@@ -167,6 +168,9 @@
return res;
}
+ /** Create buffer manager */
+ mBufferManager = new Camera3BufferManager();
+
bool aeLockAvailable = false;
camera_metadata_ro_entry aeLockAvailableEntry;
res = find_camera_metadata_ro_entry(info.static_camera_characteristics,
@@ -201,6 +205,14 @@
mNeedConfig = true;
mPauseStateNotify = false;
+ // Measure the clock domain offset between camera and video/hw_composer
+ camera_metadata_entry timestampSource =
+ mDeviceInfo.find(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE);
+ if (timestampSource.count > 0 && timestampSource.data.u8[0] ==
+ ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME) {
+ mTimestampOffset = getMonoToBoottimeOffset();
+ }
+
// Will the HAL be sending in early partial result metadata?
if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
camera_metadata_entry partialResultsCount =
@@ -293,6 +305,7 @@
mRequestThread.clear();
mStatusTracker.clear();
+ mBufferManager.clear();
hal3Device = mHal3Device;
}
@@ -378,6 +391,24 @@
return Size(maxJpegWidth, maxJpegHeight);
}
+nsecs_t Camera3Device::getMonoToBoottimeOffset() {
+ // try three times to get the clock offset, choose the one
+ // with the minimum gap in measurements.
+ const int tries = 3;
+ nsecs_t bestGap, measured;
+ for (int i = 0; i < tries; ++i) {
+ const nsecs_t tmono = systemTime(SYSTEM_TIME_MONOTONIC);
+ const nsecs_t tbase = systemTime(SYSTEM_TIME_BOOTTIME);
+ const nsecs_t tmono2 = systemTime(SYSTEM_TIME_MONOTONIC);
+ const nsecs_t gap = tmono2 - tmono;
+ if (i == 0 || gap < bestGap) {
+ bestGap = gap;
+ measured = tbase - ((tmono + tmono2) >> 1);
+ }
+ }
+ return measured;
+}
+
ssize_t Camera3Device::getJpegBufferSize(uint32_t width, uint32_t height) const {
// Get max jpeg size (area-wise).
Size maxJpegResolution = getMaxJpegResolution();
@@ -422,7 +453,31 @@
return maxBytesForPointCloud;
}
+ssize_t Camera3Device::getRawOpaqueBufferSize(uint32_t width, uint32_t height) const {
+ const int PER_CONFIGURATION_SIZE = 3;
+ const int WIDTH_OFFSET = 0;
+ const int HEIGHT_OFFSET = 1;
+ const int SIZE_OFFSET = 2;
+ camera_metadata_ro_entry rawOpaqueSizes =
+ mDeviceInfo.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+ size_t count = rawOpaqueSizes.count;
+ if (count == 0 || (count % PER_CONFIGURATION_SIZE)) {
+ ALOGE("%s: Camera %d: bad opaque RAW size static metadata length(%d)!",
+ __FUNCTION__, mId, count);
+ return BAD_VALUE;
+ }
+ for (size_t i = 0; i < count; i += PER_CONFIGURATION_SIZE) {
+ if (width == rawOpaqueSizes.data.i32[i + WIDTH_OFFSET] &&
+ height == rawOpaqueSizes.data.i32[i + HEIGHT_OFFSET]) {
+ return rawOpaqueSizes.data.i32[i + SIZE_OFFSET];
+ }
+ }
+
+ ALOGE("%s: Camera %d: cannot find size for %dx%d opaque RAW image!",
+ __FUNCTION__, mId, width, height);
+ return BAD_VALUE;
+}
status_t Camera3Device::dump(int fd, const Vector<String16> &args) {
ATRACE_CALL();
@@ -440,6 +495,15 @@
"Camera %d: %s: Unable to lock main lock, proceeding anyway",
mId, __FUNCTION__);
+ bool dumpTemplates = false;
+ String16 templatesOption("-t");
+ int n = args.size();
+ for (int i = 0; i < n; i++) {
+ if (args[i] == templatesOption) {
+ dumpTemplates = true;
+ }
+ }
+
String8 lines;
const char *status =
@@ -469,6 +533,10 @@
mOutputStreams[i]->dump(fd,args);
}
+ lines = String8(" Camera3 Buffer Manager:\n");
+ write(fd, lines.string(), lines.size());
+ mBufferManager->dump(fd, args);
+
lines = String8(" In-flight requests:\n");
if (mInFlightMap.size() == 0) {
lines.append(" None\n");
@@ -491,6 +559,33 @@
lastRequest.dump(fd, /*verbosity*/2, /*indentation*/6);
}
+ if (dumpTemplates) {
+ const char *templateNames[] = {
+ "TEMPLATE_PREVIEW",
+ "TEMPLATE_STILL_CAPTURE",
+ "TEMPLATE_VIDEO_RECORD",
+ "TEMPLATE_VIDEO_SNAPSHOT",
+ "TEMPLATE_ZERO_SHUTTER_LAG",
+ "TEMPLATE_MANUAL"
+ };
+
+ for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; i++) {
+ const camera_metadata_t *templateRequest;
+ templateRequest =
+ mHal3Device->ops->construct_default_request_settings(
+ mHal3Device, i);
+ lines = String8::format(" HAL Request %s:\n", templateNames[i-1]);
+ if (templateRequest == NULL) {
+ lines.append(" Not supported\n");
+ write(fd, lines.string(), lines.size());
+ } else {
+ write(fd, lines.string(), lines.size());
+ dump_indented_camera_metadata(templateRequest,
+ fd, /*verbosity*/2, /*indentation*/8);
+ }
+ }
+ }
+
if (mHal3Device != NULL) {
lines = String8(" HAL device dump:\n");
write(fd, lines.string(), lines.size());
@@ -866,7 +961,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) {
+ camera3_stream_rotation_t rotation, int *id, int streamSetId) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
@@ -903,6 +998,11 @@
assert(mStatus != STATUS_ACTIVE);
sp<Camera3OutputStream> newStream;
+ // Overwrite stream set id to invalid for HAL3.2 or lower, as buffer manager does support
+ // such devices.
+ if (mDeviceVersion <= CAMERA_DEVICE_API_VERSION_3_2) {
+ streamSetId = CAMERA3_STREAM_SET_ID_INVALID;
+ }
if (format == HAL_PIXEL_FORMAT_BLOB) {
ssize_t blobBufferSize;
if (dataSpace != HAL_DATASPACE_DEPTH) {
@@ -919,13 +1019,34 @@
}
}
newStream = new Camera3OutputStream(mNextStreamId, consumer,
- width, height, blobBufferSize, format, dataSpace, rotation);
+ width, height, blobBufferSize, format, dataSpace, rotation,
+ mTimestampOffset, streamSetId);
+ } else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+ ssize_t rawOpaqueBufferSize = getRawOpaqueBufferSize(width, height);
+ if (rawOpaqueBufferSize <= 0) {
+ SET_ERR_L("Invalid RAW opaque buffer size %zd", rawOpaqueBufferSize);
+ return BAD_VALUE;
+ }
+ newStream = new Camera3OutputStream(mNextStreamId, consumer,
+ width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
+ mTimestampOffset, streamSetId);
} else {
newStream = new Camera3OutputStream(mNextStreamId, consumer,
- width, height, format, dataSpace, rotation);
+ width, height, format, dataSpace, rotation,
+ mTimestampOffset, streamSetId);
}
newStream->setStatusTracker(mStatusTracker);
+ /**
+ * Camera3 Buffer manager is only supported by HAL3.3 onwards, as the older HALs ( < HAL3.2)
+ * requires buffers to be statically allocated for internal static buffer registration, while
+ * the buffers provided by buffer manager are really dynamically allocated. For HAL3.2, because
+ * not all HAL implementation supports dynamic buffer registeration, exlude it as well.
+ */
+ if (mDeviceVersion > CAMERA_DEVICE_API_VERSION_3_2) {
+ newStream->setBufferManager(mBufferManager);
+ }
+
res = mOutputStreams.add(mNextStreamId, newStream);
if (res < 0) {
SET_ERR_L("Can't add new stream to set: %s (%d)", strerror(-res), res);
@@ -3266,7 +3387,7 @@
}
if (mNextRequests.size() < batchSize) {
- ALOGE("RequestThread: only get %d out of %d requests. Skipping requests.",
+ ALOGE("RequestThread: only get %zu out of %zu requests. Skipping requests.",
mNextRequests.size(), batchSize);
cleanUpFailedRequests(/*sendRequestError*/true);
}
@@ -3586,7 +3707,7 @@
status_t Camera3Device::RequestThread::addDummyTriggerIds(
const sp<CaptureRequest> &request) {
- // Trigger ID 0 has special meaning in the HAL2 spec, so avoid it here
+ // Trigger ID 0 had special meaning in the HAL2 spec, so avoid it here
static const int32_t dummyTriggerId = 1;
status_t res;
@@ -3680,8 +3801,6 @@
}
status_t Camera3Device::PreparerThread::clear() {
- status_t res;
-
Mutex::Autolock l(mLock);
for (const auto& stream : mPendingStreams) {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 2cd5af3..3848200 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -23,12 +23,14 @@
#include <utils/Mutex.h>
#include <utils/Thread.h>
#include <utils/KeyedVector.h>
+#include <utils/Timers.h>
#include <hardware/camera3.h>
#include <camera/CaptureResult.h>
#include <camera/camera2/ICameraDeviceUser.h>
#include "common/CameraDeviceBase.h"
#include "device3/StatusTracker.h"
+#include "device3/Camera3BufferManager.h"
/**
* Function pointer types with C calling convention to
@@ -97,7 +99,8 @@
// stream, reconfiguring device, and unpausing.
virtual status_t createStream(sp<Surface> consumer,
uint32_t width, uint32_t height, int format,
- android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id);
+ android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
+ int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID);
virtual status_t createInputStream(
uint32_t width, uint32_t height, int format,
int *id);
@@ -150,6 +153,7 @@
virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
ssize_t getPointCloudBufferSize() const;
+ ssize_t getRawOpaqueBufferSize(uint32_t width, uint32_t height) const;
// Methods called by subclasses
void notifyStatus(bool idle); // updates from StatusTracker
@@ -248,6 +252,12 @@
/**** End scope for mLock ****/
+ // The offset converting from clock domain of other subsystem
+ // (video/hardware composer) to that of camera. Assumption is that this
+ // offset won't change during the life cycle of the camera device. In other
+ // words, camera device shouldn't be open during CPU suspend.
+ nsecs_t mTimestampOffset;
+
typedef struct AeTriggerCancelOverride {
bool applyAeLock;
uint8_t aeLock;
@@ -389,6 +399,12 @@
*/
Size getMaxJpegResolution() const;
+ /**
+ * Helper function to get the offset between MONOTONIC and BOOTTIME
+ * timestamp.
+ */
+ static nsecs_t getMonoToBoottimeOffset();
+
struct RequestTrigger {
// Metadata tag number, e.g. android.control.aePrecaptureTrigger
uint32_t metadataTag;
@@ -720,6 +736,13 @@
sp<camera3::StatusTracker> mStatusTracker;
/**
+ * Graphic buffer manager for output streams. Each device has a buffer manager, which is used
+ * by the output streams to get and return buffers if these streams are registered to this
+ * buffer manager.
+ */
+ sp<camera3::Camera3BufferManager> mBufferManager;
+
+ /**
* Thread for preparing streams
*/
class PreparerThread : private Thread, public virtual RefBase {
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index 1d9d04f..fe04eb1 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -38,7 +38,7 @@
status_t Camera3DummyStream::getBufferLocked(camera3_stream_buffer *buffer) {
ATRACE_CALL();
- ALOGE("%s: Stream %d: Dummy stream cannot produce buffers!", mId);
+ ALOGE("%s: Stream %d: Dummy stream cannot produce buffers!", __FUNCTION__, mId);
return INVALID_OPERATION;
}
@@ -46,7 +46,7 @@
const camera3_stream_buffer &buffer,
nsecs_t timestamp) {
ATRACE_CALL();
- ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", mId);
+ ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", __FUNCTION__, mId);
return INVALID_OPERATION;
}
@@ -57,7 +57,7 @@
/*out*/
sp<Fence> *releaseFenceOut) {
ATRACE_CALL();
- ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", mId);
+ ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", __FUNCTION__, mId);
return INVALID_OPERATION;
}
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index 23b1c45..4824974 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -31,9 +31,9 @@
Camera3IOStreamBase::Camera3IOStreamBase(int id, camera3_stream_type_t type,
uint32_t width, uint32_t height, size_t maxSize, int format,
- android_dataspace dataSpace, camera3_stream_rotation_t rotation) :
+ android_dataspace dataSpace, camera3_stream_rotation_t rotation, int setId) :
Camera3Stream(id, type,
- width, height, maxSize, format, dataSpace, rotation),
+ width, height, maxSize, format, dataSpace, rotation, setId),
mTotalBufferCount(0),
mHandoutTotalBufferCount(0),
mHandoutOutputBufferCount(0),
@@ -42,7 +42,8 @@
mCombinedFence = new Fence();
- if (maxSize > 0 && format != HAL_PIXEL_FORMAT_BLOB) {
+ if (maxSize > 0 &&
+ (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
format);
mState = STATE_ERROR;
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index f5727e8..35dda39 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -34,7 +34,8 @@
protected:
Camera3IOStreamBase(int id, camera3_stream_type_t type,
uint32_t width, uint32_t height, size_t maxSize, int format,
- android_dataspace dataSpace, camera3_stream_rotation_t rotation);
+ android_dataspace dataSpace, camera3_stream_rotation_t rotation,
+ int setId = CAMERA3_STREAM_SET_ID_INVALID);
public:
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 2504bfd..7dab2e3 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -169,7 +169,7 @@
if (producer == NULL) {
return BAD_VALUE;
} else if (mProducer == NULL) {
- ALOGE("%s: No input stream is configured");
+ ALOGE("%s: No input stream is configured", __FUNCTION__);
return INVALID_OPERATION;
}
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 3f0a736..1e6452f 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -34,30 +34,41 @@
Camera3OutputStream::Camera3OutputStream(int id,
sp<Surface> consumer,
uint32_t width, uint32_t height, int format,
- android_dataspace dataSpace, camera3_stream_rotation_t rotation) :
+ 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),
+ /*maxSize*/0, format, dataSpace, rotation, setId),
mConsumer(consumer),
mTransform(0),
- mTraceFirstBuffer(true) {
+ mTraceFirstBuffer(true),
+ mUseBufferManager(false),
+ mTimestampOffset(timestampOffset) {
if (mConsumer == NULL) {
ALOGE("%s: Consumer is NULL!", __FUNCTION__);
mState = STATE_ERROR;
}
+
+ if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
+ mBufferReleasedListener = new BufferReleasedListener(this);
+ }
}
Camera3OutputStream::Camera3OutputStream(int id,
sp<Surface> consumer,
uint32_t width, uint32_t height, size_t maxSize, int format,
- android_dataspace dataSpace, camera3_stream_rotation_t rotation) :
+ android_dataspace dataSpace, camera3_stream_rotation_t rotation,
+ nsecs_t timestampOffset, int setId) :
Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, maxSize,
- format, dataSpace, rotation),
+ format, dataSpace, rotation, setId),
mConsumer(consumer),
mTransform(0),
- mTraceFirstBuffer(true) {
+ mTraceFirstBuffer(true),
+ mUseMonoTimestamp(false),
+ mUseBufferManager(false),
+ mTimestampOffset(timestampOffset) {
- if (format != HAL_PIXEL_FORMAT_BLOB) {
+ if (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW_OPAQUE) {
ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
format);
mState = STATE_ERROR;
@@ -67,17 +78,29 @@
ALOGE("%s: Consumer is NULL!", __FUNCTION__);
mState = STATE_ERROR;
}
+
+ if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
+ mBufferReleasedListener = new BufferReleasedListener(this);
+ }
}
Camera3OutputStream::Camera3OutputStream(int id, camera3_stream_type_t type,
uint32_t width, uint32_t height,
int format,
android_dataspace dataSpace,
- camera3_stream_rotation_t rotation) :
+ camera3_stream_rotation_t rotation,
+ int setId) :
Camera3IOStreamBase(id, type, width, height,
/*maxSize*/0,
- format, dataSpace, rotation),
- mTransform(0) {
+ format, dataSpace, rotation, setId),
+ mTransform(0),
+ mTraceFirstBuffer(true),
+ mUseMonoTimestamp(false),
+ mUseBufferManager(false) {
+
+ if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
+ mBufferReleasedListener = new BufferReleasedListener(this);
+ }
// Subclasses expected to initialize mConsumer themselves
}
@@ -96,28 +119,46 @@
}
ANativeWindowBuffer* anb;
- int fenceFd;
+ int fenceFd = -1;
+ if (mUseBufferManager) {
+ sp<GraphicBuffer> gb;
+ res = mBufferManager->getBufferForStream(getId(), getStreamSetId(), &gb, &fenceFd);
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Can't get next output buffer from buffer manager: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
+ // Attach this buffer to the bufferQueue: the buffer will be in dequeue state after a
+ // successful return.
+ anb = gb.get();
+ res = mConsumer->attachBuffer(anb);
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
+ } else {
+ /**
+ * Release the lock briefly to avoid deadlock for below scenario:
+ * Thread 1: StreamingProcessor::startStream -> Camera3Stream::isConfiguring().
+ * This thread acquired StreamingProcessor lock and try to lock Camera3Stream lock.
+ * Thread 2: Camera3Stream::returnBuffer->StreamingProcessor::onFrameAvailable().
+ * This thread acquired Camera3Stream lock and bufferQueue lock, and try to lock
+ * StreamingProcessor lock.
+ * Thread 3: Camera3Stream::getBuffer(). This thread acquired Camera3Stream lock
+ * and try to lock bufferQueue lock.
+ * Then there is circular locking dependency.
+ */
+ sp<ANativeWindow> currentConsumer = mConsumer;
+ mLock.unlock();
- /**
- * Release the lock briefly to avoid deadlock for below scenario:
- * Thread 1: StreamingProcessor::startStream -> Camera3Stream::isConfiguring().
- * This thread acquired StreamingProcessor lock and try to lock Camera3Stream lock.
- * Thread 2: Camera3Stream::returnBuffer->StreamingProcessor::onFrameAvailable().
- * This thread acquired Camera3Stream lock and bufferQueue lock, and try to lock
- * StreamingProcessor lock.
- * Thread 3: Camera3Stream::getBuffer(). This thread acquired Camera3Stream lock
- * and try to lock bufferQueue lock.
- * Then there is circular locking dependency.
- */
- sp<ANativeWindow> currentConsumer = mConsumer;
- mLock.unlock();
-
- res = currentConsumer->dequeueBuffer(currentConsumer.get(), &anb, &fenceFd);
- mLock.lock();
- if (res != OK) {
- ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- return res;
+ res = currentConsumer->dequeueBuffer(currentConsumer.get(), &anb, &fenceFd);
+ mLock.lock();
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
}
/**
@@ -183,6 +224,11 @@
ALOGE("%s: Stream %d: Error cancelling buffer to native window:"
" %s (%d)", __FUNCTION__, mId, strerror(-res), res);
}
+
+ if (mUseBufferManager) {
+ // Return this buffer back to buffer manager.
+ mBufferReleasedListener->onBufferReleased();
+ }
} else {
if (mTraceFirstBuffer && (stream_type == CAMERA3_STREAM_OUTPUT)) {
{
@@ -193,7 +239,11 @@
mTraceFirstBuffer = false;
}
- res = native_window_set_buffers_timestamp(mConsumer.get(), timestamp);
+ /* Certain consumers (such as AudioSource or HardwareComposer) use
+ * MONOTONIC time, causing time misalignment if camera timestamp is
+ * in BOOTTIME. Do the conversion if necessary. */
+ res = native_window_set_buffers_timestamp(mConsumer.get(),
+ mUseMonoTimestamp ? timestamp - mTimestampOffset : timestamp);
if (res != OK) {
ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
@@ -270,9 +320,9 @@
ALOG_ASSERT(mConsumer != 0, "mConsumer should never be NULL");
- // Configure consumer-side ANativeWindow interface
- res = native_window_api_connect(mConsumer.get(),
- NATIVE_WINDOW_API_CAMERA);
+ // Configure consumer-side ANativeWindow interface. The listener may be used
+ // to notify buffer manager (if it is used) of the returned buffers.
+ res = mConsumer->connect(NATIVE_WINDOW_API_CAMERA, /*listener*/mBufferReleasedListener);
if (res != OK) {
ALOGE("%s: Unable to connect to native window for stream %d",
__FUNCTION__, mId);
@@ -350,6 +400,7 @@
mHandoutTotalBufferCount = 0;
mFrameCount = 0;
mLastTimestamp = 0;
+ mUseMonoTimestamp = (isConsumedByHWComposer() | isVideoStream());
res = native_window_set_buffer_count(mConsumer.get(),
mTotalBufferCount);
@@ -366,6 +417,31 @@
__FUNCTION__, mTransform, strerror(-res), res);
}
+ /**
+ * Camera3 Buffer manager is only supported by HAL3.3 onwards, as the older HALs requires
+ * buffers to be statically allocated for internal static buffer registration, while the
+ * buffers provided by buffer manager are really dynamically allocated. Camera3Device only
+ * sets the mBufferManager if device version is > HAL3.2, which guarantees that the buffer
+ * manager setup is skipped in below code. Note that HAL3.2 is also excluded here, as some
+ * HAL3.2 devices may not support the dynamic buffer registeration.
+ */
+ if (mBufferManager != 0 && mSetId > CAMERA3_STREAM_SET_ID_INVALID) {
+ StreamInfo streamInfo(
+ getId(), getStreamSetId(), getWidth(), getHeight(), getFormat(), getDataSpace(),
+ camera3_stream::usage, mTotalBufferCount, /*isConfigured*/true);
+ res = mBufferManager->registerStream(streamInfo);
+ if (res == OK) {
+ // Disable buffer allocation for this BufferQueue, buffer manager will take over
+ // the buffer allocation responsibility.
+ mConsumer->getIGraphicBufferProducer()->allowAllocation(false);
+ mUseBufferManager = true;
+ } else {
+ ALOGE("%s: Unable to register stream %d to camera3 buffer manager, "
+ "(error %d %s), fall back to BufferQueue for buffer management!",
+ __FUNCTION__, mId, res, strerror(-res));
+ }
+ }
+
return OK;
}
@@ -376,6 +452,8 @@
return res;
}
+ ALOGV("%s: disconnecting stream %d from native window", __FUNCTION__, getId());
+
res = native_window_api_disconnect(mConsumer.get(),
NATIVE_WINDOW_API_CAMERA);
@@ -396,6 +474,21 @@
return res;
}
+ // Since device is already idle, there is no getBuffer call to buffer manager, unregister the
+ // stream at this point should be safe.
+ if (mUseBufferManager) {
+ res = mBufferManager->unregisterStream(getId(), getStreamSetId());
+ if (res != OK) {
+ ALOGE("%s: Unable to unregister stream %d from buffer manager "
+ "(error %d %s)", __FUNCTION__, mId, res, strerror(-res));
+ mState = STATE_ERROR;
+ return res;
+ }
+ // Note that, to make prepare/teardown case work, we must not mBufferManager.clear(), as
+ // the stream is still in usable state after this call.
+ mUseBufferManager = false;
+ }
+
mState = (mState == STATE_IN_RECONFIG) ? STATE_IN_CONFIG
: STATE_CONSTRUCTED;
return OK;
@@ -437,6 +530,71 @@
return (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) != 0;
}
+status_t Camera3OutputStream::setBufferManager(sp<Camera3BufferManager> bufferManager) {
+ Mutex::Autolock l(mLock);
+ if (mState != STATE_CONSTRUCTED) {
+ ALOGE("%s: this method can only be called when stream in in CONSTRUCTED state.",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ mBufferManager = bufferManager;
+
+ return OK;
+}
+
+void Camera3OutputStream::BufferReleasedListener::onBufferReleased() {
+ sp<Camera3OutputStream> stream = mParent.promote();
+ if (stream == nullptr) {
+ ALOGV("%s: Parent camera3 output stream was destroyed", __FUNCTION__);
+ return;
+ }
+
+ Mutex::Autolock l(stream->mLock);
+ if (!(stream->mUseBufferManager)) {
+ return;
+ }
+
+ sp<Fence> fence;
+ sp<GraphicBuffer> buffer;
+ int fenceFd = -1;
+ status_t res = stream->mConsumer->detachNextBuffer(&buffer, &fence);
+ if (res == NO_MEMORY) {
+ // This may rarely happen, which indicates that the released buffer was freed by other
+ // call (e.g., attachBuffer, dequeueBuffer etc.) before reaching here. We should notify the
+ // buffer manager that this buffer has been freed. It's not fatal, but should be avoided,
+ // therefore log a warning.
+ buffer = 0;
+ ALOGW("%s: the released buffer has already been freed by the buffer queue!", __FUNCTION__);
+ } else if (res != OK) {
+ // Other errors are fatal.
+ ALOGE("%s: detach next buffer failed: %s (%d).", __FUNCTION__, strerror(-res), res);
+ stream->mState = STATE_ERROR;
+ return;
+ }
+
+ if (fence!= 0 && fence->isValid()) {
+ fenceFd = fence->dup();
+ }
+ res = stream->mBufferManager->returnBufferForStream(stream->getId(), stream->getStreamSetId(),
+ buffer, fenceFd);
+ if (res != OK) {
+ ALOGE("%s: return buffer to buffer manager failed: %s (%d).", __FUNCTION__,
+ strerror(-res), res);
+ stream->mState = STATE_ERROR;
+ }
+}
+
+bool Camera3OutputStream::isConsumedByHWComposer() const {
+ uint32_t usage = 0;
+ status_t res = getEndpointUsage(&usage);
+ if (res != OK) {
+ ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res);
+ return false;
+ }
+
+ return (usage & GRALLOC_USAGE_HW_COMPOSER) != 0;
+}
+
}; // namespace camera3
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 3c083ec..a883448 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -18,16 +18,54 @@
#define ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H
#include <utils/RefBase.h>
+#include <gui/IProducerListener.h>
#include <gui/Surface.h>
#include "Camera3Stream.h"
#include "Camera3IOStreamBase.h"
#include "Camera3OutputStreamInterface.h"
+#include "Camera3BufferManager.h"
namespace android {
namespace camera3 {
+class Camera3BufferManager;
+
+/**
+ * Stream info structure that holds the necessary stream info for buffer manager to use for
+ * buffer allocation and management.
+ */
+struct StreamInfo {
+ int streamId;
+ int streamSetId;
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ android_dataspace dataSpace;
+ uint32_t combinedUsage;
+ size_t totalBufferCount;
+ bool isConfigured;
+ StreamInfo(int id = CAMERA3_STREAM_ID_INVALID,
+ int setId = CAMERA3_STREAM_SET_ID_INVALID,
+ uint32_t w = 0,
+ uint32_t h = 0,
+ uint32_t fmt = 0,
+ android_dataspace ds = HAL_DATASPACE_UNKNOWN,
+ uint32_t usage = 0,
+ size_t bufferCount = 0,
+ bool configured = false) :
+ streamId(id),
+ streamSetId(setId),
+ width(w),
+ height(h),
+ format(fmt),
+ dataSpace(ds),
+ combinedUsage(usage),
+ totalBufferCount(bufferCount),
+ isConfigured(configured){}
+};
+
/**
* A class for managing a single stream of output data from the camera device.
*/
@@ -37,18 +75,24 @@
public:
/**
* Set up a stream for formats that have 2 dimensions, such as RAW and YUV.
+ * A valid stream set id needs to be set to support buffer sharing between multiple
+ * streams.
*/
Camera3OutputStream(int id, sp<Surface> consumer,
uint32_t width, uint32_t height, int format,
- android_dataspace dataSpace, camera3_stream_rotation_t rotation);
+ android_dataspace dataSpace, camera3_stream_rotation_t rotation,
+ nsecs_t timestampOffset, int setId = CAMERA3_STREAM_SET_ID_INVALID);
/**
* Set up a stream for formats that have a variable buffer size for the same
* dimensions, such as compressed JPEG.
+ * A valid stream set id needs to be set to support buffer sharing between multiple
+ * streams.
*/
Camera3OutputStream(int id, sp<Surface> consumer,
uint32_t width, uint32_t height, size_t maxSize, int format,
- android_dataspace dataSpace, camera3_stream_rotation_t rotation);
+ android_dataspace dataSpace, camera3_stream_rotation_t rotation,
+ nsecs_t timestampOffset, int setId = CAMERA3_STREAM_SET_ID_INVALID);
virtual ~Camera3OutputStream();
@@ -68,11 +112,37 @@
* Return if this output stream is for video encoding.
*/
bool isVideoStream() const;
+ /**
+ * Return if this output stream is consumed by hardware composer.
+ */
+ bool isConsumedByHWComposer() const;
+
+ class BufferReleasedListener : public BnProducerListener {
+ public:
+ BufferReleasedListener(wp<Camera3OutputStream> parent) : mParent(parent) {}
+
+ /**
+ * Implementation of IProducerListener, used to notify this stream that the consumer
+ * has returned a buffer and it is ready to return to Camera3BufferManager for reuse.
+ */
+ virtual void onBufferReleased();
+
+ private:
+ wp<Camera3OutputStream> mParent;
+ };
+
+ /**
+ * 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.
+ */
+ status_t setBufferManager(sp<Camera3BufferManager> bufferManager);
protected:
Camera3OutputStream(int id, camera3_stream_type_t type,
uint32_t width, uint32_t height, int format,
- android_dataspace dataSpace, camera3_stream_rotation_t rotation);
+ android_dataspace dataSpace, camera3_stream_rotation_t rotation,
+ int setId = CAMERA3_STREAM_SET_ID_INVALID);
/**
* Note that we release the lock briefly in this function
@@ -97,6 +167,31 @@
// Name of Surface consumer
String8 mConsumerName;
+ // Whether consumer assumes MONOTONIC timestamp
+ bool mUseMonoTimestamp;
+
+ /**
+ * GraphicBuffer manager this stream is registered to. Used to replace the buffer
+ * allocation/deallocation role of BufferQueue.
+ */
+ sp<Camera3BufferManager> mBufferManager;
+
+ /**
+ * Buffer released listener, used to notify the buffer manager that a buffer is released
+ * from consumer side.
+ */
+ sp<BufferReleasedListener> mBufferReleasedListener;
+
+ /**
+ * Flag indicating if the buffer manager is used to allocate the stream buffers
+ */
+ bool mUseBufferManager;
+
+ /**
+ * Timestamp offset for video and hardware composer consumed streams
+ */
+ nsecs_t mTimestampOffset;
+
/**
* Internal Camera3Stream interface
*/
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 96299b3..ed3ab97 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -47,13 +47,19 @@
Camera3Stream::Camera3Stream(int id,
camera3_stream_type type,
uint32_t width, uint32_t height, size_t maxSize, int format,
- android_dataspace dataSpace, camera3_stream_rotation_t rotation) :
+ android_dataspace dataSpace, camera3_stream_rotation_t rotation, int setId) :
camera3_stream(),
mId(id),
+ mSetId(setId),
mName(String8::format("Camera3Stream[%d]", id)),
mMaxSize(maxSize),
mState(STATE_CONSTRUCTED),
mStatusId(StatusTracker::NO_STATUS_ID),
+ oldUsage(0),
+ oldMaxBuffers(0),
+ mStreamUnpreparable(false),
+ mPrepared(false),
+ mPreparedBufferIdx(0),
mLastMaxCount(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX) {
camera3_stream::stream_type = type;
@@ -66,8 +72,9 @@
camera3_stream::max_buffers = 0;
camera3_stream::priv = NULL;
- if (format == HAL_PIXEL_FORMAT_BLOB && maxSize == 0) {
- ALOGE("%s: BLOB format with size == 0", __FUNCTION__);
+ if ((format == HAL_PIXEL_FORMAT_BLOB || format == HAL_PIXEL_FORMAT_RAW_OPAQUE) &&
+ maxSize == 0) {
+ ALOGE("%s: BLOB or RAW_OPAQUE format with size == 0", __FUNCTION__);
mState = STATE_ERROR;
}
}
@@ -76,6 +83,10 @@
return mId;
}
+int Camera3Stream::getStreamSetId() const {
+ return mSetId;
+}
+
uint32_t Camera3Stream::getWidth() const {
return camera3_stream::width;
}
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 753280b..fe51ab5 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -130,6 +130,11 @@
int getId() const;
/**
+ * Get the output stream set id.
+ */
+ int getStreamSetId() const;
+
+ /**
* Get the stream's dimensions and format
*/
uint32_t getWidth() const;
@@ -350,6 +355,21 @@
protected:
const int mId;
+ /**
+ * Stream set id, used to indicate which group of this stream belongs to for buffer sharing
+ * across multiple streams.
+ *
+ * The default value is set to CAMERA3_STREAM_SET_ID_INVALID, which indicates that this stream
+ * doesn't intend to share buffers with any other streams, and this stream will fall back to
+ * the existing BufferQueue mechanism to manage the buffer allocations and buffer circulation.
+ * When a valid stream set id is set, this stream intends to use the Camera3BufferManager to
+ * manage the buffer allocations; the BufferQueue will only handle the buffer transaction
+ * between the producer and consumer. For this case, upon successfully registration, the streams
+ * with the same stream set id will potentially share the buffers allocated by
+ * Camera3BufferManager.
+ */
+ const int mSetId;
+
const String8 mName;
// Zero for formats with fixed buffer size for given dimensions.
const size_t mMaxSize;
@@ -367,7 +387,8 @@
Camera3Stream(int id, camera3_stream_type type,
uint32_t width, uint32_t height, size_t maxSize, int format,
- android_dataspace dataSpace, camera3_stream_rotation_t rotation);
+ android_dataspace dataSpace, camera3_stream_rotation_t rotation,
+ int setId);
/**
* Interface to be implemented by derived classes
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 54009ae..3f7e7a7 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -26,6 +26,20 @@
namespace camera3 {
+enum {
+ /**
+ * This stream set ID indicates that the set ID is invalid, and this stream doesn't intend to
+ * share buffers with any other stream. It is illegal to register this kind of stream to
+ * Camera3BufferManager.
+ */
+ CAMERA3_STREAM_SET_ID_INVALID = -1,
+
+ /**
+ * Invalid output stream ID.
+ */
+ CAMERA3_STREAM_ID_INVALID = -1,
+};
+
class StatusTracker;
/**
@@ -45,6 +59,11 @@
virtual int getId() const = 0;
/**
+ * Get the output stream set id.
+ */
+ virtual int getStreamSetId() const = 0;
+
+ /**
* Get the stream's dimensions and format
*/
virtual uint32_t getWidth() const = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
index eefcb44..7414c4c 100644
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
@@ -115,8 +115,7 @@
Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL,
width, height,
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
- HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0),
- mDepth(bufferCount) {
+ HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0) {
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.h b/services/camera/libcameraservice/device3/Camera3ZslStream.h
index 5323a49..12369cf 100644
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.h
+++ b/services/camera/libcameraservice/device3/Camera3ZslStream.h
@@ -73,7 +73,6 @@
private:
- int mDepth;
// Input buffers pending to be queued into HAL
List<sp<RingBufferConsumer::PinnedBufferItem> > mInputBufferQueue;
sp<RingBufferConsumer> mProducer;
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index 8cd6800..65816e0 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -229,7 +229,7 @@
// item.mGraphicBuffer was populated with the proper graphic-buffer
// at acquire even if it was previously acquired
- err = addReleaseFenceLocked(item.mBuf,
+ err = addReleaseFenceLocked(item.mSlot,
item.mGraphicBuffer, item.mFence);
if (err != OK) {
@@ -244,7 +244,7 @@
// item.mGraphicBuffer was populated with the proper graphic-buffer
// at acquire even if it was previously acquired
- err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer,
+ err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer,
EGL_NO_DISPLAY,
EGL_NO_SYNC_KHR);
if (err != OK) {
@@ -318,7 +318,7 @@
mLatestTimestamp = item.mTimestamp;
- item.mGraphicBuffer = mSlots[item.mBuf].mGraphicBuffer;
+ item.mGraphicBuffer = mSlots[item.mSlot].mGraphicBuffer;
} // end of mMutex lock
ConsumerBase::onFrameAvailable(item);
@@ -335,7 +335,7 @@
RingBufferItem& find = *it;
if (item.mGraphicBuffer == find.mGraphicBuffer) {
- status_t res = addReleaseFenceLocked(item.mBuf,
+ status_t res = addReleaseFenceLocked(item.mSlot,
item.mGraphicBuffer, item.mFence);
if (res != OK) {
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.h b/services/camera/libcameraservice/gui/RingBufferConsumer.h
index 83e7298..28dc5d5 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.h
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.h
@@ -133,7 +133,7 @@
}
bool isEmpty() {
- return mBufferItem.mBuf == BufferQueue::INVALID_BUFFER_SLOT;
+ return mBufferItem.mSlot == BufferQueue::INVALID_BUFFER_SLOT;
}
BufferItem& getBufferItem() { return mBufferItem; }
@@ -189,4 +189,4 @@
} // namespace android
-#endif // ANDROID_GUI_CPUCONSUMER_H
+#endif // ANDROID_GUI_RINGBUFFERCONSUMER_H
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
new file mode 100644
index 0000000..239b4e1
--- /dev/null
+++ b/services/mediacodec/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH := $(call my-dir)
+
+# service library
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := MediaCodecService.cpp
+LOCAL_SHARED_LIBRARIES := libmedia libbinder libutils liblog libstagefright_omx
+LOCAL_C_INCLUDES := \
+ $(TOP)/frameworks/av/media/libstagefright \
+ $(TOP)/frameworks/native/include/media/openmax
+LOCAL_MODULE:= libmediacodecservice
+LOCAL_32_BIT_ONLY := true
+include $(BUILD_SHARED_LIBRARY)
+
+
+# service executable
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := main_codecservice.cpp
+LOCAL_SHARED_LIBRARIES := libmedia libmediacodecservice libbinder libutils liblog
+LOCAL_C_INCLUDES := \
+ $(TOP)/frameworks/av/media/libstagefright \
+ $(TOP)/frameworks/native/include/media/openmax
+LOCAL_MODULE:= mediacodec
+LOCAL_32_BIT_ONLY := true
+LOCAL_INIT_RC := mediacodec.rc
+include $(BUILD_EXECUTABLE)
+
+
diff --git a/services/mediacodec/MODULE_LICENSE_APACHE2 b/services/mediacodec/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/mediacodec/MODULE_LICENSE_APACHE2
diff --git a/services/mediacodec/MediaCodecService.cpp b/services/mediacodec/MediaCodecService.cpp
new file mode 100644
index 0000000..fc1e5d9
--- /dev/null
+++ b/services/mediacodec/MediaCodecService.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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 "MediaCodecService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "MediaCodecService.h"
+
+namespace android {
+
+sp<IOMX> MediaCodecService::getOMX() {
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (mOMX.get() == NULL) {
+ mOMX = new OMX;
+ }
+
+ return mOMX;
+}
+
+
+status_t MediaCodecService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags)
+{
+ return BnMediaCodecService::onTransact(code, data, reply, flags);
+}
+
+} // namespace android
diff --git a/services/mediacodec/MediaCodecService.h b/services/mediacodec/MediaCodecService.h
new file mode 100644
index 0000000..d64debb
--- /dev/null
+++ b/services/mediacodec/MediaCodecService.h
@@ -0,0 +1,48 @@
+/*
+ * 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_MEDIA_CODEC_SERVICE_H
+#define ANDROID_MEDIA_CODEC_SERVICE_H
+
+#include <binder/BinderService.h>
+#include <media/IMediaCodecService.h>
+#include <include/OMX.h>
+
+namespace android {
+
+class MediaCodecService : public BinderService<MediaCodecService>, public BnMediaCodecService
+{
+ friend class BinderService<MediaCodecService>; // for MediaCodecService()
+public:
+ MediaCodecService() : BnMediaCodecService() { }
+ virtual ~MediaCodecService() { }
+ virtual void onFirstRef() { }
+
+ static const char* getServiceName() { return "media.codec"; }
+
+ virtual sp<IOMX> getOMX();
+
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags);
+
+private:
+ Mutex mLock;
+ sp<IOMX> mOMX;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_CODEC_SERVICE_H
diff --git a/services/mediacodec/NOTICE b/services/mediacodec/NOTICE
new file mode 100644
index 0000000..34bdaf1
--- /dev/null
+++ b/services/mediacodec/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
new file mode 100644
index 0000000..aedf0c3
--- /dev/null
+++ b/services/mediacodec/main_codecservice.cpp
@@ -0,0 +1,45 @@
+/*
+**
+** 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 "mediacodec"
+//#define LOG_NDEBUG 0
+
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+// from LOCAL_C_INCLUDES
+#include "MediaCodecService.h"
+
+using namespace android;
+
+int main(int argc __unused, char** argv)
+{
+ ALOGI("@@@ mediacodecservice starting");
+ signal(SIGPIPE, SIG_IGN);
+
+ strcpy(argv[0], "media.codec");
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm = defaultServiceManager();
+ MediaCodecService::instantiate();
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+}
diff --git a/services/mediacodec/mediacodec.rc b/services/mediacodec/mediacodec.rc
new file mode 100644
index 0000000..e8df7be
--- /dev/null
+++ b/services/mediacodec/mediacodec.rc
@@ -0,0 +1,5 @@
+service mediacodec /system/bin/mediacodec
+ class main
+ user mediacodec
+ group camera drmrpc mediadrm
+ ioprio rt 4
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
new file mode 100644
index 0000000..f6ddf94
--- /dev/null
+++ b/services/mediadrm/Android.mk
@@ -0,0 +1,44 @@
+# 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:= \
+ MediaDrmService.cpp \
+ main_mediadrmserver.cpp
+
+LOCAL_SHARED_LIBRARIES:= \
+ libui \
+ liblog \
+ libutils \
+ libbinder \
+ libcutils \
+ libstagefright \
+ libmediaplayerservice \
+ libmedia \
+
+LOCAL_C_INCLUDES := \
+ frameworks/av/media/libmediaplayerservice \
+
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
+LOCAL_MODULE:= mediadrmserver
+LOCAL_32_BIT_ONLY := true
+
+LOCAL_INIT_RC := mediadrmserver.rc
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/TimeSource.cpp b/services/mediadrm/DrmSessionClientInterface.h
similarity index 61%
rename from media/libstagefright/TimeSource.cpp
rename to services/mediadrm/DrmSessionClientInterface.h
index 041980f..17faf08 100644
--- a/media/libstagefright/TimeSource.cpp
+++ b/services/mediadrm/DrmSessionClientInterface.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
@@ -14,21 +14,21 @@
* limitations under the License.
*/
-#include <stddef.h>
-#include <sys/time.h>
+#ifndef DRM_PROXY_INTERFACE_H_
+#define DRM_PROXY_INTERFACE_H_
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/TimeSource.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
namespace android {
-SystemTimeSource::SystemTimeSource()
- : mStartTimeUs(ALooper::GetNowUs()) {
-}
+struct DrmSessionClientInterface : public RefBase {
+ virtual bool reclaimSession(const Vector<uint8_t>& sessionId) = 0;
-int64_t SystemTimeSource::getRealTimeUs() {
- return ALooper::GetNowUs() - mStartTimeUs;
-}
+protected:
+ virtual ~DrmSessionClientInterface() {}
+};
} // namespace android
+#endif // DRM_PROXY_INTERFACE_H_
diff --git a/services/mediadrm/MediaDrmService.cpp b/services/mediadrm/MediaDrmService.cpp
new file mode 100644
index 0000000..36ab8fe6
--- /dev/null
+++ b/services/mediadrm/MediaDrmService.cpp
@@ -0,0 +1,45 @@
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+// Proxy for media player implementations
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaDrmService"
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include "MediaDrmService.h"
+
+#include "Crypto.h"
+#include "Drm.h"
+
+namespace android {
+
+void MediaDrmService::instantiate() {
+ defaultServiceManager()->addService(
+ String16("media.drm"), new MediaDrmService());
+}
+
+sp<ICrypto> MediaDrmService::makeCrypto() {
+ return new Crypto;
+}
+
+sp<IDrm> MediaDrmService::makeDrm() {
+ return new Drm;
+}
+
+} // namespace android
diff --git a/services/mediadrm/MediaDrmService.h b/services/mediadrm/MediaDrmService.h
new file mode 100644
index 0000000..ecc2da7
--- /dev/null
+++ b/services/mediadrm/MediaDrmService.h
@@ -0,0 +1,48 @@
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_MEDIADRMSERVICE_H
+#define ANDROID_MEDIADRMSERVICE_H
+
+#include <arpa/inet.h>
+
+#include <utils/threads.h>
+
+#include <media/Metadata.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/IMediaDrmService.h>
+
+namespace android {
+
+class MediaDrmService : public BnMediaDrmService
+{
+public:
+ static void instantiate();
+
+ // IMediaDrmService interface
+ virtual sp<ICrypto> makeCrypto();
+ virtual sp<IDrm> makeDrm();
+private:
+ MediaDrmService() {}
+ virtual ~MediaDrmService() {}
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_MEDIADRMSERVICE_H
diff --git a/services/mediadrm/main_mediadrmserver.cpp b/services/mediadrm/main_mediadrmserver.cpp
new file mode 100644
index 0000000..b767b8c
--- /dev/null
+++ b/services/mediadrm/main_mediadrmserver.cpp
@@ -0,0 +1,43 @@
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "mediaserver"
+//#define LOG_NDEBUG 0
+
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
+#include <utils/Log.h>
+#include "MediaDrmService.h"
+
+using namespace android;
+
+int main()
+{
+ signal(SIGPIPE, SIG_IGN);
+
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm = defaultServiceManager();
+ ALOGI("ServiceManager: %p", sm.get());
+ MediaDrmService::instantiate();
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+}
diff --git a/services/mediadrm/mediadrmserver.rc b/services/mediadrm/mediadrmserver.rc
new file mode 100644
index 0000000..c22ec7c
--- /dev/null
+++ b/services/mediadrm/mediadrmserver.rc
@@ -0,0 +1,5 @@
+service mediadrm /system/bin/mediadrmserver
+ class main
+ user mediadrm
+ group drmrpc
+ ioprio rt 4
diff --git a/services/mediadrm/tests/Android.mk b/services/mediadrm/tests/Android.mk
new file mode 100644
index 0000000..8cbf782
--- /dev/null
+++ b/services/mediadrm/tests/Android.mk
@@ -0,0 +1,27 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := DrmSessionManager_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+ DrmSessionManager_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libmediaplayerservice \
+ libutils \
+
+LOCAL_C_INCLUDES := \
+ frameworks/av/include \
+ frameworks/av/media/libmediaplayerservice \
+
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+
+LOCAL_32_BIT_ONLY := true
+
+include $(BUILD_NATIVE_TEST)
+
diff --git a/services/mediadrm/tests/DrmSessionManager_test.cpp b/services/mediadrm/tests/DrmSessionManager_test.cpp
new file mode 100644
index 0000000..de350a1
--- /dev/null
+++ b/services/mediadrm/tests/DrmSessionManager_test.cpp
@@ -0,0 +1,249 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "DrmSessionManager_test"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include "Drm.h"
+#include "DrmSessionClientInterface.h"
+#include "DrmSessionManager.h"
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/ProcessInfoInterface.h>
+
+namespace android {
+
+struct FakeProcessInfo : public ProcessInfoInterface {
+ FakeProcessInfo() {}
+ virtual ~FakeProcessInfo() {}
+
+ virtual bool getPriority(int pid, int* priority) {
+ // For testing, use pid as priority.
+ // Lower the value higher the priority.
+ *priority = pid;
+ return true;
+ }
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo);
+};
+
+struct FakeDrm : public DrmSessionClientInterface {
+ FakeDrm() {}
+ virtual ~FakeDrm() {}
+
+ virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
+ mReclaimedSessions.push_back(sessionId);
+ return true;
+ }
+
+ const Vector<Vector<uint8_t> >& reclaimedSessions() const {
+ return mReclaimedSessions;
+ }
+
+private:
+ Vector<Vector<uint8_t> > mReclaimedSessions;
+
+ DISALLOW_EVIL_CONSTRUCTORS(FakeDrm);
+};
+
+static const int kTestPid1 = 30;
+static const int kTestPid2 = 20;
+static const uint8_t kTestSessionId1[] = {1, 2, 3};
+static const uint8_t kTestSessionId2[] = {4, 5, 6, 7, 8};
+static const uint8_t kTestSessionId3[] = {9, 0};
+
+class DrmSessionManagerTest : public ::testing::Test {
+public:
+ DrmSessionManagerTest()
+ : mDrmSessionManager(new DrmSessionManager(new FakeProcessInfo())),
+ mTestDrm1(new FakeDrm()),
+ mTestDrm2(new FakeDrm()) {
+ GetSessionId(kTestSessionId1, ARRAY_SIZE(kTestSessionId1), &mSessionId1);
+ GetSessionId(kTestSessionId2, ARRAY_SIZE(kTestSessionId2), &mSessionId2);
+ GetSessionId(kTestSessionId3, ARRAY_SIZE(kTestSessionId3), &mSessionId3);
+ }
+
+protected:
+ static void GetSessionId(const uint8_t* ids, size_t num, Vector<uint8_t>* sessionId) {
+ for (size_t i = 0; i < num; ++i) {
+ sessionId->push_back(ids[i]);
+ }
+ }
+
+ static void ExpectEqSessionInfo(const SessionInfo& info, sp<DrmSessionClientInterface> drm,
+ const Vector<uint8_t>& sessionId, int64_t timeStamp) {
+ EXPECT_EQ(drm, info.drm);
+ EXPECT_TRUE(isEqualSessionId(sessionId, info.sessionId));
+ EXPECT_EQ(timeStamp, info.timeStamp);
+ }
+
+ void addSession() {
+ mDrmSessionManager->addSession(kTestPid1, mTestDrm1, mSessionId1);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId2);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId3);
+ const PidSessionInfosMap& map = sessionMap();
+ EXPECT_EQ(2u, map.size());
+ ssize_t index1 = map.indexOfKey(kTestPid1);
+ ASSERT_GE(index1, 0);
+ const SessionInfos& infos1 = map[index1];
+ EXPECT_EQ(1u, infos1.size());
+ ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 0);
+
+ ssize_t index2 = map.indexOfKey(kTestPid2);
+ ASSERT_GE(index2, 0);
+ const SessionInfos& infos2 = map[index2];
+ EXPECT_EQ(2u, infos2.size());
+ ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId2, 1);
+ ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 2);
+ }
+
+ const PidSessionInfosMap& sessionMap() {
+ return mDrmSessionManager->mSessionMap;
+ }
+
+ void testGetLowestPriority() {
+ int pid;
+ int priority;
+ EXPECT_FALSE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
+
+ addSession();
+ EXPECT_TRUE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
+
+ EXPECT_EQ(kTestPid1, pid);
+ FakeProcessInfo processInfo;
+ int priority1;
+ processInfo.getPriority(kTestPid1, &priority1);
+ EXPECT_EQ(priority1, priority);
+ }
+
+ void testGetLeastUsedSession() {
+ sp<DrmSessionClientInterface> drm;
+ Vector<uint8_t> sessionId;
+ EXPECT_FALSE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
+
+ addSession();
+
+ EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
+ EXPECT_EQ(mTestDrm1, drm);
+ EXPECT_TRUE(isEqualSessionId(mSessionId1, sessionId));
+
+ EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
+ EXPECT_EQ(mTestDrm2, drm);
+ EXPECT_TRUE(isEqualSessionId(mSessionId2, sessionId));
+
+ // mSessionId2 is no longer the least used session.
+ mDrmSessionManager->useSession(mSessionId2);
+ EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
+ EXPECT_EQ(mTestDrm2, drm);
+ EXPECT_TRUE(isEqualSessionId(mSessionId3, sessionId));
+ }
+
+ sp<DrmSessionManager> mDrmSessionManager;
+ sp<FakeDrm> mTestDrm1;
+ sp<FakeDrm> mTestDrm2;
+ Vector<uint8_t> mSessionId1;
+ Vector<uint8_t> mSessionId2;
+ Vector<uint8_t> mSessionId3;
+};
+
+TEST_F(DrmSessionManagerTest, addSession) {
+ addSession();
+}
+
+TEST_F(DrmSessionManagerTest, useSession) {
+ addSession();
+
+ mDrmSessionManager->useSession(mSessionId1);
+ mDrmSessionManager->useSession(mSessionId3);
+
+ const PidSessionInfosMap& map = sessionMap();
+ const SessionInfos& infos1 = map.valueFor(kTestPid1);
+ const SessionInfos& infos2 = map.valueFor(kTestPid2);
+ ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 3);
+ ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 4);
+}
+
+TEST_F(DrmSessionManagerTest, removeSession) {
+ addSession();
+
+ mDrmSessionManager->removeSession(mSessionId2);
+
+ const PidSessionInfosMap& map = sessionMap();
+ EXPECT_EQ(2u, map.size());
+ const SessionInfos& infos1 = map.valueFor(kTestPid1);
+ const SessionInfos& infos2 = map.valueFor(kTestPid2);
+ EXPECT_EQ(1u, infos1.size());
+ EXPECT_EQ(1u, infos2.size());
+ // mSessionId2 has been removed.
+ ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId3, 2);
+}
+
+TEST_F(DrmSessionManagerTest, removeDrm) {
+ addSession();
+
+ sp<FakeDrm> drm = new FakeDrm;
+ const uint8_t ids[] = {123};
+ Vector<uint8_t> sessionId;
+ GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
+ mDrmSessionManager->addSession(kTestPid2, drm, sessionId);
+
+ mDrmSessionManager->removeDrm(mTestDrm2);
+
+ const PidSessionInfosMap& map = sessionMap();
+ const SessionInfos& infos2 = map.valueFor(kTestPid2);
+ EXPECT_EQ(1u, infos2.size());
+ // mTestDrm2 has been removed.
+ ExpectEqSessionInfo(infos2[0], drm, sessionId, 3);
+}
+
+TEST_F(DrmSessionManagerTest, reclaimSession) {
+ EXPECT_FALSE(mDrmSessionManager->reclaimSession(kTestPid1));
+ addSession();
+
+ // calling pid priority is too low
+ EXPECT_FALSE(mDrmSessionManager->reclaimSession(50));
+
+ EXPECT_TRUE(mDrmSessionManager->reclaimSession(10));
+ EXPECT_EQ(1u, mTestDrm1->reclaimedSessions().size());
+ EXPECT_TRUE(isEqualSessionId(mSessionId1, mTestDrm1->reclaimedSessions()[0]));
+
+ mDrmSessionManager->removeSession(mSessionId1);
+
+ // add a session from a higher priority process.
+ sp<FakeDrm> drm = new FakeDrm;
+ const uint8_t ids[] = {1, 3, 5};
+ Vector<uint8_t> sessionId;
+ GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
+ mDrmSessionManager->addSession(15, drm, sessionId);
+
+ EXPECT_TRUE(mDrmSessionManager->reclaimSession(18));
+ EXPECT_EQ(1u, mTestDrm2->reclaimedSessions().size());
+ // mSessionId2 is reclaimed.
+ EXPECT_TRUE(isEqualSessionId(mSessionId2, mTestDrm2->reclaimedSessions()[0]));
+}
+
+TEST_F(DrmSessionManagerTest, getLowestPriority) {
+ testGetLowestPriority();
+}
+
+TEST_F(DrmSessionManagerTest, getLeastUsedSession_l) {
+ testGetLeastUsedSession();
+}
+
+} // namespace android
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
new file mode 100644
index 0000000..bc2b641
--- /dev/null
+++ b/services/mediaextractor/Android.mk
@@ -0,0 +1,24 @@
+LOCAL_PATH := $(call my-dir)
+
+# service library
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := MediaExtractorService.cpp
+LOCAL_SHARED_LIBRARIES := libmedia libstagefright libbinder libutils liblog
+LOCAL_MODULE:= libmediaextractorservice
+LOCAL_32_BIT_ONLY := true
+include $(BUILD_SHARED_LIBRARY)
+
+
+# service executable
+include $(CLEAR_VARS)
+LOCAL_REQUIRED_MODULES_arm := mediaextractor-seccomp.policy
+LOCAL_REQUIRED_MODULES_x86 := mediaextractor-seccomp.policy
+LOCAL_SRC_FILES := main_extractorservice.cpp minijail/minijail.cpp
+LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils liblog libicuuc libminijail
+LOCAL_STATIC_LIBRARIES := libicuandroid_utils
+LOCAL_MODULE:= mediaextractor
+LOCAL_32_BIT_ONLY := true
+LOCAL_INIT_RC := mediaextractor.rc
+include $(BUILD_EXECUTABLE)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/mediaextractor/MODULE_LICENSE_APACHE2 b/services/mediaextractor/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/mediaextractor/MODULE_LICENSE_APACHE2
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
new file mode 100644
index 0000000..cd20635
--- /dev/null
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MediaExtractorService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaExtractor.h>
+#include "MediaExtractorService.h"
+
+namespace android {
+
+sp<IMediaExtractor> MediaExtractorService::makeExtractor(
+ const sp<IDataSource> &remoteSource, const char *mime) {
+ ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime);
+
+ sp<DataSource> localSource = DataSource::CreateFromIDataSource(remoteSource);
+
+ sp<MediaExtractor> ret = MediaExtractor::CreateFromService(localSource, mime);
+
+ ALOGV("extractor service created %p (%s)",
+ ret.get(),
+ ret == NULL ? "" : ret->name());
+
+ return ret;
+}
+
+
+status_t MediaExtractorService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags)
+{
+ return BnMediaExtractorService::onTransact(code, data, reply, flags);
+}
+
+} // namespace android
diff --git a/services/mediaextractor/MediaExtractorService.h b/services/mediaextractor/MediaExtractorService.h
new file mode 100644
index 0000000..9c75042
--- /dev/null
+++ b/services/mediaextractor/MediaExtractorService.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_EXTRACTOR_SERVICE_H
+#define ANDROID_MEDIA_EXTRACTOR_SERVICE_H
+
+#include <binder/BinderService.h>
+#include <media/IMediaExtractorService.h>
+#include <media/IMediaExtractor.h>
+
+namespace android {
+
+class MediaExtractorService : public BinderService<MediaExtractorService>, public BnMediaExtractorService
+{
+ friend class BinderService<MediaExtractorService>; // for MediaExtractorService()
+public:
+ MediaExtractorService() : BnMediaExtractorService() { }
+ virtual ~MediaExtractorService() { }
+ virtual void onFirstRef() { }
+
+ static const char* getServiceName() { return "media.extractor"; }
+
+ virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime);
+
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags);
+
+private:
+ Mutex mLock;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_EXTRACTOR_SERVICE_H
diff --git a/services/mediaextractor/NOTICE b/services/mediaextractor/NOTICE
new file mode 100644
index 0000000..34bdaf1
--- /dev/null
+++ b/services/mediaextractor/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
new file mode 100644
index 0000000..a7f3fbe
--- /dev/null
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -0,0 +1,49 @@
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "mediaextractor"
+//#define LOG_NDEBUG 0
+
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+// from LOCAL_C_INCLUDES
+#include "IcuUtils.h"
+#include "MediaExtractorService.h"
+#include "minijail/minijail.h"
+
+using namespace android;
+
+int main(int argc __unused, char** argv)
+{
+ signal(SIGPIPE, SIG_IGN);
+ MiniJail();
+
+ InitializeIcuOrDie();
+
+ strcpy(argv[0], "media.extractor");
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm = defaultServiceManager();
+ MediaExtractorService::instantiate();
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+}
diff --git a/services/mediaextractor/mediaextractor.rc b/services/mediaextractor/mediaextractor.rc
new file mode 100644
index 0000000..f733a2b
--- /dev/null
+++ b/services/mediaextractor/mediaextractor.rc
@@ -0,0 +1,5 @@
+service mediaextractor /system/bin/mediaextractor
+ class main
+ user mediaex
+ group drmrpc mediadrm
+ ioprio rt 4
diff --git a/services/mediaextractor/minijail/Android.mk b/services/mediaextractor/minijail/Android.mk
new file mode 100644
index 0000000..79c5505
--- /dev/null
+++ b/services/mediaextractor/minijail/Android.mk
@@ -0,0 +1,28 @@
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64 x86 x86_64))
+include $(CLEAR_VARS)
+LOCAL_MODULE := mediaextractor-seccomp.policy
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
+
+# mediaextractor runs in 32-bit combatibility mode. For 64 bit architectures,
+# use the 32 bit policy
+ifdef TARGET_2ND_ARCH
+ LOCAL_SRC_FILES := $(LOCAL_PATH)/seccomp_policy/mediaextractor-seccomp-$(TARGET_2ND_ARCH).policy
+else
+ LOCAL_SRC_FILES := $(LOCAL_PATH)/seccomp_policy/mediaextractor-seccomp-$(TARGET_ARCH).policy
+endif
+
+# allow device specific additions to the syscall whitelist
+ifneq (,$(wildcard $(BOARD_SECCOMP_POLICY)/mediaextractor-seccomp.policy))
+ LOCAL_SRC_FILES += $(BOARD_SECCOMP_POLICY)/mediaextractor-seccomp.policy
+endif
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(LOCAL_SRC_FILES)
+ @mkdir -p $(dir $@)
+ $(hide) cat > $@ $^
+
+endif
diff --git a/services/mediaextractor/minijail/minijail.cpp b/services/mediaextractor/minijail/minijail.cpp
new file mode 100644
index 0000000..421a1e0
--- /dev/null
+++ b/services/mediaextractor/minijail/minijail.cpp
@@ -0,0 +1,50 @@
+/*
+**
+** 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 <cutils/log.h>
+#include <libminijail.h>
+
+#include "minijail.h"
+
+namespace android {
+
+/* Must match location in Android.mk */
+static const char kSeccompFilePath[] = "/system/etc/seccomp_policy/mediaextractor-seccomp.policy";
+
+int MiniJail()
+{
+ /* no seccomp policy for this architecture */
+ if (access(kSeccompFilePath, R_OK) == -1) {
+ ALOGW("No seccomp filter defined for this architecture.");
+ return 0;
+ }
+
+ struct minijail *jail = minijail_new();
+ if (jail == NULL) {
+ ALOGW("Failed to create minijail.");
+ return -1;
+ }
+
+ minijail_no_new_privs(jail);
+ minijail_log_seccomp_filter_failures(jail);
+ minijail_use_seccomp_filter(jail);
+ minijail_parse_seccomp_filters(jail, kSeccompFilePath);
+ minijail_enter(jail);
+ minijail_destroy(jail);
+ return 0;
+}
+}
diff --git a/services/mediaextractor/minijail/minijail.h b/services/mediaextractor/minijail/minijail.h
new file mode 100644
index 0000000..6ea4487
--- /dev/null
+++ b/services/mediaextractor/minijail/minijail.h
@@ -0,0 +1,20 @@
+/*
+**
+** 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.
+*/
+
+namespace android {
+int MiniJail();
+}
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
new file mode 100644
index 0000000..5bbd4e3
--- /dev/null
+++ b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
@@ -0,0 +1,41 @@
+# Organized by frequency of systemcall - in descending order for
+# best performance.
+ioctl: 1
+futex: 1
+prctl: 1
+write: 1
+getpriority: 1
+mmap2: 1
+close: 1
+munmap: 1
+dup: 1
+mprotect: 1
+getuid32: 1
+setpriority: 1
+sigaltstack: 1
+openat: 1
+clone: 1
+read: 1
+clock_gettime: 1
+lseek: 1
+writev: 1
+fstatat64: 1
+fstat64: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+faccessat: 1
+madvise: 1
+brk: 1
+sched_setscheduler: 1
+gettid: 1
+rt_sigprocmask: 1
+sched_yield: 1
+
+# for attaching to debuggerd on process crash
+sigaction: 1
+tgkill: 1
+socket: 1
+connect: 1
+fcntl64: 1
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy
new file mode 100644
index 0000000..f321366
--- /dev/null
+++ b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy
@@ -0,0 +1,30 @@
+# Organized by frequency of systemcall - in descending order for
+# best performance.
+ioctl: 1
+futex: 1
+prctl: 1
+write: 1
+getpriority: 1
+close: 1
+dup: 1
+munmap: 1
+mmap2: 1
+madvise: 1
+openat: 1
+clock_gettime: 1
+writev: 1
+brk: 1
+mprotect: 1
+read: 1
+lseek: 1
+getuid32: 1
+clone: 1
+setpriority: 1
+sigaltstack: 1
+fstatat64: 1
+fstat64: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+faccessat: 1
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 6781a36..4f99860 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -19,6 +19,7 @@
#define LOG_TAG "ResourceManagerService"
#include <utils/Log.h>
+#include <binder/IMediaResourceMonitor.h>
#include <binder/IServiceManager.h>
#include <dirent.h>
#include <media/stagefright/ProcessInfo.h>
@@ -89,6 +90,18 @@
return infos.editItemAt(infos.size() - 1);
}
+static void notifyResourceGranted(int pid, const Vector<MediaResource> &resources) {
+ static const char* const kServiceName = "media_resource_monitor";
+ sp<IBinder> binder = defaultServiceManager()->getService(String16(kServiceName));
+ if (binder != NULL) {
+ sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
+ for (size_t i = 0; i < resources.size(); ++i) {
+ service->notifyResourceGranted(pid, String16(resources[i].mType),
+ String16(resources[i].mSubType), resources[i].mValue);
+ }
+ }
+}
+
status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) {
String8 result;
@@ -197,6 +210,7 @@
ResourceInfo& info = getResourceInfoForEdit(clientId, client, infos);
// TODO: do the merge instead of append.
info.resources.appendVector(resources);
+ notifyResourceGranted(pid, resources);
}
void ResourceManagerService::removeResource(int pid, int64_t clientId) {
diff --git a/services/radio/Android.mk b/services/radio/Android.mk
index 9ee5666..6aae31d 100644
--- a/services/radio/Android.mk
+++ b/services/radio/Android.mk
@@ -31,6 +31,8 @@
libradio \
libradio_metadata
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
LOCAL_MODULE:= libradioservice
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/radio/RadioRegions.h b/services/radio/RadioRegions.h
index 3335b8a..d40ee83 100644
--- a/services/radio/RadioRegions.h
+++ b/services/radio/RadioRegions.h
@@ -67,11 +67,14 @@
1,
{RADIO_BAND_SPACING_FM_ITU1},
{
- RADIO_DEEMPHASIS_50,
- true,
- RADIO_RDS_WORLD,
- true,
- true,
+ {
+ RADIO_DEEMPHASIS_50,
+ true,
+ RADIO_RDS_WORLD,
+ true,
+ true,
+ true,
+ }
}
}
},
@@ -85,11 +88,14 @@
1,
{RADIO_BAND_SPACING_FM_ITU2},
{
- RADIO_DEEMPHASIS_75,
- true,
- RADIO_RDS_US,
- true,
- true,
+ {
+ RADIO_DEEMPHASIS_75,
+ true,
+ RADIO_RDS_US,
+ true,
+ true,
+ true,
+ }
}
}
},
@@ -103,11 +109,14 @@
1,
{RADIO_BAND_SPACING_FM_JAPAN},
{
- RADIO_DEEMPHASIS_50,
- true,
- RADIO_RDS_WORLD,
- true,
- true,
+ {
+ RADIO_DEEMPHASIS_50,
+ true,
+ RADIO_RDS_WORLD,
+ true,
+ true,
+ true,
+ }
}
}
},
@@ -121,11 +130,14 @@
1,
{RADIO_BAND_SPACING_FM_ITU1},
{
- RADIO_DEEMPHASIS_75,
- true,
- RADIO_RDS_WORLD,
- true,
- true,
+ {
+ RADIO_DEEMPHASIS_75,
+ true,
+ RADIO_RDS_WORLD,
+ true,
+ true,
+ true,
+ }
}
}
},
@@ -139,11 +151,14 @@
1,
{RADIO_BAND_SPACING_FM_OIRT},
{
- RADIO_DEEMPHASIS_50,
- true,
- RADIO_RDS_WORLD,
- true,
- true,
+ {
+ RADIO_DEEMPHASIS_50,
+ true,
+ RADIO_RDS_WORLD,
+ true,
+ true,
+ true,
+ }
}
}
},
@@ -157,11 +172,14 @@
1,
{RADIO_BAND_SPACING_FM_ITU2},
{
- RADIO_DEEMPHASIS_75,
- true,
- RADIO_RDS_US,
- true,
- true,
+ {
+ RADIO_DEEMPHASIS_75,
+ true,
+ RADIO_RDS_US,
+ true,
+ true,
+ true,
+ }
}
}
},
diff --git a/services/radio/RadioService.cpp b/services/radio/RadioService.cpp
index cd0f5f3..5a3f750 100644
--- a/services/radio/RadioService.cpp
+++ b/services/radio/RadioService.cpp
@@ -349,6 +349,7 @@
}
break;
case RADIO_EVENT_TA:
+ case RADIO_EVENT_EA:
case RADIO_EVENT_ANTENNA:
case RADIO_EVENT_CONTROL:
event->on = halEvent->on;
@@ -734,7 +735,7 @@
}
} else {
mConfig = *config;
- status == INVALID_OPERATION;
+ status = INVALID_OPERATION;
}
return status;
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 9de6fe2..66310b5 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -61,13 +61,13 @@
rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, &mod);
if (rc != 0) {
ALOGE("couldn't load sound trigger module %s.%s (%s)",
- SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc));
+ SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, strerror(-rc));
return;
}
rc = sound_trigger_hw_device_open(mod, &dev);
if (rc != 0) {
ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
- SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc));
+ SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, strerror(-rc));
return;
}
if (dev->common.version != SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
@@ -241,6 +241,13 @@
event->data_offset);
event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
break;
+ case SOUND_MODEL_TYPE_GENERIC:
+ ALOGW_IF(event->data_size != 0 && event->data_offset !=
+ sizeof(struct sound_trigger_generic_recognition_event),
+ "prepareRecognitionEvent_l(): invalid data offset %u for generic event type",
+ event->data_offset);
+ event->data_offset = sizeof(struct sound_trigger_generic_recognition_event);
+ break;
case SOUND_MODEL_TYPE_UNKNOWN:
ALOGW_IF(event->data_size != 0 && event->data_offset !=
sizeof(struct sound_trigger_recognition_event),
@@ -537,19 +544,39 @@
AutoMutex lock(mLock);
if (mModels.size() >= mDescriptor.properties.max_sound_models) {
+ /* Make space for a keyphrase sound model by first trying to swap out a previously loaded
+ * keyphrase sound model, or if needed, another sound model. This decision would optimally
+ * happen in SoundTriggerHelper, but is happening here because state tracking isn't good
+ * enough in SoundTriggerHelper to ensure that state is consistent between it and the HAL,
+ * nor does sufficient error handling exist to recover from inconsistencies.
+ * Once that exists:
+ * TODO: we should return an error instead of unloading a previous sound model here.
+ */
if (mModels.size() == 0) {
return INVALID_OPERATION;
}
- ALOGW("loadSoundModel() max number of models exceeded %d making room for a new one",
- mDescriptor.properties.max_sound_models);
- unloadSoundModel_l(mModels.valueAt(0)->mHandle);
+ if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ ALOGW("loadSoundModel() max number of models exceeded %d making room for a new one",
+ mDescriptor.properties.max_sound_models);
+ sound_model_handle_t unload_handle = mModels.valueAt(0)->mHandle;
+ for (size_t i = 0; i < mModels.size(); i++) {
+ if (mModels.valueAt(i)->mType == SOUND_MODEL_TYPE_KEYPHRASE) {
+ unload_handle = mModels.keyAt(i);
+ break;
+ }
+ }
+ unloadSoundModel_l(unload_handle);
+ } else {
+ ALOGW("loadSoundModel(): Not loading, max number of models (%d) would be exceeded",
+ mDescriptor.properties.max_sound_models);
+ return INVALID_OPERATION;
+ }
}
- status_t status = mHwDevice->load_sound_model(mHwDevice,
- sound_model,
+ status_t status = mHwDevice->load_sound_model(mHwDevice, sound_model,
SoundTriggerHwService::soundModelCallback,
- this,
- handle);
+ this, handle);
+
if (status != NO_ERROR) {
return status;
}
@@ -786,26 +813,45 @@
if (model->mState == Model::STATE_ACTIVE) {
mHwDevice->stop_recognition(mHwDevice, model->mHandle);
// keep model in ACTIVE state so that event is processed by onCallbackEvent()
- struct sound_trigger_phrase_recognition_event phraseEvent;
- memset(&phraseEvent, 0, sizeof(struct sound_trigger_phrase_recognition_event));
- switch (model->mType) {
- case SOUND_MODEL_TYPE_KEYPHRASE:
- phraseEvent.num_phrases = model->mConfig.num_phrases;
- for (size_t i = 0; i < phraseEvent.num_phrases; i++) {
- phraseEvent.phrase_extras[i] = model->mConfig.phrases[i];
+ if (model->mType == SOUND_MODEL_TYPE_KEYPHRASE) {
+ struct sound_trigger_phrase_recognition_event event;
+ memset(&event, 0, sizeof(struct sound_trigger_phrase_recognition_event));
+ event.num_phrases = model->mConfig.num_phrases;
+ for (size_t i = 0; i < event.num_phrases; i++) {
+ event.phrase_extras[i] = model->mConfig.phrases[i];
}
- break;
- case SOUND_MODEL_TYPE_UNKNOWN:
- default:
- break;
- }
- phraseEvent.common.status = RECOGNITION_STATUS_ABORT;
- phraseEvent.common.type = model->mType;
- phraseEvent.common.model = model->mHandle;
- phraseEvent.common.data_size = 0;
- sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&phraseEvent.common);
- if (eventMemory != 0) {
- events.add(eventMemory);
+ event.common.status = RECOGNITION_STATUS_ABORT;
+ event.common.type = model->mType;
+ event.common.model = model->mHandle;
+ event.common.data_size = 0;
+ sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+ if (eventMemory != 0) {
+ events.add(eventMemory);
+ }
+ } else if (model->mType == SOUND_MODEL_TYPE_GENERIC) {
+ struct sound_trigger_generic_recognition_event event;
+ memset(&event, 0, sizeof(struct sound_trigger_generic_recognition_event));
+ event.common.status = RECOGNITION_STATUS_ABORT;
+ event.common.type = model->mType;
+ event.common.model = model->mHandle;
+ event.common.data_size = 0;
+ sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+ if (eventMemory != 0) {
+ events.add(eventMemory);
+ }
+ } else if (model->mType == SOUND_MODEL_TYPE_UNKNOWN) {
+ struct sound_trigger_phrase_recognition_event event;
+ memset(&event, 0, sizeof(struct sound_trigger_phrase_recognition_event));
+ event.common.status = RECOGNITION_STATUS_ABORT;
+ event.common.type = model->mType;
+ event.common.model = model->mHandle;
+ event.common.data_size = 0;
+ sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+ if (eventMemory != 0) {
+ events.add(eventMemory);
+ }
+ } else {
+ goto exit;
}
}
}